aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml73
-rw-r--r--.github/ISSUE_TEMPLATE.md27
-rw-r--r--.github/ISSUE_TEMPLATE/bug.yml93
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md41
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml8
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md20
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.yml36
-rw-r--r--.github/ISSUE_TEMPLATE/good_first_issue.md22
-rw-r--r--.github/ISSUE_TEMPLATE/good_first_issue.yml42
-rw-r--r--.github/ISSUE_TEMPLATE/gui_issue.md11
-rw-r--r--.github/ISSUE_TEMPLATE/gui_issue.yml18
-rw-r--r--.python-version2
-rw-r--r--.tx/config2
-rw-r--r--COPYING4
-rw-r--r--REVIEWERS17
-rw-r--r--build-aux/m4/ax_boost_base.m461
-rw-r--r--build_msvc/README.md8
-rw-r--r--build_msvc/bitcoin-cli/bitcoin-cli.vcxproj3
-rw-r--r--build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in1
-rw-r--r--build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in1
-rw-r--r--build_msvc/libleveldb/libleveldb.vcxproj2
-rw-r--r--build_msvc/libsecp256k1/libsecp256k1.vcxproj2
-rwxr-xr-xbuild_msvc/msvc-autogen.py2
-rw-r--r--build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj3
-rw-r--r--ci/README.md3
-rwxr-xr-xci/lint/04_install.sh48
-rwxr-xr-xci/lint/06_script.sh21
-rw-r--r--ci/lint/Dockerfile29
-rwxr-xr-xci/lint/docker-entrypoint.sh12
-rwxr-xr-xci/test/00_setup_env.sh14
-rwxr-xr-xci/test/00_setup_env_android.sh4
-rwxr-xr-xci/test/00_setup_env_arm.sh2
-rwxr-xr-xci/test/00_setup_env_i686_centos.sh7
-rwxr-xr-xci/test/00_setup_env_i686_multiprocess.sh4
-rwxr-xr-xci/test/00_setup_env_mac.sh2
-rwxr-xr-xci/test/00_setup_env_mac_native_arm64.sh (renamed from ci/test/00_setup_env_mac_native_x86_64.sh)9
-rwxr-xr-xci/test/00_setup_env_native_asan.sh23
-rwxr-xr-xci/test/00_setup_env_native_fuzz.sh4
-rwxr-xr-xci/test/00_setup_env_native_fuzz_with_msan.sh10
-rwxr-xr-xci/test/00_setup_env_native_fuzz_with_valgrind.sh4
-rwxr-xr-xci/test/00_setup_env_native_msan.sh8
-rwxr-xr-xci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh9
-rwxr-xr-xci/test/00_setup_env_native_qt5.sh6
-rwxr-xr-xci/test/00_setup_env_native_tidy.sh4
-rwxr-xr-xci/test/00_setup_env_native_tsan.sh6
-rwxr-xr-xci/test/00_setup_env_native_valgrind.sh4
-rwxr-xr-xci/test/00_setup_env_s390x.sh4
-rwxr-xr-xci/test/00_setup_env_win64.sh6
-rwxr-xr-xci/test/01_base_install.sh33
-rwxr-xr-xci/test/04_install.sh83
-rwxr-xr-xci/test/05_before_script.sh5
-rwxr-xr-xci/test/06_script_a.sh9
-rwxr-xr-xci/test/06_script_b.sh33
-rwxr-xr-xci/test/wrap-qemu.sh2
-rwxr-xr-xci/test/wrap-wine.sh2
-rw-r--r--ci/test_imagefile10
-rw-r--r--configure.ac177
-rw-r--r--contrib/README.md9
-rw-r--r--contrib/builder-keys/README.md33
-rw-r--r--contrib/builder-keys/keys.txt57
-rw-r--r--contrib/completions/bash/bitcoin-cli.bash-completion (renamed from contrib/bitcoin-cli.bash-completion)2
-rw-r--r--contrib/completions/bash/bitcoin-tx.bash-completion (renamed from contrib/bitcoin-tx.bash-completion)2
-rw-r--r--contrib/completions/bash/bitcoind.bash-completion (renamed from contrib/bitcoind.bash-completion)2
-rw-r--r--contrib/completions/fish/bitcoin-cli.fish99
-rw-r--r--contrib/completions/fish/bitcoin-qt.fish35
-rw-r--r--contrib/completions/fish/bitcoin-tx.fish65
-rw-r--r--contrib/completions/fish/bitcoin-util.fish38
-rw-r--r--contrib/completions/fish/bitcoin-wallet.fish35
-rw-r--r--contrib/completions/fish/bitcoind.fish35
-rw-r--r--contrib/debian/copyright20
-rwxr-xr-xcontrib/devtools/clang-format-diff.py2
-rwxr-xr-xcontrib/devtools/copyright_header.py2
-rwxr-xr-xcontrib/devtools/gen-manpages.py4
-rwxr-xr-xcontrib/devtools/security-check.py11
-rwxr-xr-xcontrib/devtools/symbol-check.py22
-rwxr-xr-xcontrib/devtools/test-security-check.py20
-rwxr-xr-xcontrib/devtools/test-symbol-check.py31
-rw-r--r--contrib/guix/INSTALL.md66
-rw-r--r--contrib/guix/README.md49
-rwxr-xr-xcontrib/guix/libexec/build.sh15
-rwxr-xr-xcontrib/guix/libexec/codesign.sh2
-rw-r--r--contrib/guix/manifest.scm65
-rw-r--r--contrib/guix/patches/glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch62
-rw-r--r--contrib/guix/patches/glibc-2.24-guix-prefix.patch25
-rw-r--r--contrib/guix/patches/glibc-2.24-no-build-time-cxx-header-run.patch100
-rw-r--r--contrib/guix/patches/glibc-2.27-dont-redefine-nss-database.patch87
-rw-r--r--contrib/guix/patches/glibc-2.27-fcommon.patch (renamed from contrib/guix/patches/glibc-2.24-fcommon.patch)10
-rw-r--r--contrib/guix/patches/glibc-2.27-guix-prefix.patch3
-rw-r--r--contrib/guix/patches/glibc-ldd-x86_64.patch4
-rwxr-xr-xcontrib/install_db4.sh260
-rwxr-xr-xcontrib/linearize/linearize-data.py2
-rwxr-xr-xcontrib/linearize/linearize-hashes.py4
-rwxr-xr-xcontrib/macdeploy/detached-sig-create.sh2
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus10
-rwxr-xr-xcontrib/message-capture/message-capture-parser.py2
-rw-r--r--contrib/seeds/README.md2
-rwxr-xr-xcontrib/seeds/generate-seeds.py4
-rwxr-xr-xcontrib/seeds/makeseeds.py4
-rwxr-xr-xcontrib/signet/getcoins.py6
-rwxr-xr-xcontrib/tracing/log_utxocache_flush.py2
-rw-r--r--contrib/valgrind.supp8
-rw-r--r--contrib/verify-commits/README.md4
-rw-r--r--contrib/verify-commits/allow-incorrect-sha512-commits2
-rw-r--r--contrib/verify-commits/allow-revsig-commits645
-rw-r--r--contrib/verify-commits/allow-unclean-merge-commits4
-rwxr-xr-xcontrib/verify-commits/gpg.sh42
-rw-r--r--contrib/verify-commits/trusted-git-root2
-rw-r--r--contrib/verify-commits/trusted-keys2
-rwxr-xr-xcontrib/verify-commits/verify-commits.py51
-rw-r--r--contrib/verifybinaries/README.md11
-rw-r--r--depends/Makefile8
-rw-r--r--depends/README.md4
-rw-r--r--depends/funcs.mk21
-rw-r--r--depends/hosts/default.mk5
-rw-r--r--depends/packages/bdb.mk3
-rw-r--r--depends/packages/boost.mk4
-rw-r--r--depends/packages/capnp.mk9
-rw-r--r--depends/packages/libevent.mk1
-rw-r--r--depends/packages/libmultiprocess.mk2
-rw-r--r--depends/packages/miniupnpc.mk9
-rw-r--r--depends/packages/native_libmultiprocess.mk6
-rw-r--r--depends/packages/packages.mk6
-rw-r--r--depends/packages/qt.mk4
-rw-r--r--depends/packages/sqlite.mk5
-rw-r--r--depends/packages/systemtap.mk9
-rw-r--r--depends/packages/zeromq.mk4
-rw-r--r--depends/patches/miniupnpc/respect_mingw_cflags.patch23
-rw-r--r--depends/patches/systemtap/fix_variadic_warning.patch16
-rw-r--r--doc/JSON-RPC-interface.md22
-rw-r--r--doc/REST-interface.md31
-rw-r--r--doc/bips.md1
-rw-r--r--doc/build-freebsd.md37
-rw-r--r--doc/build-openbsd.md8
-rw-r--r--doc/build-unix.md38
-rw-r--r--doc/build-windows.md8
-rw-r--r--doc/dependencies.md8
-rw-r--r--doc/descriptors.md4
-rw-r--r--doc/design/assumeutxo.md58
-rw-r--r--doc/design/libraries.md12
-rw-r--r--doc/developer-notes.md32
-rw-r--r--doc/fuzzing.md8
-rw-r--r--doc/i2p.md95
-rw-r--r--doc/init.md2
-rw-r--r--doc/managing-wallets.md8
-rw-r--r--doc/reduce-memory.md6
-rw-r--r--doc/release-note-26194.md4
-rw-r--r--doc/release-notes-19762.md19
-rw-r--r--doc/release-notes-22087.md4
-rw-r--r--doc/release-notes-23395.md8
-rw-r--r--doc/release-notes-25375.md11
-rw-r--r--doc/release-notes-25412.md5
-rw-r--r--doc/release-notes-25574.md13
-rw-r--r--doc/release-notes-25730.md6
-rw-r--r--doc/release-notes-25934.md8
-rw-r--r--doc/release-notes-25943.md4
-rw-r--r--doc/release-notes-25957.md9
-rw-r--r--doc/release-notes-26213.md8
-rw-r--r--doc/release-notes-26265.md6
-rw-r--r--doc/release-notes-26471.md13
-rw-r--r--doc/release-notes-26618.md4
-rw-r--r--doc/release-notes-26628.md4
-rw-r--r--doc/release-notes-26646.md8
-rw-r--r--doc/release-notes-26896.md7
-rw-r--r--doc/release-notes-27037.md5
-rw-r--r--doc/release-notes-27068.md6
-rw-r--r--doc/release-notes-empty-template.md2
-rw-r--r--doc/release-notes/release-notes-22.1.md128
-rw-r--r--doc/release-notes/release-notes-23.1.md90
-rw-r--r--doc/release-notes/release-notes-24.0.1.md391
-rw-r--r--doc/release-notes/release-notes-24.0.md4
-rw-r--r--doc/release-process.md8
-rw-r--r--doc/tracing.md8
-rwxr-xr-xshare/rpcauth/rpcauth.py14
-rw-r--r--src/.clang-tidy16
-rw-r--r--src/Makefile.am105
-rw-r--r--src/Makefile.bench.include2
-rw-r--r--src/Makefile.minisketch.include2
-rw-r--r--src/Makefile.qt_locale.include6
-rw-r--r--src/Makefile.test.include19
-rw-r--r--src/Makefile.test_fuzz.include4
-rw-r--r--src/Makefile.test_util.include45
-rw-r--r--src/addrdb.cpp12
-rw-r--r--src/addrman.cpp92
-rw-r--r--src/addrman.h12
-rw-r--r--src/addrman_impl.h14
-rw-r--r--src/arith_uint256.cpp2
-rw-r--r--src/arith_uint256.h30
-rw-r--r--src/banman.cpp2
-rw-r--r--src/banman.h2
-rw-r--r--src/base58.cpp2
-rw-r--r--src/base58.h2
-rw-r--r--src/bech32.cpp2
-rw-r--r--src/bench/addrman.cpp10
-rw-r--r--src/bench/base58.cpp8
-rw-r--r--src/bench/bech32.cpp6
-rw-r--r--src/bench/bench.cpp60
-rw-r--r--src/bench/bench.h24
-rw-r--r--src/bench/bench_bitcoin.cpp42
-rw-r--r--src/bench/block_assemble.cpp19
-rw-r--r--src/bench/ccoins_caching.cpp5
-rw-r--r--src/bench/chacha20.cpp12
-rw-r--r--src/bench/chacha_poly_aead.cpp20
-rw-r--r--src/bench/checkblock.cpp6
-rw-r--r--src/bench/checkqueue.cpp5
-rw-r--r--src/bench/coin_selection.cpp19
-rw-r--r--src/bench/crypto_hash.cpp36
-rw-r--r--src/bench/descriptors.cpp9
-rw-r--r--src/bench/duplicate_inputs.cpp4
-rw-r--r--src/bench/examples.cpp4
-rw-r--r--src/bench/gcs_filter.cpp14
-rw-r--r--src/bench/hashpadding.cpp6
-rw-r--r--src/bench/load_external.cpp63
-rw-r--r--src/bench/lockedpool.cpp4
-rw-r--r--src/bench/logging.cpp12
-rw-r--r--src/bench/mempool_eviction.cpp5
-rw-r--r--src/bench/mempool_stress.cpp7
-rw-r--r--src/bench/merkle_root.cpp4
-rw-r--r--src/bench/nanobench.h461
-rw-r--r--src/bench/peer_eviction.cpp26
-rw-r--r--src/bench/poly1305.cpp8
-rw-r--r--src/bench/prevector.cpp8
-rw-r--r--src/bench/rollingbloom.cpp6
-rw-r--r--src/bench/rpc_blockchain.cpp6
-rw-r--r--src/bench/rpc_mempool.cpp6
-rw-r--r--src/bench/strencodings.cpp2
-rw-r--r--src/bench/util_time.cpp10
-rw-r--r--src/bench/verify_script.cpp7
-rw-r--r--src/bench/wallet_balance.cpp16
-rw-r--r--src/bench/wallet_create_tx.cpp183
-rw-r--r--src/bench/wallet_loading.cpp32
-rw-r--r--src/bitcoin-chainstate.cpp8
-rw-r--r--src/bitcoin-cli.cpp33
-rw-r--r--src/bitcoin-tx.cpp7
-rw-r--r--src/bitcoin-util.cpp17
-rw-r--r--src/bitcoin-wallet.cpp8
-rw-r--r--src/bitcoind.cpp32
-rw-r--r--src/blockencodings.cpp22
-rw-r--r--src/blockencodings.h12
-rw-r--r--src/blockfilter.cpp17
-rw-r--r--src/blockfilter.h2
-rw-r--r--src/chain.cpp2
-rw-r--r--src/chain.h27
-rw-r--r--src/chainparams.cpp537
-rw-r--r--src/chainparams.h133
-rw-r--r--src/checkqueue.h5
-rw-r--r--src/clientversion.cpp2
-rw-r--r--src/clientversion.h2
-rw-r--r--src/coins.cpp78
-rw-r--r--src/coins.h32
-rw-r--r--src/common/bloom.cpp6
-rw-r--r--src/common/init.cpp74
-rw-r--r--src/common/init.h39
-rw-r--r--src/common/interfaces.cpp53
-rw-r--r--src/common/run_command.cpp64
-rw-r--r--src/common/run_command.h21
-rw-r--r--src/common/url.cpp (renamed from src/util/url.cpp)4
-rw-r--r--src/common/url.h (renamed from src/util/url.h)8
-rw-r--r--src/compat/byteswap.h2
-rw-r--r--src/compat/compat.h10
-rw-r--r--src/compat/cpuid.h2
-rw-r--r--src/compat/endian.h2
-rw-r--r--src/compat/stdin.cpp4
-rw-r--r--src/consensus/consensus.h2
-rw-r--r--src/consensus/params.h3
-rw-r--r--src/consensus/tx_verify.h4
-rw-r--r--src/consensus/validation.h2
-rw-r--r--src/core_io.h5
-rw-r--r--src/core_read.cpp4
-rw-r--r--src/core_write.cpp8
-rw-r--r--src/crypto/chacha20.cpp262
-rw-r--r--src/crypto/chacha20.h68
-rw-r--r--src/crypto/chacha_poly_aead.cpp15
-rw-r--r--src/crypto/hkdf_sha256_32.h2
-rw-r--r--src/crypto/hmac_sha256.h2
-rw-r--r--src/crypto/hmac_sha512.h2
-rw-r--r--src/crypto/muhash.cpp4
-rw-r--r--src/crypto/poly1305.h2
-rw-r--r--src/crypto/ripemd160.cpp2
-rw-r--r--src/crypto/ripemd160.h4
-rw-r--r--src/crypto/sha1.cpp2
-rw-r--r--src/crypto/sha1.h4
-rw-r--r--src/crypto/sha256.cpp4
-rw-r--r--src/crypto/sha256.h4
-rw-r--r--src/crypto/sha256_sse4.cpp2
-rw-r--r--src/crypto/sha256_x86_shani.cpp2
-rw-r--r--src/crypto/sha3.h2
-rw-r--r--src/crypto/sha512.cpp6
-rw-r--r--src/crypto/sha512.h4
-rw-r--r--src/crypto/siphash.cpp6
-rw-r--r--src/cuckoocache.h13
-rw-r--r--src/dbwrapper.cpp34
-rw-r--r--src/dbwrapper.h69
-rw-r--r--src/deploymentinfo.cpp18
-rw-r--r--src/deploymentinfo.h3
-rw-r--r--src/deploymentstatus.cpp2
-rw-r--r--src/deploymentstatus.h2
-rw-r--r--src/external_signer.cpp9
-rw-r--r--src/external_signer.h2
-rw-r--r--src/flatfile.cpp2
-rw-r--r--src/fs.cpp34
-rw-r--r--src/fs.h4
-rw-r--r--src/hash.cpp2
-rw-r--r--src/hash.h69
-rw-r--r--src/httprpc.cpp4
-rw-r--r--src/httpserver.cpp65
-rw-r--r--src/httpserver.h2
-rw-r--r--src/i2p.cpp22
-rw-r--r--src/i2p.h4
-rw-r--r--src/index/base.cpp32
-rw-r--r--src/index/base.h4
-rw-r--r--src/index/blockfilterindex.cpp6
-rw-r--r--src/index/blockfilterindex.h2
-rw-r--r--src/index/coinstatsindex.cpp9
-rw-r--r--src/index/coinstatsindex.h2
-rw-r--r--src/index/txindex.cpp3
-rw-r--r--src/index/txindex.h2
-rw-r--r--src/init.cpp228
-rw-r--r--src/init.h2
-rw-r--r--src/init/bitcoin-gui.cpp2
-rw-r--r--src/init/bitcoin-node.cpp2
-rw-r--r--src/init/bitcoin-qt.cpp2
-rw-r--r--src/init/bitcoin-wallet.cpp2
-rw-r--r--src/init/bitcoind.cpp2
-rw-r--r--src/init/common.cpp6
-rw-r--r--src/init/common.h2
-rw-r--r--src/interfaces/chain.h14
-rw-r--r--src/interfaces/echo.cpp18
-rw-r--r--src/interfaces/handler.cpp45
-rw-r--r--src/interfaces/handler.h6
-rw-r--r--src/interfaces/init.cpp17
-rw-r--r--src/interfaces/init.h21
-rw-r--r--src/interfaces/node.h9
-rw-r--r--src/interfaces/wallet.h2
-rw-r--r--src/ipc/interfaces.cpp2
-rw-r--r--src/ipc/process.cpp2
-rw-r--r--src/kernel/blockmanager_opts.h20
-rw-r--r--src/kernel/chainparams.cpp532
-rw-r--r--src/kernel/chainparams.h187
-rw-r--r--src/kernel/chainstatemanager_opts.h20
-rw-r--r--src/kernel/coinstats.cpp7
-rw-r--r--src/kernel/coinstats.h2
-rw-r--r--src/kernel/context.cpp2
-rw-r--r--src/kernel/context.h4
-rw-r--r--src/kernel/cs_main.cpp8
-rw-r--r--src/kernel/cs_main.h22
-rw-r--r--src/kernel/mempool_entry.h174
-rw-r--r--src/kernel/mempool_limits.h9
-rw-r--r--src/kernel/mempool_options.h2
-rw-r--r--src/key.cpp19
-rw-r--r--src/key.h8
-rw-r--r--src/key_io.cpp10
-rw-r--r--src/logging.cpp8
-rw-r--r--src/logging.h11
-rw-r--r--src/logging/timer.h28
-rw-r--r--src/mapport.cpp18
-rw-r--r--src/mapport.h8
-rw-r--r--src/memusage.h2
-rw-r--r--src/minisketch/configure.ac3
-rw-r--r--src/minisketch/src/bench.cpp4
-rw-r--r--src/minisketch/src/int_utils.h24
-rw-r--r--src/minisketch/src/test.cpp1
-rw-r--r--src/net.cpp164
-rw-r--r--src/net.h50
-rw-r--r--src/net_permissions.h5
-rw-r--r--src/net_processing.cpp436
-rw-r--r--src/net_processing.h2
-rw-r--r--src/net_types.cpp2
-rw-r--r--src/netaddress.cpp54
-rw-r--r--src/netaddress.h13
-rw-r--r--src/netbase.cpp42
-rw-r--r--src/netbase.h4
-rw-r--r--src/netgroup.cpp2
-rw-r--r--src/node/blockmanager_args.cpp30
-rw-r--r--src/node/blockmanager_args.h20
-rw-r--r--src/node/blockstorage.cpp112
-rw-r--r--src/node/blockstorage.h44
-rw-r--r--src/node/caches.cpp2
-rw-r--r--src/node/chainstate.cpp168
-rw-r--r--src/node/chainstate.h15
-rw-r--r--src/node/chainstatemanager_args.cpp46
-rw-r--r--src/node/chainstatemanager_args.h19
-rw-r--r--src/node/coin.h2
-rw-r--r--src/node/coins_view_args.cpp16
-rw-r--r--src/node/coins_view_args.h15
-rw-r--r--src/node/context.cpp2
-rw-r--r--src/node/context.h2
-rw-r--r--src/node/database_args.cpp18
-rw-r--r--src/node/database_args.h15
-rw-r--r--src/node/interface_ui.cpp15
-rw-r--r--src/node/interface_ui.h4
-rw-r--r--src/node/interfaces.cpp107
-rw-r--r--src/node/mempool_args.cpp2
-rw-r--r--src/node/miner.cpp62
-rw-r--r--src/node/miner.h21
-rw-r--r--src/node/minisketchwrapper.cpp8
-rw-r--r--src/node/psbt.cpp4
-rw-r--r--src/node/transaction.h2
-rw-r--r--src/node/txreconciliation.cpp169
-rw-r--r--src/node/txreconciliation.h91
-rw-r--r--src/node/utxo_snapshot.cpp96
-rw-r--r--src/node/utxo_snapshot.h40
-rw-r--r--src/noui.cpp2
-rw-r--r--src/outputtype.cpp2
-rw-r--r--src/outputtype.h2
-rw-r--r--src/policy/feerate.cpp2
-rw-r--r--src/policy/feerate.h2
-rw-r--r--src/policy/fees.cpp48
-rw-r--r--src/policy/fees.h31
-rw-r--r--src/policy/fees_args.cpp4
-rw-r--r--src/policy/packages.cpp2
-rw-r--r--src/policy/packages.h2
-rw-r--r--src/policy/policy.cpp2
-rw-r--r--src/policy/policy.h6
-rw-r--r--src/policy/rbf.cpp12
-rw-r--r--src/policy/rbf.h2
-rw-r--r--src/policy/settings.cpp2
-rw-r--r--src/policy/settings.h2
-rw-r--r--src/pow.cpp2
-rw-r--r--src/pow.h2
-rw-r--r--src/prevector.h2
-rw-r--r--src/primitives/block.h2
-rw-r--r--src/primitives/transaction.cpp2
-rw-r--r--src/primitives/transaction.h9
-rw-r--r--src/protocol.cpp4
-rw-r--r--src/protocol.h8
-rw-r--r--src/psbt.cpp63
-rw-r--r--src/psbt.h44
-rw-r--r--src/pubkey.cpp102
-rw-r--r--src/pubkey.h19
-rw-r--r--src/qt/addressbookpage.cpp3
-rw-r--r--src/qt/addressbookpage.h2
-rw-r--r--src/qt/addresstablemodel.cpp2
-rw-r--r--src/qt/askpassphrasedialog.cpp40
-rw-r--r--src/qt/askpassphrasedialog.h4
-rw-r--r--src/qt/bantablemodel.cpp10
-rw-r--r--src/qt/bantablemodel.h4
-rw-r--r--src/qt/bitcoin.cpp145
-rw-r--r--src/qt/bitcoin.h15
-rw-r--r--src/qt/bitcoin_locale.qrc6
-rw-r--r--src/qt/bitcoinamountfield.cpp7
-rw-r--r--src/qt/bitcoinamountfield.h2
-rw-r--r--src/qt/bitcoingui.cpp32
-rw-r--r--src/qt/bitcoingui.h8
-rw-r--r--src/qt/bitcoinstrings.cpp42
-rw-r--r--src/qt/clientmodel.cpp17
-rw-r--r--src/qt/clientmodel.h13
-rw-r--r--src/qt/coincontroldialog.cpp4
-rw-r--r--src/qt/csvmodelwriter.cpp6
-rw-r--r--src/qt/csvmodelwriter.h2
-rw-r--r--src/qt/editaddressdialog.cpp10
-rw-r--r--src/qt/editaddressdialog.h4
-rw-r--r--src/qt/forms/debugwindow.ui4
-rw-r--r--src/qt/forms/optionsdialog.ui2
-rw-r--r--src/qt/guiconstants.h2
-rw-r--r--src/qt/guiutil.cpp10
-rw-r--r--src/qt/guiutil.h2
-rw-r--r--src/qt/initexecutor.cpp4
-rw-r--r--src/qt/intro.cpp4
-rw-r--r--src/qt/intro.h4
-rw-r--r--src/qt/locale/bitcoin_am.ts26
-rw-r--r--src/qt/locale/bitcoin_ar.ts1783
-rw-r--r--src/qt/locale/bitcoin_az.ts1240
-rw-r--r--src/qt/locale/bitcoin_be.ts36
-rw-r--r--src/qt/locale/bitcoin_bg.ts562
-rw-r--r--src/qt/locale/bitcoin_bn.ts154
-rw-r--r--src/qt/locale/bitcoin_bs.ts67
-rw-r--r--src/qt/locale/bitcoin_ca.ts156
-rw-r--r--src/qt/locale/bitcoin_cs.ts632
-rw-r--r--src/qt/locale/bitcoin_cy.ts30
-rw-r--r--src/qt/locale/bitcoin_da.ts908
-rw-r--r--src/qt/locale/bitcoin_el.ts319
-rw-r--r--src/qt/locale/bitcoin_en.ts299
-rw-r--r--src/qt/locale/bitcoin_en.xlf3301
-rw-r--r--src/qt/locale/bitcoin_eo.ts39
-rw-r--r--src/qt/locale/bitcoin_es.ts2554
-rw-r--r--src/qt/locale/bitcoin_es_CL.ts70
-rw-r--r--src/qt/locale/bitcoin_es_CO.ts1412
-rw-r--r--src/qt/locale/bitcoin_es_DO.ts109
-rw-r--r--src/qt/locale/bitcoin_es_VE.ts33
-rw-r--r--src/qt/locale/bitcoin_et.ts73
-rw-r--r--src/qt/locale/bitcoin_eu.ts735
-rw-r--r--src/qt/locale/bitcoin_fa.ts249
-rw-r--r--src/qt/locale/bitcoin_fi.ts187
-rw-r--r--src/qt/locale/bitcoin_fil.ts140
-rw-r--r--src/qt/locale/bitcoin_fr.ts526
-rw-r--r--src/qt/locale/bitcoin_ga.ts92
-rw-r--r--src/qt/locale/bitcoin_gd.ts32
-rw-r--r--src/qt/locale/bitcoin_gl.ts32
-rw-r--r--src/qt/locale/bitcoin_gl_ES.ts102
-rw-r--r--src/qt/locale/bitcoin_gu.ts31
-rw-r--r--src/qt/locale/bitcoin_ha.ts273
-rw-r--r--src/qt/locale/bitcoin_he.ts138
-rw-r--r--src/qt/locale/bitcoin_hr.ts1421
-rw-r--r--src/qt/locale/bitcoin_hu.ts310
-rw-r--r--src/qt/locale/bitcoin_id.ts509
-rw-r--r--src/qt/locale/bitcoin_is.ts21
-rw-r--r--src/qt/locale/bitcoin_it.ts438
-rw-r--r--src/qt/locale/bitcoin_ja.ts379
-rw-r--r--src/qt/locale/bitcoin_ka.ts244
-rw-r--r--src/qt/locale/bitcoin_kk.ts35
-rw-r--r--src/qt/locale/bitcoin_kl.ts21
-rw-r--r--src/qt/locale/bitcoin_km.ts312
-rw-r--r--src/qt/locale/bitcoin_ko.ts466
-rw-r--r--src/qt/locale/bitcoin_ku.ts357
-rw-r--r--src/qt/locale/bitcoin_ku_IQ.ts45
-rw-r--r--src/qt/locale/bitcoin_ky.ts21
-rw-r--r--src/qt/locale/bitcoin_la.ts28
-rw-r--r--src/qt/locale/bitcoin_lt.ts124
-rw-r--r--src/qt/locale/bitcoin_lv.ts95
-rw-r--r--src/qt/locale/bitcoin_mk.ts24
-rw-r--r--src/qt/locale/bitcoin_ml.ts35
-rw-r--r--src/qt/locale/bitcoin_mn.ts104
-rw-r--r--src/qt/locale/bitcoin_mr_IN.ts118
-rw-r--r--src/qt/locale/bitcoin_ms.ts18
-rw-r--r--src/qt/locale/bitcoin_my.ts30
-rw-r--r--src/qt/locale/bitcoin_nb.ts243
-rw-r--r--src/qt/locale/bitcoin_ne.ts149
-rw-r--r--src/qt/locale/bitcoin_no.ts21
-rw-r--r--src/qt/locale/bitcoin_pa.ts492
-rw-r--r--src/qt/locale/bitcoin_pam.ts24
-rw-r--r--src/qt/locale/bitcoin_pl.ts948
-rw-r--r--src/qt/locale/bitcoin_pt.ts435
-rw-r--r--src/qt/locale/bitcoin_pt_BR.ts557
-rw-r--r--src/qt/locale/bitcoin_ro.ts82
-rw-r--r--src/qt/locale/bitcoin_ru.ts1349
-rw-r--r--src/qt/locale/bitcoin_sc.ts18
-rw-r--r--src/qt/locale/bitcoin_si.ts261
-rw-r--r--src/qt/locale/bitcoin_sk.ts401
-rw-r--r--src/qt/locale/bitcoin_sl.ts336
-rw-r--r--src/qt/locale/bitcoin_sn.ts21
-rw-r--r--src/qt/locale/bitcoin_sq.ts42
-rw-r--r--src/qt/locale/bitcoin_sr.ts802
-rw-r--r--src/qt/locale/bitcoin_sr@latin.ts26
-rw-r--r--src/qt/locale/bitcoin_sv.ts298
-rw-r--r--src/qt/locale/bitcoin_sw.ts21
-rw-r--r--src/qt/locale/bitcoin_szl.ts24
-rw-r--r--src/qt/locale/bitcoin_ta.ts152
-rw-r--r--src/qt/locale/bitcoin_te.ts2254
-rw-r--r--src/qt/locale/bitcoin_th.ts2138
-rw-r--r--src/qt/locale/bitcoin_tk.ts1577
-rw-r--r--src/qt/locale/bitcoin_tl.ts1527
-rw-r--r--src/qt/locale/bitcoin_tr.ts270
-rw-r--r--src/qt/locale/bitcoin_ug.ts60
-rw-r--r--src/qt/locale/bitcoin_uk.ts561
-rw-r--r--src/qt/locale/bitcoin_ur.ts1693
-rw-r--r--src/qt/locale/bitcoin_uz.ts225
-rw-r--r--src/qt/locale/bitcoin_uz@Cyrl.ts73
-rw-r--r--src/qt/locale/bitcoin_uz@Latn.ts1642
-rw-r--r--src/qt/locale/bitcoin_vi.ts2290
-rw-r--r--src/qt/locale/bitcoin_yo.ts42
-rw-r--r--src/qt/locale/bitcoin_zh-Hans.ts4561
-rw-r--r--src/qt/locale/bitcoin_zh.ts460
-rw-r--r--src/qt/locale/bitcoin_zh_CN.ts587
-rw-r--r--src/qt/locale/bitcoin_zh_HK.ts18
-rw-r--r--src/qt/locale/bitcoin_zh_TW.ts565
-rw-r--r--src/qt/locale/bitcoin_zu.ts52
-rw-r--r--src/qt/main.cpp4
-rw-r--r--src/qt/modaloverlay.cpp13
-rw-r--r--src/qt/modaloverlay.h8
-rw-r--r--src/qt/networkstyle.cpp2
-rw-r--r--src/qt/notificator.cpp6
-rw-r--r--src/qt/notificator.h6
-rw-r--r--src/qt/optionsdialog.cpp45
-rw-r--r--src/qt/optionsdialog.h6
-rw-r--r--src/qt/optionsmodel.cpp150
-rw-r--r--src/qt/optionsmodel.h20
-rw-r--r--src/qt/overviewpage.cpp20
-rw-r--r--src/qt/overviewpage.h7
-rw-r--r--src/qt/paymentserver.cpp9
-rw-r--r--src/qt/paymentserver.h6
-rw-r--r--src/qt/peertablemodel.cpp9
-rw-r--r--src/qt/peertablemodel.h4
-rw-r--r--src/qt/peertablesortproxy.cpp2
-rw-r--r--src/qt/platformstyle.cpp4
-rw-r--r--src/qt/psbtoperationsdialog.cpp8
-rw-r--r--src/qt/qrimagewidget.cpp4
-rw-r--r--src/qt/qrimagewidget.h2
-rw-r--r--src/qt/qvalidatedlineedit.cpp8
-rw-r--r--src/qt/qvalidatedlineedit.h6
-rw-r--r--src/qt/qvaluecombobox.cpp4
-rw-r--r--src/qt/qvaluecombobox.h2
-rw-r--r--src/qt/receivecoinsdialog.cpp3
-rw-r--r--src/qt/receivecoinsdialog.h2
-rw-r--r--src/qt/receiverequestdialog.cpp7
-rw-r--r--src/qt/receiverequestdialog.h2
-rw-r--r--src/qt/recentrequeststablemodel.cpp6
-rw-r--r--src/qt/recentrequeststablemodel.h4
-rw-r--r--src/qt/rpcconsole.cpp33
-rw-r--r--src/qt/rpcconsole.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp14
-rw-r--r--src/qt/sendcoinsdialog.h10
-rw-r--r--src/qt/sendcoinsentry.cpp3
-rw-r--r--src/qt/sendcoinsentry.h4
-rw-r--r--src/qt/signverifymessagedialog.cpp3
-rw-r--r--src/qt/signverifymessagedialog.h2
-rw-r--r--src/qt/splashscreen.cpp14
-rw-r--r--src/qt/splashscreen.h7
-rw-r--r--src/qt/test/addressbooktests.cpp4
-rw-r--r--src/qt/test/apptests.cpp4
-rw-r--r--src/qt/test/optiontests.cpp2
-rw-r--r--src/qt/test/optiontests.h2
-rw-r--r--src/qt/test/test_main.cpp4
-rw-r--r--src/qt/test/util.cpp2
-rw-r--r--src/qt/test/util.h2
-rw-r--r--src/qt/test/wallettests.cpp18
-rw-r--r--src/qt/trafficgraphwidget.cpp15
-rw-r--r--src/qt/trafficgraphwidget.h12
-rw-r--r--src/qt/transactiondesc.cpp2
-rw-r--r--src/qt/transactiondesc.h2
-rw-r--r--src/qt/transactionfilterproxy.cpp29
-rw-r--r--src/qt/transactionfilterproxy.h12
-rw-r--r--src/qt/transactionoverviewwidget.cpp2
-rw-r--r--src/qt/transactionoverviewwidget.h2
-rw-r--r--src/qt/transactionrecord.cpp2
-rw-r--r--src/qt/transactionrecord.h6
-rw-r--r--src/qt/transactiontablemodel.cpp8
-rw-r--r--src/qt/transactiontablemodel.h2
-rw-r--r--src/qt/transactionview.cpp20
-rw-r--r--src/qt/transactionview.h4
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/qt/walletcontroller.cpp2
-rw-r--r--src/qt/walletframe.cpp4
-rw-r--r--src/qt/walletmodel.cpp33
-rw-r--r--src/qt/walletmodel.h28
-rw-r--r--src/qt/walletmodeltransaction.cpp7
-rw-r--r--src/qt/walletmodeltransaction.h2
-rw-r--r--src/qt/walletview.cpp9
-rw-r--r--src/qt/walletview.h5
-rw-r--r--src/random.cpp59
-rw-r--r--src/random.h27
-rw-r--r--src/randomenv.cpp18
-rw-r--r--src/rest.cpp87
-rw-r--r--src/reverse_iterator.h2
-rw-r--r--src/rpc/blockchain.cpp428
-rw-r--r--src/rpc/blockchain.h4
-rw-r--r--src/rpc/client.cpp73
-rw-r--r--src/rpc/client.h5
-rw-r--r--src/rpc/external_signer.cpp2
-rw-r--r--src/rpc/fees.cpp6
-rw-r--r--src/rpc/mempool.cpp75
-rw-r--r--src/rpc/mining.cpp14
-rw-r--r--src/rpc/net.cpp115
-rw-r--r--src/rpc/node.cpp36
-rw-r--r--src/rpc/output_script.cpp16
-rw-r--r--src/rpc/rawtransaction.cpp190
-rw-r--r--src/rpc/rawtransaction_util.cpp45
-rw-r--r--src/rpc/rawtransaction_util.h9
-rw-r--r--src/rpc/register.h2
-rw-r--r--src/rpc/request.cpp6
-rw-r--r--src/rpc/server.cpp39
-rw-r--r--src/rpc/server_util.cpp16
-rw-r--r--src/rpc/server_util.h5
-rw-r--r--src/rpc/txoutproof.cpp10
-rw-r--r--src/rpc/util.cpp217
-rw-r--r--src/rpc/util.h108
-rw-r--r--src/scheduler.cpp2
-rw-r--r--src/scheduler.h2
-rw-r--r--src/script/bitcoinconsensus.cpp8
-rw-r--r--src/script/bitcoinconsensus.h2
-rw-r--r--src/script/descriptor.cpp15
-rw-r--r--src/script/descriptor.h12
-rw-r--r--src/script/interpreter.cpp35
-rw-r--r--src/script/interpreter.h7
-rw-r--r--src/script/miniscript.cpp78
-rw-r--r--src/script/miniscript.h343
-rw-r--r--src/script/script.cpp2
-rw-r--r--src/script/script.h2
-rw-r--r--src/script/sigcache.cpp2
-rw-r--r--src/script/sigcache.h2
-rw-r--r--src/script/sign.cpp156
-rw-r--r--src/script/sign.h28
-rw-r--r--src/script/signingprovider.cpp4
-rw-r--r--src/script/signingprovider.h2
-rw-r--r--src/script/standard.cpp27
-rw-r--r--src/script/standard.h14
-rw-r--r--src/secp256k1/.cirrus.yml221
-rw-r--r--src/secp256k1/.gitignore13
-rw-r--r--src/secp256k1/CHANGELOG.md61
-rw-r--r--src/secp256k1/CMakeLists.txt302
-rw-r--r--src/secp256k1/Makefile.am85
-rw-r--r--src/secp256k1/README.md51
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m44
-rwxr-xr-xsrc/secp256k1/ci/cirrus.sh74
-rw-r--r--src/secp256k1/ci/linux-debian.Dockerfile31
-rw-r--r--src/secp256k1/cmake/Check64bitAssembly.cmake14
-rw-r--r--src/secp256k1/cmake/CheckStringOptionValue.cmake12
-rw-r--r--src/secp256k1/cmake/FindValgrind.cmake41
-rw-r--r--src/secp256k1/cmake/TryAddCompileOption.cmake23
-rw-r--r--src/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake3
-rw-r--r--src/secp256k1/cmake/config.cmake.in5
-rw-r--r--src/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake3
-rw-r--r--src/secp256k1/configure.ac142
-rw-r--r--src/secp256k1/contrib/lax_der_privatekey_parsing.h3
-rw-r--r--src/secp256k1/doc/CHANGELOG.md12
-rw-r--r--src/secp256k1/doc/release-process.md62
-rw-r--r--src/secp256k1/doc/safegcd_implementation.md54
-rw-r--r--src/secp256k1/examples/CMakeLists.txt34
-rw-r--r--src/secp256k1/examples/ecdh.c21
-rw-r--r--src/secp256k1/examples/ecdsa.c28
-rw-r--r--src/secp256k1/examples/examples_util.h (renamed from src/secp256k1/examples/random.h)29
-rw-r--r--src/secp256k1/examples/schnorr.c26
-rw-r--r--src/secp256k1/include/secp256k1.h216
-rw-r--r--src/secp256k1/include/secp256k1_ecdh.h4
-rw-r--r--src/secp256k1/include/secp256k1_extrakeys.h8
-rw-r--r--src/secp256k1/include/secp256k1_preallocated.h10
-rw-r--r--src/secp256k1/include/secp256k1_recovery.h4
-rw-r--r--src/secp256k1/include/secp256k1_schnorrsig.h6
-rw-r--r--src/secp256k1/libsecp256k1.pc.in1
-rw-r--r--src/secp256k1/sage/gen_exhaustive_groups.sage200
-rw-r--r--src/secp256k1/sage/prove_group_implementations.sage26
-rw-r--r--src/secp256k1/src/CMakeLists.txt151
-rw-r--r--src/secp256k1/src/assumptions.h7
-rw-r--r--src/secp256k1/src/basic-config.h17
-rw-r--r--src/secp256k1/src/bench.c17
-rw-r--r--src/secp256k1/src/bench.h30
-rw-r--r--src/secp256k1/src/bench_ecmult.c8
-rw-r--r--src/secp256k1/src/bench_internal.c87
-rw-r--r--src/secp256k1/src/checkmem.h88
-rw-r--r--src/secp256k1/src/ctime_tests.c (renamed from src/secp256k1/src/valgrind_ctime_test.c)87
-rw-r--r--src/secp256k1/src/ecmult.h11
-rw-r--r--src/secp256k1/src/ecmult_gen.h12
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h17
-rw-r--r--src/secp256k1/src/ecmult_impl.h12
-rw-r--r--src/secp256k1/src/field.h10
-rw-r--r--src/secp256k1/src/field_10x26_impl.h46
-rw-r--r--src/secp256k1/src/field_5x52_impl.h50
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h252
-rw-r--r--src/secp256k1/src/field_impl.h4
-rw-r--r--src/secp256k1/src/group.h5
-rw-r--r--src/secp256k1/src/group_impl.h108
-rw-r--r--src/secp256k1/src/int128.h90
-rw-r--r--src/secp256k1/src/int128_impl.h18
-rw-r--r--src/secp256k1/src/int128_native.h19
-rw-r--r--src/secp256k1/src/int128_native_impl.h93
-rw-r--r--src/secp256k1/src/int128_struct.h14
-rw-r--r--src/secp256k1/src/int128_struct_impl.h199
-rw-r--r--src/secp256k1/src/modinv32.h9
-rw-r--r--src/secp256k1/src/modinv32_impl.h188
-rw-r--r--src/secp256k1/src/modinv64.h9
-rw-r--r--src/secp256k1/src/modinv64_impl.h392
-rw-r--r--src/secp256k1/src/modules/ecdh/bench_impl.h4
-rw-r--r--src/secp256k1/src/modules/ecdh/tests_impl.h54
-rw-r--r--src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h2
-rw-r--r--src/secp256k1/src/modules/extrakeys/tests_impl.h369
-rw-r--r--src/secp256k1/src/modules/recovery/bench_impl.h10
-rw-r--r--src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h9
-rw-r--r--src/secp256k1/src/modules/recovery/tests_impl.h236
-rw-r--r--src/secp256k1/src/modules/schnorrsig/bench_impl.h18
-rw-r--r--src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h2
-rw-r--r--src/secp256k1/src/modules/schnorrsig/tests_impl.h234
-rw-r--r--src/secp256k1/src/precompute_ecmult.c12
-rw-r--r--src/secp256k1/src/precompute_ecmult_gen.c6
-rw-r--r--src/secp256k1/src/precomputed_ecmult.c3
-rw-r--r--src/secp256k1/src/precomputed_ecmult.h4
-rw-r--r--src/secp256k1/src/precomputed_ecmult_gen.c3
-rw-r--r--src/secp256k1/src/scalar.h11
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h153
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h3
-rw-r--r--src/secp256k1/src/scalar_impl.h19
-rw-r--r--src/secp256k1/src/scalar_low_impl.h3
-rw-r--r--src/secp256k1/src/scratch_impl.h2
-rw-r--r--src/secp256k1/src/secp256k1.c104
-rw-r--r--src/secp256k1/src/selftest.h2
-rw-r--r--src/secp256k1/src/testrand.h4
-rw-r--r--src/secp256k1/src/tests.c2051
-rw-r--r--src/secp256k1/src/tests_exhaustive.c34
-rw-r--r--src/secp256k1/src/util.h68
-rw-r--r--src/serialize.h6
-rw-r--r--src/shutdown.cpp4
-rw-r--r--src/span.h6
-rw-r--r--src/streams.h137
-rw-r--r--src/support/allocators/secure.h1
-rw-r--r--src/support/allocators/zeroafterfree.h2
-rw-r--r--src/support/cleanse.h2
-rw-r--r--src/support/lockedpool.cpp26
-rw-r--r--src/support/lockedpool.h16
-rw-r--r--src/sync.h45
-rw-r--r--src/test/addrman_tests.cpp156
-rw-r--r--src/test/argsman_tests.cpp1043
-rw-r--r--src/test/arith_uint256_tests.cpp2
-rw-r--r--src/test/banman_tests.cpp2
-rw-r--r--src/test/base32_tests.cpp2
-rw-r--r--src/test/base58_tests.cpp6
-rw-r--r--src/test/base64_tests.cpp2
-rw-r--r--src/test/bip32_tests.cpp2
-rw-r--r--src/test/blockchain_tests.cpp2
-rw-r--r--src/test/blockencodings_tests.cpp10
-rw-r--r--src/test/blockfilter_index_tests.cpp2
-rw-r--r--src/test/blockfilter_tests.cpp4
-rw-r--r--src/test/blockmanager_tests.cpp85
-rw-r--r--src/test/bloom_tests.cpp11
-rw-r--r--src/test/checkqueue_tests.cpp7
-rw-r--r--src/test/coins_tests.cpp287
-rw-r--r--src/test/coinstatsindex_tests.cpp12
-rw-r--r--src/test/crypto_tests.cpp172
-rw-r--r--src/test/cuckoocache_tests.cpp2
-rw-r--r--src/test/dbwrapper_tests.cpp68
-rw-r--r--src/test/denialofservice_tests.cpp2
-rw-r--r--src/test/descriptor_tests.cpp71
-rw-r--r--src/test/flatfile_tests.cpp2
-rw-r--r--src/test/fs_tests.cpp2
-rw-r--r--src/test/fuzz/addition_overflow.cpp2
-rw-r--r--src/test/fuzz/addrman.cpp7
-rw-r--r--src/test/fuzz/autofile.cpp2
-rw-r--r--src/test/fuzz/banman.cpp3
-rw-r--r--src/test/fuzz/base_encode_decode.cpp9
-rw-r--r--src/test/fuzz/block.cpp1
-rw-r--r--src/test/fuzz/buffered_file.cpp2
-rw-r--r--src/test/fuzz/chain.cpp2
-rw-r--r--src/test/fuzz/checkqueue.cpp2
-rw-r--r--src/test/fuzz/coins_view.cpp7
-rw-r--r--src/test/fuzz/coinscache_sim.cpp478
-rw-r--r--src/test/fuzz/connman.cpp3
-rw-r--r--src/test/fuzz/crypto_chacha20.cpp118
-rw-r--r--src/test/fuzz/crypto_diff_fuzz_chacha20.cpp33
-rw-r--r--src/test/fuzz/descriptor_parse.cpp1
-rw-r--r--src/test/fuzz/deserialize.cpp3
-rw-r--r--src/test/fuzz/eval_script.cpp7
-rw-r--r--src/test/fuzz/fuzz.cpp2
-rw-r--r--src/test/fuzz/golomb_rice.cpp2
-rw-r--r--src/test/fuzz/hex.cpp9
-rw-r--r--src/test/fuzz/http_request.cpp4
-rw-r--r--src/test/fuzz/i2p.cpp5
-rw-r--r--src/test/fuzz/integer.cpp8
-rw-r--r--src/test/fuzz/key.cpp5
-rw-r--r--src/test/fuzz/key_io.cpp1
-rw-r--r--src/test/fuzz/message.cpp1
-rw-r--r--src/test/fuzz/miniscript.cpp952
-rw-r--r--src/test/fuzz/net.cpp3
-rw-r--r--src/test/fuzz/net_permissions.cpp3
-rw-r--r--src/test/fuzz/netaddress.cpp11
-rw-r--r--src/test/fuzz/netbase_dns_lookup.cpp4
-rw-r--r--src/test/fuzz/node_eviction.cpp3
-rw-r--r--src/test/fuzz/p2p_transport_serialization.cpp4
-rw-r--r--src/test/fuzz/parse_univalue.cpp3
-rw-r--r--src/test/fuzz/partially_downloaded_block.cpp142
-rw-r--r--src/test/fuzz/policy_estimator.cpp3
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp2
-rw-r--r--src/test/fuzz/pow.cpp17
-rw-r--r--src/test/fuzz/prevector.cpp6
-rw-r--r--src/test/fuzz/process_message.cpp9
-rw-r--r--src/test/fuzz/process_messages.cpp8
-rw-r--r--src/test/fuzz/psbt.cpp9
-rw-r--r--src/test/fuzz/rbf.cpp3
-rw-r--r--src/test/fuzz/rpc.cpp5
-rw-r--r--src/test/fuzz/script.cpp5
-rw-r--r--src/test/fuzz/script_assets_test_minimizer.cpp7
-rw-r--r--src/test/fuzz/script_flags.cpp7
-rw-r--r--src/test/fuzz/script_sigcache.cpp2
-rw-r--r--src/test/fuzz/script_sign.cpp7
-rw-r--r--src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp6
-rw-r--r--src/test/fuzz/signature_checker.cpp9
-rw-r--r--src/test/fuzz/socks5.cpp3
-rw-r--r--src/test/fuzz/string.cpp8
-rw-r--r--src/test/fuzz/transaction.cpp2
-rw-r--r--src/test/fuzz/tx_in.cpp5
-rw-r--r--src/test/fuzz/tx_out.cpp7
-rw-r--r--src/test/fuzz/tx_pool.cpp9
-rw-r--r--src/test/fuzz/txorphan.cpp22
-rw-r--r--src/test/fuzz/util.cpp316
-rw-r--r--src/test/fuzz/util.h111
-rw-r--r--src/test/fuzz/util/mempool.cpp5
-rw-r--r--src/test/fuzz/util/mempool.h8
-rw-r--r--src/test/fuzz/util/net.cpp358
-rw-r--r--src/test/fuzz/util/net.h141
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp2
-rw-r--r--src/test/fuzz/validation_load_mempool.cpp3
-rw-r--r--src/test/fuzz/versionbits.cpp2
-rw-r--r--src/test/getarg_tests.cpp6
-rw-r--r--src/test/hash_tests.cpp1
-rw-r--r--src/test/i2p_tests.cpp4
-rw-r--r--src/test/interfaces_tests.cpp2
-rw-r--r--src/test/key_io_tests.cpp5
-rw-r--r--src/test/key_tests.cpp10
-rw-r--r--src/test/logging_tests.cpp17
-rw-r--r--src/test/main.cpp2
-rw-r--r--src/test/mempool_tests.cpp24
-rw-r--r--src/test/merkle_tests.cpp17
-rw-r--r--src/test/miner_tests.cpp481
-rw-r--r--src/test/miniscript_tests.cpp234
-rw-r--r--src/test/minisketch_tests.cpp3
-rw-r--r--src/test/multisig_tests.cpp5
-rw-r--r--src/test/net_peer_eviction_tests.cpp2
-rw-r--r--src/test/net_tests.cpp36
-rw-r--r--src/test/netbase_tests.cpp31
-rw-r--r--src/test/orphanage_tests.cpp15
-rw-r--r--src/test/pmt_tests.cpp5
-rw-r--r--src/test/policyestimator_tests.cpp9
-rw-r--r--src/test/pow_tests.cpp3
-rw-r--r--src/test/prevector_tests.cpp7
-rw-r--r--src/test/raii_event_tests.cpp2
-rw-r--r--src/test/random_tests.cpp6
-rw-r--r--src/test/rbf_tests.cpp3
-rw-r--r--src/test/rpc_tests.cpp75
-rw-r--r--src/test/sanity_tests.cpp2
-rw-r--r--src/test/scheduler_tests.cpp2
-rw-r--r--src/test/script_p2sh_tests.cpp17
-rw-r--r--src/test/script_standard_tests.cpp7
-rw-r--r--src/test/script_tests.cpp48
-rw-r--r--src/test/serfloat_tests.cpp3
-rw-r--r--src/test/serialize_tests.cpp27
-rw-r--r--src/test/settings_tests.cpp3
-rw-r--r--src/test/sighash_tests.cpp8
-rw-r--r--src/test/sigopcount_tests.cpp3
-rw-r--r--src/test/skiplist_tests.cpp3
-rw-r--r--src/test/sock_tests.cpp4
-rw-r--r--src/test/streams_tests.cpp102
-rw-r--r--src/test/sync_tests.cpp6
-rw-r--r--src/test/system_tests.cpp31
-rw-r--r--src/test/timedata_tests.cpp2
-rw-r--r--src/test/transaction_tests.cpp58
-rw-r--r--src/test/translation_tests.cpp21
-rw-r--r--src/test/txindex_tests.cpp13
-rw-r--r--src/test/txpackage_tests.cpp121
-rw-r--r--src/test/txreconciliation_tests.cpp84
-rw-r--r--src/test/txrequest_tests.cpp1
-rw-r--r--src/test/txvalidationcache_tests.cpp12
-rw-r--r--src/test/uint256_tests.cpp2
-rw-r--r--src/test/util/blockfilter.cpp1
-rw-r--r--src/test/util/chainstate.h51
-rw-r--r--src/test/util/coins.cpp27
-rw-r--r--src/test/util/coins.h19
-rw-r--r--src/test/util/json.cpp17
-rw-r--r--src/test/util/json.h14
-rw-r--r--src/test/util/logging.h2
-rw-r--r--src/test/util/mining.cpp14
-rw-r--r--src/test/util/mining.h4
-rw-r--r--src/test/util/net.cpp9
-rw-r--r--src/test/util/net.h10
-rw-r--r--src/test/util/random.h45
-rw-r--r--src/test/util/setup_common.cpp102
-rw-r--r--src/test/util/setup_common.h62
-rw-r--r--src/test/util/txmempool.cpp38
-rw-r--r--src/test/util/txmempool.h37
-rw-r--r--src/test/util/validation.cpp2
-rw-r--r--src/test/util/validation.h2
-rw-r--r--src/test/util/wallet.cpp27
-rw-r--r--src/test/util/wallet.h26
-rw-r--r--src/test/util/xoroshiro128plusplus.h71
-rw-r--r--src/test/util_tests.cpp1076
-rw-r--r--src/test/validation_block_tests.cpp3
-rw-r--r--src/test/validation_chainstate_tests.cpp23
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp567
-rw-r--r--src/test/validation_flush_tests.cpp29
-rw-r--r--src/test/versionbits_tests.cpp5
-rw-r--r--src/test/xoroshiro128plusplus_tests.cpp29
-rw-r--r--src/timedata.cpp2
-rw-r--r--src/timedata.h2
-rw-r--r--src/tinyformat.h12
-rw-r--r--src/torcontrol.cpp12
-rw-r--r--src/torcontrol.h2
-rw-r--r--src/txdb.cpp35
-rw-r--r--src/txdb.h31
-rw-r--r--src/txmempool.cpp209
-rw-r--r--src/txmempool.h235
-rw-r--r--src/txorphanage.cpp74
-rw-r--r--src/txorphanage.h55
-rw-r--r--src/uint256.cpp15
-rw-r--r--src/uint256.h82
-rw-r--r--src/univalue/include/univalue.h15
-rw-r--r--src/univalue/include/univalue_utffilter.h12
-rw-r--r--src/univalue/lib/univalue.cpp12
-rw-r--r--src/univalue/lib/univalue_get.cpp2
-rw-r--r--src/univalue/test/object.cpp15
-rw-r--r--src/util/asmap.cpp2
-rw-r--r--src/util/bip32.cpp2
-rw-r--r--src/util/bip32.h2
-rw-r--r--src/util/bytevectorhash.cpp2
-rw-r--r--src/util/bytevectorhash.h2
-rw-r--r--src/util/check.cpp25
-rw-r--r--src/util/check.h35
-rw-r--r--src/util/epochguard.h2
-rw-r--r--src/util/error.cpp9
-rw-r--r--src/util/error.h5
-rw-r--r--src/util/exception.cpp41
-rw-r--r--src/util/exception.h14
-rw-r--r--src/util/fastrange.h2
-rw-r--r--src/util/fees.cpp2
-rw-r--r--src/util/fees.h2
-rw-r--r--src/util/getuniquepath.cpp2
-rw-r--r--src/util/golombrice.h2
-rw-r--r--src/util/hasher.cpp7
-rw-r--r--src/util/hasher.h4
-rw-r--r--src/util/macros.h2
-rw-r--r--src/util/message.cpp2
-rw-r--r--src/util/message.h2
-rw-r--r--src/util/moneystr.cpp4
-rw-r--r--src/util/moneystr.h2
-rw-r--r--src/util/overflow.h2
-rw-r--r--src/util/readwritefile.cpp6
-rw-r--r--src/util/serfloat.h2
-rw-r--r--src/util/settings.cpp4
-rw-r--r--src/util/settings.h2
-rw-r--r--src/util/sock.cpp36
-rw-r--r--src/util/sock.h20
-rw-r--r--src/util/spanparsing.cpp2
-rw-r--r--src/util/spanparsing.h2
-rw-r--r--src/util/strencodings.cpp21
-rw-r--r--src/util/strencodings.h23
-rw-r--r--src/util/string.cpp2
-rw-r--r--src/util/string.h2
-rw-r--r--src/util/syscall_sandbox.cpp2
-rw-r--r--src/util/syscall_sandbox.h2
-rw-r--r--src/util/system.cpp155
-rw-r--r--src/util/system.h48
-rw-r--r--src/util/thread.cpp4
-rw-r--r--src/util/thread.h2
-rw-r--r--src/util/threadinterrupt.cpp (renamed from src/threadinterrupt.cpp)4
-rw-r--r--src/util/threadinterrupt.h (renamed from src/threadinterrupt.h)8
-rw-r--r--src/util/threadnames.cpp2
-rw-r--r--src/util/time.cpp2
-rw-r--r--src/util/time.h5
-rw-r--r--src/util/tokenpipe.cpp2
-rw-r--r--src/util/translation.h17
-rw-r--r--src/util/vector.h2
-rw-r--r--src/validation.cpp1364
-rw-r--r--src/validation.h275
-rw-r--r--src/validationinterface.cpp9
-rw-r--r--src/validationinterface.h4
-rw-r--r--src/versionbits.cpp4
-rw-r--r--src/versionbits.h2
-rw-r--r--src/wallet/bdb.cpp84
-rw-r--r--src/wallet/bdb.h67
-rw-r--r--src/wallet/coincontrol.h4
-rw-r--r--src/wallet/coinselection.cpp71
-rw-r--r--src/wallet/coinselection.h82
-rw-r--r--src/wallet/context.cpp2
-rw-r--r--src/wallet/crypter.h2
-rw-r--r--src/wallet/db.h64
-rw-r--r--src/wallet/dump.cpp26
-rw-r--r--src/wallet/dump.h2
-rw-r--r--src/wallet/external_signer_scriptpubkeyman.cpp2
-rw-r--r--src/wallet/external_signer_scriptpubkeyman.h8
-rw-r--r--src/wallet/feebumper.cpp40
-rw-r--r--src/wallet/feebumper.h5
-rw-r--r--src/wallet/fees.cpp4
-rw-r--r--src/wallet/init.cpp5
-rw-r--r--src/wallet/interfaces.cpp23
-rw-r--r--src/wallet/load.cpp2
-rw-r--r--src/wallet/load.h2
-rw-r--r--src/wallet/receive.cpp2
-rw-r--r--src/wallet/receive.h2
-rw-r--r--src/wallet/rpc/addresses.cpp18
-rw-r--r--src/wallet/rpc/backup.cpp123
-rw-r--r--src/wallet/rpc/coins.cpp35
-rw-r--r--src/wallet/rpc/encrypt.cpp65
-rw-r--r--src/wallet/rpc/signmessage.cpp2
-rw-r--r--src/wallet/rpc/spend.cpp246
-rw-r--r--src/wallet/rpc/transactions.cpp51
-rw-r--r--src/wallet/rpc/util.cpp12
-rw-r--r--src/wallet/rpc/util.h2
-rw-r--r--src/wallet/rpc/wallet.cpp78
-rw-r--r--src/wallet/salvage.cpp4
-rw-r--r--src/wallet/salvage.h2
-rw-r--r--src/wallet/scriptpubkeyman.cpp96
-rw-r--r--src/wallet/scriptpubkeyman.h30
-rw-r--r--src/wallet/spend.cpp651
-rw-r--r--src/wallet/spend.h125
-rw-r--r--src/wallet/sqlite.cpp66
-rw-r--r--src/wallet/sqlite.h40
-rw-r--r--src/wallet/test/availablecoins_tests.cpp107
-rw-r--r--src/wallet/test/coinselector_tests.cpp312
-rw-r--r--src/wallet/test/db_tests.cpp2
-rw-r--r--src/wallet/test/feebumper_tests.cpp2
-rw-r--r--src/wallet/test/fuzz/coinselection.cpp6
-rw-r--r--src/wallet/test/fuzz/notifications.cpp2
-rw-r--r--src/wallet/test/fuzz/parse_iso8601.cpp2
-rw-r--r--src/wallet/test/group_outputs_tests.cpp234
-rw-r--r--src/wallet/test/init_test_fixture.cpp2
-rw-r--r--src/wallet/test/init_tests.cpp2
-rw-r--r--src/wallet/test/ismine_tests.cpp339
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp2
-rw-r--r--src/wallet/test/scriptpubkeyman_tests.cpp2
-rw-r--r--src/wallet/test/spend_tests.cpp51
-rw-r--r--src/wallet/test/util.cpp52
-rw-r--r--src/wallet/test/util.h17
-rw-r--r--src/wallet/test/wallet_crypto_tests.cpp3
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp4
-rw-r--r--src/wallet/test/wallet_test_fixture.h2
-rw-r--r--src/wallet/test/wallet_tests.cpp100
-rw-r--r--src/wallet/test/walletdb_tests.cpp2
-rw-r--r--src/wallet/test/walletload_tests.cpp139
-rw-r--r--src/wallet/transaction.h3
-rw-r--r--src/wallet/wallet.cpp444
-rw-r--r--src/wallet/wallet.h63
-rw-r--r--src/wallet/walletdb.cpp82
-rw-r--r--src/wallet/walletdb.h9
-rw-r--r--src/wallet/wallettool.cpp12
-rw-r--r--src/wallet/walletutil.cpp2
-rw-r--r--src/walletinitinterface.h2
-rw-r--r--src/warnings.cpp2
-rw-r--r--src/zmq/zmqabstractnotifier.h8
-rw-r--r--src/zmq/zmqnotificationinterface.cpp18
-rw-r--r--src/zmq/zmqnotificationinterface.h8
-rw-r--r--src/zmq/zmqpublishnotifier.cpp37
-rw-r--r--src/zmq/zmqpublishnotifier.h6
-rw-r--r--src/zmq/zmqrpc.cpp7
-rw-r--r--src/zmq/zmqutil.cpp2
-rw-r--r--test/README.md41
-rw-r--r--test/functional/data/invalid_txs.py11
-rw-r--r--test/functional/data/rpc_decodescript.json2
-rw-r--r--test/functional/data/rpc_getblockstats.json90
-rw-r--r--test/functional/data/rpc_psbt.json4
-rwxr-xr-xtest/functional/example_test.py5
-rwxr-xr-xtest/functional/feature_abortnode.py3
-rwxr-xr-xtest/functional/feature_addrman.py2
-rwxr-xr-xtest/functional/feature_assumevalid.py20
-rwxr-xr-xtest/functional/feature_bind_extra.py2
-rwxr-xr-xtest/functional/feature_bip68_sequence.py141
-rwxr-xr-xtest/functional/feature_block.py52
-rwxr-xr-xtest/functional/feature_cltv.py5
-rwxr-xr-xtest/functional/feature_coinstatsindex.py13
-rwxr-xr-xtest/functional/feature_config_args.py65
-rwxr-xr-xtest/functional/feature_csv_activation.py2
-rwxr-xr-xtest/functional/feature_dbcrash.py5
-rwxr-xr-xtest/functional/feature_dersig.py2
-rwxr-xr-xtest/functional/feature_discover.py75
-rwxr-xr-xtest/functional/feature_fee_estimation.py48
-rwxr-xr-xtest/functional/feature_filelock.py5
-rwxr-xr-xtest/functional/feature_index_prune.py9
-rwxr-xr-xtest/functional/feature_init.py6
-rwxr-xr-xtest/functional/feature_maxtipage.py27
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py5
-rwxr-xr-xtest/functional/feature_minchainwork.py2
-rwxr-xr-xtest/functional/feature_notifications.py15
-rwxr-xr-xtest/functional/feature_nulldummy.py2
-rwxr-xr-xtest/functional/feature_posix_fs_permissions.py43
-rwxr-xr-xtest/functional/feature_proxy.py35
-rwxr-xr-xtest/functional/feature_pruning.py51
-rwxr-xr-xtest/functional/feature_rbf.py14
-rwxr-xr-xtest/functional/feature_reindex.py50
-rwxr-xr-xtest/functional/feature_remove_pruned_files_on_startup.py54
-rwxr-xr-xtest/functional/feature_segwit.py5
-rwxr-xr-xtest/functional/feature_signet.py2
-rwxr-xr-xtest/functional/feature_startupnotify.py13
-rwxr-xr-xtest/functional/feature_syscall_sandbox.py2
-rwxr-xr-xtest/functional/feature_taproot.py70
-rwxr-xr-xtest/functional/feature_txindex_compatibility.py9
-rwxr-xr-xtest/functional/feature_utxo_set_hash.py2
-rwxr-xr-xtest/functional/feature_versionbits_warning.py2
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py17
-rwxr-xr-xtest/functional/interface_rest.py42
-rwxr-xr-xtest/functional/interface_rpc.py4
-rwxr-xr-xtest/functional/interface_usdt_coinselection.py3
-rwxr-xr-xtest/functional/interface_usdt_utxocache.py5
-rwxr-xr-xtest/functional/interface_usdt_validation.py2
-rwxr-xr-xtest/functional/interface_zmq.py19
-rwxr-xr-xtest/functional/mempool_accept.py46
-rwxr-xr-xtest/functional/mempool_compatibility.py12
-rwxr-xr-xtest/functional/mempool_datacarrier.py3
-rwxr-xr-xtest/functional/mempool_dust.py115
-rwxr-xr-xtest/functional/mempool_expiry.py11
-rwxr-xr-xtest/functional/mempool_limit.py3
-rwxr-xr-xtest/functional/mempool_package_limits.py14
-rwxr-xr-xtest/functional/mempool_package_onemore.py3
-rwxr-xr-xtest/functional/mempool_packages.py123
-rwxr-xr-xtest/functional/mempool_persist.py6
-rwxr-xr-xtest/functional/mempool_reorg.py3
-rwxr-xr-xtest/functional/mempool_resurrect.py6
-rwxr-xr-xtest/functional/mempool_sigoplimit.py154
-rwxr-xr-xtest/functional/mempool_spend_coinbase.py3
-rwxr-xr-xtest/functional/mempool_unbroadcast.py9
-rwxr-xr-xtest/functional/mempool_updatefromblock.py59
-rwxr-xr-xtest/functional/mining_basic.py4
-rwxr-xr-xtest/functional/mining_getblocktemplate_longpoll.py18
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py3
-rwxr-xr-xtest/functional/mocks/invalid_signer.py4
-rwxr-xr-xtest/functional/mocks/signer.py14
-rwxr-xr-xtest/functional/p2p_addr_relay.py2
-rwxr-xr-xtest/functional/p2p_blockfilters.py2
-rwxr-xr-xtest/functional/p2p_blocksonly.py7
-rwxr-xr-xtest/functional/p2p_compactblocks.py2
-rwxr-xr-xtest/functional/p2p_disconnect_ban.py23
-rwxr-xr-xtest/functional/p2p_dos_header_tree.py6
-rwxr-xr-xtest/functional/p2p_eviction.py32
-rwxr-xr-xtest/functional/p2p_feefilter.py4
-rwxr-xr-xtest/functional/p2p_filter.py1
-rwxr-xr-xtest/functional/p2p_getaddr_caching.py16
-rwxr-xr-xtest/functional/p2p_headers_sync_with_minchainwork.py9
-rwxr-xr-xtest/functional/p2p_i2p_sessions.py4
-rwxr-xr-xtest/functional/p2p_ibd_stalling.py164
-rwxr-xr-xtest/functional/p2p_invalid_messages.py41
-rwxr-xr-xtest/functional/p2p_invalid_tx.py2
-rwxr-xr-xtest/functional/p2p_leak.py2
-rwxr-xr-xtest/functional/p2p_leak_tx.py4
-rwxr-xr-xtest/functional/p2p_message_capture.py6
-rwxr-xr-xtest/functional/p2p_node_network_limited.py2
-rwxr-xr-xtest/functional/p2p_permissions.py39
-rwxr-xr-xtest/functional/p2p_ping.py12
-rwxr-xr-xtest/functional/p2p_segwit.py14
-rwxr-xr-xtest/functional/p2p_sendtxrcncl.py233
-rwxr-xr-xtest/functional/p2p_timeouts.py2
-rwxr-xr-xtest/functional/p2p_tx_download.py25
-rwxr-xr-xtest/functional/p2p_tx_privacy.py77
-rwxr-xr-xtest/functional/p2p_unrequested_blocks.py2
-rwxr-xr-xtest/functional/rpc_blockchain.py33
-rwxr-xr-xtest/functional/rpc_createmultisig.py8
-rwxr-xr-xtest/functional/rpc_decodescript.py17
-rwxr-xr-xtest/functional/rpc_deriveaddresses.py9
-rwxr-xr-xtest/functional/rpc_dumptxoutset.py2
-rwxr-xr-xtest/functional/rpc_estimatefee.py2
-rwxr-xr-xtest/functional/rpc_generate.py3
-rwxr-xr-xtest/functional/rpc_getblockfrompeer.py83
-rwxr-xr-xtest/functional/rpc_getblockstats.py20
-rwxr-xr-xtest/functional/rpc_help.py5
-rwxr-xr-xtest/functional/rpc_invalid_address_message.py33
-rwxr-xr-xtest/functional/rpc_invalidateblock.py2
-rwxr-xr-xtest/functional/rpc_mempool_info.py3
-rwxr-xr-xtest/functional/rpc_misc.py2
-rwxr-xr-xtest/functional/rpc_named_arguments.py5
-rwxr-xr-xtest/functional/rpc_net.py62
-rwxr-xr-xtest/functional/rpc_packages.py315
-rwxr-xr-xtest/functional/rpc_preciousblock.py2
-rwxr-xr-xtest/functional/rpc_psbt.py155
-rwxr-xr-xtest/functional/rpc_rawtransaction.py155
-rwxr-xr-xtest/functional/rpc_scanblocks.py137
-rwxr-xr-xtest/functional/rpc_scantxoutset.py6
-rwxr-xr-xtest/functional/rpc_signer.py2
-rwxr-xr-xtest/functional/rpc_signmessagewithprivkey.py2
-rwxr-xr-xtest/functional/rpc_txoutproof.py7
-rwxr-xr-xtest/functional/rpc_uptime.py2
-rwxr-xr-xtest/functional/rpc_users.py6
-rw-r--r--test/functional/test-shell.md4
-rw-r--r--test/functional/test_framework/address.py2
-rw-r--r--test/functional/test_framework/authproxy.py11
-rw-r--r--test/functional/test_framework/blockfilter.py49
-rw-r--r--test/functional/test_framework/blocktools.py7
-rw-r--r--test/functional/test_framework/key.py14
-rwxr-xr-xtest/functional/test_framework/messages.py24
-rw-r--r--test/functional/test_framework/netutil.py2
-rwxr-xr-xtest/functional/test_framework/p2p.py10
-rw-r--r--test/functional/test_framework/psbt.py17
-rw-r--r--test/functional/test_framework/script.py22
-rwxr-xr-xtest/functional/test_framework/script_util.py23
-rw-r--r--test/functional/test_framework/siphash.py56
-rwxr-xr-xtest/functional/test_framework/test_framework.py87
-rwxr-xr-xtest/functional/test_framework/test_node.py42
-rw-r--r--test/functional/test_framework/test_shell.py5
-rw-r--r--test/functional/test_framework/util.py24
-rw-r--r--test/functional/test_framework/wallet.py229
-rwxr-xr-xtest/functional/test_runner.py137
-rwxr-xr-xtest/functional/tool_signet_miner.py3
-rwxr-xr-xtest/functional/tool_wallet.py7
-rwxr-xr-xtest/functional/wallet_abandonconflict.py5
-rwxr-xr-xtest/functional/wallet_address_types.py5
-rwxr-xr-xtest/functional/wallet_avoid_mixing_output_types.py3
-rwxr-xr-xtest/functional/wallet_avoidreuse.py8
-rwxr-xr-xtest/functional/wallet_backup.py5
-rwxr-xr-xtest/functional/wallet_backwards_compatibility.py (renamed from test/functional/feature_backwards_compatibility.py)22
-rwxr-xr-xtest/functional/wallet_balance.py15
-rwxr-xr-xtest/functional/wallet_basic.py46
-rwxr-xr-xtest/functional/wallet_bumpfee.py92
-rwxr-xr-xtest/functional/wallet_change_address.py108
-rwxr-xr-xtest/functional/wallet_coinbase_category.py5
-rwxr-xr-xtest/functional/wallet_create_tx.py5
-rwxr-xr-xtest/functional/wallet_createwallet.py5
-rwxr-xr-xtest/functional/wallet_crosschain.py25
-rwxr-xr-xtest/functional/wallet_descriptor.py38
-rwxr-xr-xtest/functional/wallet_disable.py2
-rwxr-xr-xtest/functional/wallet_dump.py5
-rwxr-xr-xtest/functional/wallet_encryption.py16
-rwxr-xr-xtest/functional/wallet_fallbackfee.py5
-rwxr-xr-xtest/functional/wallet_fast_rescan.py104
-rwxr-xr-xtest/functional/wallet_fundrawtransaction.py (renamed from test/functional/rpc_fundrawtransaction.py)150
-rwxr-xr-xtest/functional/wallet_groups.py10
-rwxr-xr-xtest/functional/wallet_hd.py5
-rwxr-xr-xtest/functional/wallet_implicitsegwit.py7
-rwxr-xr-xtest/functional/wallet_import_rescan.py35
-rwxr-xr-xtest/functional/wallet_import_with_label.py5
-rwxr-xr-xtest/functional/wallet_importdescriptors.py73
-rwxr-xr-xtest/functional/wallet_importmulti.py5
-rwxr-xr-xtest/functional/wallet_importprunedfunds.py5
-rwxr-xr-xtest/functional/wallet_inactive_hdchains.py5
-rwxr-xr-xtest/functional/wallet_keypool.py8
-rwxr-xr-xtest/functional/wallet_keypool_topup.py5
-rwxr-xr-xtest/functional/wallet_labels.py55
-rwxr-xr-xtest/functional/wallet_listdescriptors.py30
-rwxr-xr-xtest/functional/wallet_listreceivedby.py5
-rwxr-xr-xtest/functional/wallet_listsinceblock.py34
-rwxr-xr-xtest/functional/wallet_listtransactions.py17
-rwxr-xr-xtest/functional/wallet_migration.py124
-rwxr-xr-xtest/functional/wallet_miniscript.py214
-rwxr-xr-xtest/functional/wallet_multisig_descriptor_psbt.py5
-rwxr-xr-xtest/functional/wallet_multiwallet.py11
-rwxr-xr-xtest/functional/wallet_orphanedreward.py42
-rwxr-xr-xtest/functional/wallet_pruning.py159
-rwxr-xr-xtest/functional/wallet_reorgsrestore.py9
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py5
-rwxr-xr-xtest/functional/wallet_send.py33
-rwxr-xr-xtest/functional/wallet_sendall.py119
-rwxr-xr-xtest/functional/wallet_signer.py51
-rwxr-xr-xtest/functional/wallet_signmessagewithaddress.py5
-rwxr-xr-xtest/functional/wallet_signrawtransactionwithwallet.py5
-rwxr-xr-xtest/functional/wallet_simulaterawtx.py5
-rwxr-xr-xtest/functional/wallet_startup.py5
-rwxr-xr-xtest/functional/wallet_taproot.py179
-rwxr-xr-xtest/functional/wallet_timelock.py3
-rwxr-xr-xtest/functional/wallet_transactiontime_rescan.py60
-rwxr-xr-xtest/functional/wallet_txn_clone.py3
-rwxr-xr-xtest/functional/wallet_txn_doublespend.py3
-rwxr-xr-xtest/functional/wallet_upgradewallet.py5
-rwxr-xr-xtest/functional/wallet_watchonly.py5
-rwxr-xr-xtest/fuzz/test_runner.py10
-rwxr-xr-xtest/get_previous_releases.py51
-rw-r--r--test/lint/README.md18
-rwxr-xr-xtest/lint/all-lint.py3
-rwxr-xr-xtest/lint/check-doc.py4
-rwxr-xr-xtest/lint/commit-script-check.sh2
-rwxr-xr-xtest/lint/lint-assertions.py2
-rwxr-xr-xtest/lint/lint-circular-dependencies.py6
-rwxr-xr-xtest/lint/lint-files.py2
-rwxr-xr-xtest/lint/lint-git-commit-check.py8
-rwxr-xr-xtest/lint/lint-includes.py14
-rwxr-xr-xtest/lint/lint-locale-dependence.py5
-rwxr-xr-xtest/lint/lint-logs.py2
-rwxr-xr-xtest/lint/lint-python-mutable-default-parameters.py4
-rwxr-xr-xtest/lint/lint-python-utf8-encoding.py6
-rwxr-xr-xtest/lint/lint-python.py1
-rwxr-xr-xtest/lint/lint-shell.py2
-rwxr-xr-xtest/lint/lint-spelling.py2
-rwxr-xr-xtest/lint/lint-submodule.py2
-rwxr-xr-xtest/lint/lint-tests.py2
-rwxr-xr-xtest/lint/lint-whitespace.py6
-rwxr-xr-xtest/lint/run-lint-format-strings.py3
-rw-r--r--test/lint/spelling.ignore-words.txt1
-rw-r--r--test/sanitizer_suppressions/ubsan2
-rwxr-xr-xtest/util/rpcauth-test.py11
-rwxr-xr-xtest/util/test_runner.py6
1328 files changed, 70836 insertions, 23522 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index f9b47ff7d9..80b8b2ac27 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -1,4 +1,5 @@
env: # Global defaults
+ CIRRUS_CLONE_DEPTH: 1
PACKAGE_MANAGER_INSTALL: "apt-get update && apt-get install -y"
MAKEJOBS: "-j10"
TEST_RUNNER_PORT_MIN: "14000" # Must be larger than 12321, which is used for the http cache. See https://cirrus-ci.org/guide/writing-tasks/#http-cache
@@ -27,8 +28,9 @@ base_template: &BASE_TEMPLATE
# Unconditionally install git (used in fingerprint_script).
- bash -c "$PACKAGE_MANAGER_INSTALL git"
- if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
- - git fetch $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge"
+ - git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge"
- git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts
+ # Also, the merge commit is used to lint COMMIT_RANGE="HEAD~..HEAD"
main_template: &MAIN_TEMPLATE
timeout_in: 120m # https://cirrus-ci.org/faq/#instance-timed-out
@@ -37,7 +39,7 @@ main_template: &MAIN_TEMPLATE
ci_script:
- ./ci/test_run_all.sh
-global_task_template: &GLOBAL_TASK_TEMPLATE
+container_depends_template: &CONTAINER_DEPENDS_TEMPLATE
<< : *BASE_TEMPLATE
container:
# https://cirrus-ci.org/faq/#are-there-any-limits
@@ -47,15 +49,10 @@ global_task_template: &GLOBAL_TASK_TEMPLATE
memory: 8G # Set to 8GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-containers
depends_built_cache:
folder: "depends/built"
- fingerprint_script: echo $CIRRUS_TASK_NAME $(git rev-list -1 HEAD ./depends)
- << : *MAIN_TEMPLATE
+ fingerprint_script: echo $CIRRUS_TASK_NAME $(git rev-parse HEAD:depends)
-macos_native_task_template: &MACOS_NATIVE_TASK_TEMPLATE
- << : *BASE_TEMPLATE
- check_clang_script:
- - clang --version
- brew_install_script:
- - brew install boost libevent qt@5 miniupnpc libnatpmp ccache zeromq qrencode libtool automake gnu-getopt
+global_task_template: &GLOBAL_TASK_TEMPLATE
+ << : *CONTAINER_DEPENDS_TEMPLATE
<< : *MAIN_TEMPLATE
compute_credits_template: &CREDITS_TEMPLATE
@@ -64,14 +61,19 @@ compute_credits_template: &CREDITS_TEMPLATE
use_compute_credits: $CIRRUS_REPO_FULL_NAME == 'bitcoin/bitcoin' && $CIRRUS_PR != ""
task:
- name: 'lint [bionic]'
+ name: 'lint [bookworm]'
<< : *BASE_TEMPLATE
container:
- image: ubuntu:bionic # For python 3.6, oldest supported version according to doc/dependencies.md
+ image: debian:bookworm
cpu: 1
memory: 1G
# For faster CI feedback, immediately schedule the linters
<< : *CREDITS_TEMPLATE
+ python_cache:
+ folder: "/tmp/python"
+ fingerprint_script: cat .python-version /etc/os-release
+ unshallow_script:
+ - git fetch --unshallow --no-tags
lint_script:
- ./ci/lint_run_all.sh
env:
@@ -101,7 +103,7 @@ task:
env:
PATH: 'C:\jom;C:\Python39;C:\Python39\Scripts;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin;%PATH%'
PYTHONUTF8: 1
- CI_VCPKG_TAG: '2022.09.27'
+ CI_VCPKG_TAG: '2023.01.09'
VCPKG_DOWNLOADS: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\downloads'
VCPKG_DEFAULT_BINARY_CACHE: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\archives'
CCACHE_DIR: 'C:\Users\ContainerAdministrator\AppData\Local\ccache'
@@ -152,7 +154,7 @@ task:
ccache_cache:
folder: '%CCACHE_DIR%'
install_tools_script:
- - choco install --yes --no-progress ccache --version=4.6.1
+ - choco install --yes --no-progress ccache --version=4.7.4
- choco install --yes --no-progress python3 --version=3.9.6
- pip install zmq
- ccache --version
@@ -171,20 +173,20 @@ task:
- cd %CIRRUS_WORKING_DIR%
- ccache --zero-stats --max-size=%CCACHE_SIZE%
- python build_msvc\msvc-autogen.py
- - msbuild build_msvc\bitcoin.sln -property:CLToolExe=%WRAPPED_CL% -property:Configuration=Release -maxCpuCount -verbosity:minimal -noLogo
+ - msbuild build_msvc\bitcoin.sln -property:CLToolExe=%WRAPPED_CL%;UseMultiToolTask=true;Configuration=Release -maxCpuCount -verbosity:minimal -noLogo
- ccache --show-stats
check_script:
- src\test_bitcoin.exe -l test_suite
- - src\bench_bitcoin.exe --sanity-check > NUL
+ - src\bench_bitcoin.exe --sanity-check
- python test\util\test_runner.py
- python test\util\rpcauth-test.py
functional_tests_script:
# Increase the dynamic port range to the maximum allowed value to mitigate "OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted".
- # See: https://docs.microsoft.com/en-us/biztalk/technical-guides/settings-that-can-be-modified-to-improve-network-performance
+ # See: https://learn.microsoft.com/en-us/biztalk/technical-guides/settings-that-can-be-modified-to-improve-network-performance
- netsh int ipv4 set dynamicport tcp start=1025 num=64511
- netsh int ipv6 set dynamicport tcp start=1025 num=64511
# Exclude feature_dbcrash for now due to timeout
- - python test\functional\test_runner.py --nocleanup --ci --quiet --combinedlogslen=4000 --jobs=4 --timeout-factor=8 --extended --exclude feature_dbcrash
+ - python test\functional\test_runner.py --nocleanup --ci --quiet --combinedlogslen=99999999 --jobs=6 --timeout-factor=8 --extended --exclude feature_dbcrash
task:
name: 'ARM [unit tests, no functional tests] [bullseye]'
@@ -212,6 +214,8 @@ task:
<< : *GLOBAL_TASK_TEMPLATE
container:
image: quay.io/centos/centos:stream8
+ # For faster CI feedback, immediately schedule one task that runs all tests
+ << : *CREDITS_TEMPLATE
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
PACKAGE_MANAGER_INSTALL: "yum install -y"
@@ -289,52 +293,57 @@ task:
FILE_ENV: "./ci/test/00_setup_env_i686_multiprocess.sh"
task:
- name: '[no wallet, libbitcoinkernel] [bionic]'
+ name: '[no wallet, libbitcoinkernel] [buster]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:bionic
+ image: debian:buster
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh"
task:
name: 'macOS 10.15 [gui, no tests] [focal]'
- << : *BASE_TEMPLATE
+ << : *CONTAINER_DEPENDS_TEMPLATE
+ container:
+ image: ubuntu:focal
macos_sdk_cache:
folder: "depends/SDKs/$MACOS_SDK"
fingerprint_key: "$MACOS_SDK"
<< : *MAIN_TEMPLATE
- container:
- image: ubuntu:focal
env:
MACOS_SDK: "Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers"
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_mac.sh"
task:
- name: 'macOS 12 native x86_64 [gui, system sqlite] [no depends]'
+ name: 'macOS 13 native arm64 [gui, sqlite only] [no depends]'
macos_instance:
# Use latest image, but hardcode version to avoid silent upgrades (and breaks)
- image: monterey-xcode-13.3 # https://cirrus-ci.org/guide/macOS
- << : *MACOS_NATIVE_TASK_TEMPLATE
+ image: ghcr.io/cirruslabs/macos-ventura-xcode:14.1 # https://cirrus-ci.org/guide/macOS
+ << : *BASE_TEMPLATE
+ check_clang_script:
+ - clang --version
+ brew_install_script:
+ - brew install boost libevent qt@5 miniupnpc libnatpmp ccache zeromq qrencode libtool automake gnu-getopt
+ << : *MAIN_TEMPLATE
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
CI_USE_APT_INSTALL: "no"
PACKAGE_MANAGER_INSTALL: "echo" # Nothing to do
- FILE_ENV: "./ci/test/00_setup_env_mac_native_x86_64.sh"
+ FILE_ENV: "./ci/test/00_setup_env_mac_native_arm64.sh"
task:
- name: 'ARM64 Android APK [focal]'
- << : *BASE_TEMPLATE
+ name: 'ARM64 Android APK [jammy]'
+ << : *CONTAINER_DEPENDS_TEMPLATE
+ container:
+ image: ubuntu:jammy
android_sdk_cache:
folder: "depends/SDKs/android"
fingerprint_key: "ANDROID_API_LEVEL=28 ANDROID_BUILD_TOOLS_VERSION=28.0.3 ANDROID_NDK_VERSION=23.2.8568313"
depends_sources_cache:
folder: "depends/sources"
- fingerprint_script: git rev-list -1 HEAD ./depends
+ fingerprint_script: git rev-parse HEAD:depends/packages
<< : *MAIN_TEMPLATE
- container:
- image: ubuntu:focal
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_android.sh"
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index eedeeb4e54..0000000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,27 +0,0 @@
-<!-- This issue tracker is only for technical issues related to Bitcoin Core.
-
-General bitcoin questions and/or support requests are best directed to the Bitcoin StackExchange at https://bitcoin.stackexchange.com.
-
-For reporting security issues, please read instructions at https://bitcoincore.org/en/contact/.
-
-If the node is "stuck" during sync or giving "block checksum mismatch" errors, please ensure your hardware is stable by running memtest and observe CPU temperature with a load-test tool such as linpack before creating an issue!
-
-Any report, issue or feature request related to the GUI should be reported at
-https://github.com/bitcoin-core/gui/issues/
--->
-
-<!-- Describe the issue -->
-<!--- What behavior did you expect? -->
-
-<!--- What was the actual behavior (provide screenshots if the issue is GUI-related)? -->
-
-<!--- How reliably can you reproduce the issue, what are the steps to do so? -->
-
-<!-- What version of Bitcoin Core are you using, where did you get it (website, self-compiled, etc)? -->
-
-<!-- What type of machine are you observing the error on (OS/CPU and disk type)? -->
-
-<!-- GUI-related issue? What is your operating system and its version? If Linux, what is your desktop environment and graphical shell? -->
-
-<!-- Any extra information that might be useful in the debugging process. -->
-<!--- This is normally the contents of a `debug.log` or `config.log` file. Raw text or a link to a pastebin type site are preferred. -->
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
new file mode 100644
index 0000000000..83922b54cb
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -0,0 +1,93 @@
+name: Bug report
+description: Submit a new bug report.
+labels: [bug]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ ## This issue tracker is only for technical issues related to Bitcoin Core.
+
+ * General bitcoin questions and/or support requests should use Bitcoin StackExchange at https://bitcoin.stackexchange.com.
+ * For reporting security issues, please read instructions at https://bitcoincore.org/en/contact/.
+ * If the node is "stuck" during sync or giving "block checksum mismatch" errors, please ensure your hardware is stable by running `memtest` and observe CPU temperature with a load-test tool such as `linpack` before creating an issue.
+
+ ----
+ - type: checkboxes
+ attributes:
+ label: Is there an existing issue for this?
+ description: Please search to see if an issue already exists for the bug you encountered.
+ options:
+ - label: I have searched the existing issues
+ required: true
+ - type: textarea
+ id: current-behaviour
+ attributes:
+ label: Current behaviour
+ description: Tell us what went wrong
+ validations:
+ required: true
+ - type: textarea
+ id: expected-behaviour
+ attributes:
+ label: Expected behaviour
+ description: Tell us what you expected to happen
+ validations:
+ required: true
+ - type: textarea
+ id: reproduction-steps
+ attributes:
+ label: Steps to reproduce
+ description: |
+ Tell us how to reproduce your bug. Please attach related screenshots if necessary.
+ * Run-time or compile-time configuration options
+ * Actions taken
+ validations:
+ required: true
+ - type: textarea
+ id: logs
+ attributes:
+ label: Relevant log output
+ description: |
+ Please copy and paste any relevant log output or attach a debug log file.
+
+ You can find the debug.log in your [data dir.](https://github.com/bitcoin/bitcoin/blob/master/doc/files.md#data-directory-location)
+
+ Please be aware that the debug log might contain personally identifying information.
+ validations:
+ required: false
+ - type: dropdown
+ attributes:
+ label: How did you obtain Bitcoin Core
+ multiple: false
+ options:
+ - Compiled from source
+ - Pre-built binaries
+ - Package manager
+ - Other
+ validations:
+ required: true
+ - type: input
+ id: core-version
+ attributes:
+ label: What version of Bitcoin Core are you using?
+ description: Run `bitcoind --version` or in Bitcoin-QT use `Help > About Bitcoin Core`
+ placeholder: e.g. v24.0.1 or master@e1bf547
+ validations:
+ required: true
+ - type: input
+ id: os
+ attributes:
+ label: Operating system and version
+ placeholder: e.g. "MacOS Ventura 13.2" or "Ubuntu 22.04 LTS"
+ validations:
+ required: true
+ - type: textarea
+ id: machine-specs
+ attributes:
+ label: Machine specifications
+ description: |
+ What are the specifications of the host machine?
+ e.g. OS/CPU and disk type, network connectivity
+ validations:
+ required: false
+
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index fb91208954..0000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve (use this for suspected bugs only, if not sure, open a regular issue below)
-title: ''
-labels: Bug
-assignees: ''
-
----
-
-<!-- This issue tracker is only for technical issues related to Bitcoin Core.
-
-General bitcoin questions and/or support requests are best directed to the Bitcoin StackExchange at https://bitcoin.stackexchange.com.
-
-For reporting security issues, please read instructions at https://bitcoincore.org/en/contact/.
-
-If the node is "stuck" during sync or giving "block checksum mismatch" errors, please ensure your hardware is stable by running memtest and observe CPU temperature with a load-test tool such as linpack before creating an issue! -->
-
-<!-- Describe the issue -->
-
-**Expected behavior**
-
-<!--- What behavior did you expect? -->
-
-**Actual behavior**
-
-<!--- What was the actual behavior (provide screenshots if the issue is GUI-related)? -->
-
-**To reproduce**
-
-<!--- How reliably can you reproduce the issue, what are the steps to do so? -->
-
-**System information**
-
-<!-- What version of Bitcoin Core are you using, where did you get it (website, self-compiled, etc)? -->
-
-<!-- What type of machine are you observing the error on (OS/CPU and disk type)? -->
-
-<!-- GUI-related issue? What is your operating system and its version? If Linux, what is your desktop environment and graphical shell? -->
-
-<!-- Any extra information that might be useful in the debugging process. -->
-<!--- This is normally the contents of a `debug.log` or `config.log` file. Raw text or a link to a pastebin type site are preferred. -->
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..40370284a6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: true
+contact_links:
+ - name: Bitcoin Core Security Policy
+ url: https://github.com/bitcoin/bitcoin/blob/master/SECURITY.md
+ about: View security policy
+ - name: Bitcoin Core Developers
+ url: https://bitcoincore.org
+ about: Bitcoin Core homepage
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 2d5685185e..0000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: Feature
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
-
-**Describe the solution you'd like**
-<!-- A clear and concise description of what you want to happen. -->
-
-**Describe alternatives you've considered**
-<!-- A clear and concise description of any alternative solutions or features you've considered. -->
-
-**Additional context**
-<!-- Add any other context or screenshots about the feature request here. -->
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000000..4622fd9819
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,36 @@
+name: Feature Request
+description: Suggest an idea for this project.
+labels: [Feature]
+body:
+ - type: textarea
+ id: feature
+ attributes:
+ label: Please describe the feature you'd like to see added.
+ description: Attach screenshots or logs if applicable.
+ validations:
+ required: true
+ - type: textarea
+ id: related-problem
+ attributes:
+ label: Is your feature related to a problem, if so please describe it.
+ description: Attach screenshots or logs if applicable.
+ validations:
+ required: false
+ - type: textarea
+ id: solution
+ attributes:
+ label: Describe the solution you'd like
+ validations:
+ required: false
+ - type: textarea
+ id: alternatives
+ attributes:
+ label: Describe any alternatives you've considered
+ validations:
+ required: false
+ - type: textarea
+ id: additional-context
+ attributes:
+ label: Please leave any additional context
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/good_first_issue.md b/.github/ISSUE_TEMPLATE/good_first_issue.md
deleted file mode 100644
index d32e22d360..0000000000
--- a/.github/ISSUE_TEMPLATE/good_first_issue.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-name: Good first issue
-about: '(Regular devs only): Suggest a new good first issue'
-title: ''
-labels: ''
-assignees: ''
-
----
-
-<!-- Needs the label "good first issue" assigned manually before or after opening -->
-
-<!-- A good first issue is an uncontroversial issue, that has a relatively unique and obvious solution -->
-
-<!-- Motivate the issue and explain the solution briefly -->
-
-#### Useful skills:
-
-<!-- (For example, “C++11 std::threadâ€, “Qt5 GUI and async GUI design†or “basic understanding of Bitcoin mining and the Bitcoin Core RPC interfaceâ€.) -->
-
-#### Want to work on this issue?
-
-For guidance on contributing, please read [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md) before opening your pull request.
diff --git a/.github/ISSUE_TEMPLATE/good_first_issue.yml b/.github/ISSUE_TEMPLATE/good_first_issue.yml
new file mode 100644
index 0000000000..c40dad9687
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/good_first_issue.yml
@@ -0,0 +1,42 @@
+name: Good First Issue
+description: (Regular devs only) Suggest a new good first issue
+labels: [good first issue]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Please add the label "good first issue" manually before or after opening
+
+ A good first issue is an uncontroversial issue, that has a relatively unique and obvious solution
+
+ Motivate the issue and explain the solution briefly
+ - type: textarea
+ id: motivation
+ attributes:
+ label: Motivation
+ description: Motivate the issue
+ validations:
+ required: true
+ - type: textarea
+ id: solution
+ attributes:
+ label: Possible solution
+ description: Describe a possible solution
+ validations:
+ required: false
+ - type: textarea
+ id: useful-skills
+ attributes:
+ label: Useful Skills
+ description: For example, “`std::thread`â€, “Qt5 GUI and async GUI design†or “basic understanding of Bitcoin mining and the Bitcoin Core RPC interfaceâ€.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Guidance for new contributors
+ description: Please leave this to automatically add the footer for new contributors
+ value: |
+ Want to work on this issue?
+
+ For guidance on contributing, please read [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md) before opening your pull request.
+
diff --git a/.github/ISSUE_TEMPLATE/gui_issue.md b/.github/ISSUE_TEMPLATE/gui_issue.md
deleted file mode 100644
index 37acc81e21..0000000000
--- a/.github/ISSUE_TEMPLATE/gui_issue.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-name: An issue or feature request related to the GUI
-about: Any report, issue or feature request related to the GUI should be reported at https://github.com/bitcoin-core/gui/issues/
-title: Any report, issue or feature request related to the GUI should be reported at https://github.com/bitcoin-core/gui/issues/
-labels: GUI
-assignees: ''
-
----
-
-Any report, issue or feature request related to the GUI should be reported at
-https://github.com/bitcoin-core/gui/issues/
diff --git a/.github/ISSUE_TEMPLATE/gui_issue.yml b/.github/ISSUE_TEMPLATE/gui_issue.yml
new file mode 100644
index 0000000000..4fe578e9b5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/gui_issue.yml
@@ -0,0 +1,18 @@
+name: Issue or feature request related to the GUI
+description: Any report, issue or feature request related to the GUI
+labels: [GUI]
+body:
+- type: checkboxes
+ id: acknowledgement
+ attributes:
+ label: Issues, reports or feature requests related to the GUI should be opened directly on the GUI repo
+ description: https://github.com/bitcoin-core/gui/issues/
+ options:
+ - label: I still think this issue should be opened here
+ required: true
+- type: textarea
+ id: gui-request
+ attributes:
+ label: Report
+ validations:
+ required: true
diff --git a/.python-version b/.python-version
index 8b7b0b52e5..36f601f10e 100644
--- a/.python-version
+++ b/.python-version
@@ -1 +1 @@
-3.6.12
+3.7.16
diff --git a/.tx/config b/.tx/config
index 37c0bca0ab..ab1fb933d8 100644
--- a/.tx/config
+++ b/.tx/config
@@ -1,7 +1,7 @@
[main]
host = https://www.transifex.com
-[bitcoin.qt-translation-024x]
+[o:bitcoin:p:bitcoin:r:qt-translation-025x]
file_filter = src/qt/locale/bitcoin_<lang>.xlf
source_file = src/qt/locale/bitcoin_en.xlf
source_lang = en
diff --git a/COPYING b/COPYING
index b157c5fe49..2f7add71ac 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
The MIT License (MIT)
-Copyright (c) 2009-2022 The Bitcoin Core developers
-Copyright (c) 2009-2022 Bitcoin Developers
+Copyright (c) 2009-2023 The Bitcoin Core developers
+Copyright (c) 2009-2023 Bitcoin Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/REVIEWERS b/REVIEWERS
deleted file mode 100644
index cb1bafa496..0000000000
--- a/REVIEWERS
+++ /dev/null
@@ -1,17 +0,0 @@
-# ==============================================================================
-# Bitcoin Core REVIEWERS
-# ==============================================================================
-
-# Configuration of automated review requests for the bitcoin/bitcoin repo
-# via DrahtBot.
-
-# Order is not important; if a modified file or directory matches a fnmatch,
-# the reviewer will be mentioned in a PR comment requesting a review.
-
-# Regular contributors are free to add their names to specific directories or
-# files provided that they are willing to provide a review.
-
-# Absence from this list should not be interpreted as a discouragement to
-# review a pull request. Peer review is always welcome and is a critical
-# component of the progress of the codebase. Information on peer review
-# guidelines can be found in the CONTRIBUTING.md doc.
diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4
index 6c944b160f..f6620882a2 100644
--- a/build-aux/m4/ax_boost_base.m4
+++ b/build-aux/m4/ax_boost_base.m4
@@ -8,7 +8,7 @@
#
# DESCRIPTION
#
-# Test for the Boost C++ libraries of a particular version (or newer)
+# Test for the Boost C++ headers of a particular version (or newer)
#
# If no path to the installed boost library is given the macro searchs
# under /usr, /usr/local, /opt, /opt/local and /opt/homebrew and evaluates
@@ -17,12 +17,14 @@
#
# This macro calls:
#
-# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
+# AC_SUBST(BOOST_CPPFLAGS)
#
# And sets:
#
# HAVE_BOOST
#
+# Note that this macro has been modified compared to upstream.
+#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
@@ -59,26 +61,10 @@ AC_ARG_WITH([boost],
],
[want_boost="yes"])
-
-AC_ARG_WITH([boost-libdir],
- [AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
- [Force given directory for boost libraries.
- Note that this will override library path detection,
- so use this parameter only if default library detection fails
- and you know exactly where your boost libraries are located.])],
- [
- AS_IF([test -d "$withval"],
- [_AX_BOOST_BASE_boost_lib_path="$withval"],
- [AC_MSG_ERROR([--with-boost-libdir expected directory name])])
- ],
- [_AX_BOOST_BASE_boost_lib_path=""])
-
-BOOST_LDFLAGS=""
BOOST_CPPFLAGS=""
AS_IF([test "x$want_boost" = "xyes"],
[_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])])
AC_SUBST(BOOST_CPPFLAGS)
-AC_SUBST(BOOST_LDFLAGS)
])
@@ -139,7 +125,6 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"])
AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[
AC_MSG_RESULT([yes])
- BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp";
break;
],
[AC_MSG_RESULT([no])])
@@ -156,27 +141,17 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
for libsubdir in $search_libsubdirs ; do
if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
- BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir"
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include"
break;
fi
done
])
- dnl overwrite ld flags if we have required special directory with
- dnl --with-boost-libdir parameter
- AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"],
- [BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"])
-
- AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)])
+ AC_MSG_CHECKING([for Boost headers >= $1 ($WANT_BOOST_VERSION)])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
- LDFLAGS_SAVED="$LDFLAGS"
- LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
- export LDFLAGS
-
AC_REQUIRE([AC_PROG_CXX])
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
@@ -193,11 +168,8 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
dnl built and installed without the --layout=system option or for a staged(not installed) version
if test "x$succeeded" != "xyes" ; then
CPPFLAGS="$CPPFLAGS_SAVED"
- LDFLAGS="$LDFLAGS_SAVED"
BOOST_CPPFLAGS=
- if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
- BOOST_LDFLAGS=
- fi
+
_version=0
if test -n "$_AX_BOOST_BASE_boost_path" ; then
if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then
@@ -216,14 +188,6 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path"
fi
fi
- dnl if we found something and BOOST_LDFLAGS was unset before
- dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here.
- if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then
- for libsubdir in $libsubdirs ; do
- if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
- done
- BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir"
- fi
fi
else
if test "x$cross_compiling" != "xyes" ; then
@@ -242,12 +206,6 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
- if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
- for libsubdir in $libsubdirs ; do
- if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
- done
- BOOST_LDFLAGS="-L$best_path/$libsubdir"
- fi
fi
if test -n "$BOOST_ROOT" ; then
@@ -259,10 +217,9 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
V_CHECK=`expr $stage_version_shorten \>\= $_version`
- if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
+ if test "x$V_CHECK" = "x1" ; then
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
BOOST_CPPFLAGS="-I$BOOST_ROOT"
- BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
fi
fi
fi
@@ -270,8 +227,6 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
- LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
- export LDFLAGS
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
@@ -298,6 +253,4 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
fi
CPPFLAGS="$CPPFLAGS_SAVED"
- LDFLAGS="$LDFLAGS_SAVED"
-
])
diff --git a/build_msvc/README.md b/build_msvc/README.md
index b9bebd369c..ba6171fee7 100644
--- a/build_msvc/README.md
+++ b/build_msvc/README.md
@@ -7,7 +7,9 @@ Visual Studio 2022 is minimum required to build Bitcoin Core.
Solution and project files to build with `msbuild` or Visual Studio can be found in the `build_msvc` directory.
-To build Bitcoin Core from the command-line, it is sufficient to only install the Visual Studio Build Tools component.
+To build Bitcoin Core from the command-line, it is sufficient to only install the [Visual Studio Build Tools](https://visualstudio.microsoft.com/downloads/) component.
+
+The "Desktop development with C++" workload must be installed as well.
Building with Visual Studio is an alternative to the Linux based [cross-compiler build](../doc/build-windows.md).
@@ -15,7 +17,7 @@ Building with Visual Studio is an alternative to the Linux based [cross-compiler
Prerequisites
---------------------
To build [dependencies](../doc/dependencies.md) (except for [Qt](#qt)),
-the default approach is to use the [vcpkg](https://docs.microsoft.com/en-us/cpp/vcpkg) package manager from Microsoft:
+the default approach is to use the [vcpkg](https://vcpkg.io) package manager from Microsoft:
1. [Install](https://vcpkg.io/en/getting-started.html) vcpkg.
@@ -67,7 +69,7 @@ Alternatively, open the `build_msvc/bitcoin.sln` file in Visual Studio.
Security
---------------------
-[Base address randomization](https://docs.microsoft.com/en-us/cpp/build/reference/dynamicbase-use-address-space-layout-randomization?view=msvc-160) is used to make Bitcoin Core more secure. When building Bitcoin using the `build_msvc` process base address randomization can be disabled by editing `common.init.vcproj` to change `RandomizedBaseAddress` from `true` to `false` and then rebuilding the project.
+[Base address randomization](https://learn.microsoft.com/en-us/cpp/build/reference/dynamicbase-use-address-space-layout-randomization) is used to make Bitcoin Core more secure. When building Bitcoin using the `build_msvc` process base address randomization can be disabled by editing `common.init.vcproj` to change `RandomizedBaseAddress` from `true` to `false` and then rebuilding the project.
To check if `bitcoind` has `RandomizedBaseAddress` enabled or disabled run
diff --git a/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj b/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj
index e5e0e978f8..738884fb41 100644
--- a/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj
+++ b/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj
@@ -15,6 +15,9 @@
<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>
diff --git a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
index b47d62b295..482e4333f7 100644
--- a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
+++ b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
@@ -8,6 +8,7 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<ItemGroup>
+ <ClCompile Include="..\..\src\common\url.cpp" />
@SOURCE_FILES@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
diff --git a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in b/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in
index 6ec40461c2..adf4fa0354 100644
--- a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in
+++ b/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in
@@ -8,7 +8,6 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<ItemGroup>
- <ClCompile Include="..\..\src\util\url.cpp" />
@SOURCE_FILES@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
diff --git a/build_msvc/libleveldb/libleveldb.vcxproj b/build_msvc/libleveldb/libleveldb.vcxproj
index 009be30dec..2914eb2cfb 100644
--- a/build_msvc/libleveldb/libleveldb.vcxproj
+++ b/build_msvc/libleveldb/libleveldb.vcxproj
@@ -50,7 +50,7 @@
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
- <PreprocessorDefinitions>HAVE_CRC32C=0;HAVE_SNAPPY=0;__STDC_LIMIT_MACROS;LEVELDB_IS_BIG_ENDIAN=0;_UNICODE;UNICODE;_CRT_NONSTDC_NO_DEPRECATE;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>HAVE_CRC32C=0;HAVE_SNAPPY=0;LEVELDB_IS_BIG_ENDIAN=0;_UNICODE;UNICODE;_CRT_NONSTDC_NO_DEPRECATE;LEVELDB_PLATFORM_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4244;4267</DisableSpecificWarnings>
<AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
diff --git a/build_msvc/libsecp256k1/libsecp256k1.vcxproj b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
index 16ee32d87e..0b90f341a7 100644
--- a/build_msvc/libsecp256k1/libsecp256k1.vcxproj
+++ b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
@@ -14,7 +14,7 @@
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
- <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4146;4244;4267;4334</DisableSpecificWarnings>
</ClCompile>
diff --git a/build_msvc/msvc-autogen.py b/build_msvc/msvc-autogen.py
index ae48a52a2f..e02e3abdfa 100755
--- a/build_msvc/msvc-autogen.py
+++ b/build_msvc/msvc-autogen.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj b/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
index ec572b4f2e..3a2540d549 100644
--- a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
+++ b/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
@@ -54,6 +54,9 @@
<ProjectReference Include="..\libbitcoin_zmq\libbitcoin_zmq.vcxproj">
<Project>{792d487f-f14c-49fc-a9de-3fc150f31c3f}</Project>
</ProjectReference>
+ <ProjectReference Include="..\libtest_util\libtest_util.vcxproj">
+ <Project>{1e065f03-3566-47d0-8fa9-daa72b084e7d}</Project>
+ </ProjectReference>
<ProjectReference Include="..\libleveldb\libleveldb.vcxproj">
<Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project>
</ProjectReference>
diff --git a/ci/README.md b/ci/README.md
index 3c5f04c39e..de798607df 100644
--- a/ci/README.md
+++ b/ci/README.md
@@ -8,8 +8,7 @@ Be aware that the tests will be built and run in-place, so please run at your ow
If the repository is not a fresh git clone, you might have to clean files from previous builds or test runs first.
The ci needs to perform various sysadmin tasks such as installing packages or writing to the user's home directory.
-While most of the actions are done inside a docker container, this is not possible for all. Thus, cache directories,
-such as the depends cache, previous release binaries, or ccache, are mounted as read-write into the docker container. While it should be fine to run
+While it should be fine to run
the ci system locally on you development box, the ci scripts can generally be assumed to have received less review and
testing compared to other parts of the codebase. If you want to keep the work tree clean, you might want to run the ci
system in a virtual machine with a Linux operating system of your choice.
diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh
index 6f9a4709dd..f7147582dc 100755
--- a/ci/lint/04_install.sh
+++ b/ci/lint/04_install.sh
@@ -1,27 +1,45 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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
${CI_RETRY_EXE} apt-get update
-${CI_RETRY_EXE} apt-get install -y python3-pip curl git gawk jq
-(
- # Temporary workaround for https://github.com/bitcoin/bitcoin/pull/26130#issuecomment-1260499544
- # Can be removed once the underlying image is bumped to something that includes git2.34 or later
- sed -i -e 's/bionic/jammy/g' /etc/apt/sources.list
- ${CI_RETRY_EXE} apt-get update
- ${CI_RETRY_EXE} apt-get install -y --reinstall git
-)
+# Lint dependencies:
+# - curl/xz-utils (to install shellcheck)
+# - git (used in many lint scripts)
+# - gpg (used by verify-commits)
+${CI_RETRY_EXE} apt-get install -y curl xz-utils git gpg
+
+if [ -z "${SKIP_PYTHON_INSTALL}" ]; then
+ PYTHON_PATH=/tmp/python
+ if [ ! -d "${PYTHON_PATH}/bin" ]; then
+ (
+ git clone https://github.com/pyenv/pyenv.git
+ cd pyenv/plugins/python-build || exit 1
+ ./install.sh
+ )
+ # For dependencies see https://github.com/pyenv/pyenv/wiki#suggested-build-environment
+ ${CI_RETRY_EXE} apt-get install -y build-essential libssl-dev zlib1g-dev \
+ libbz2-dev libreadline-dev libsqlite3-dev curl llvm \
+ libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \
+ clang
+ env CC=clang python-build "$(cat "${BASE_ROOT_DIR}/.python-version")" "${PYTHON_PATH}"
+ fi
+ export PATH="${PYTHON_PATH}/bin:${PATH}"
+ command -v python3
+ python3 --version
+fi
${CI_RETRY_EXE} pip3 install codespell==2.2.1
-${CI_RETRY_EXE} pip3 install flake8==4.0.1
-${CI_RETRY_EXE} pip3 install mypy==0.942
-${CI_RETRY_EXE} pip3 install pyzmq==22.3.0
-${CI_RETRY_EXE} pip3 install vulture==2.3
+${CI_RETRY_EXE} pip3 install flake8==5.0.4
+${CI_RETRY_EXE} pip3 install mypy==0.971
+${CI_RETRY_EXE} pip3 install pyzmq==24.0.1
+${CI_RETRY_EXE} pip3 install vulture==2.6
SHELLCHECK_VERSION=v0.8.0
-curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/
-export PATH="/tmp/shellcheck-${SHELLCHECK_VERSION}:${PATH}"
+curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | \
+ tar --xz -xf - --directory /tmp/
+mv "/tmp/shellcheck-${SHELLCHECK_VERSION}/shellcheck" /usr/bin/
diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh
index 4506848740..fa28f6126c 100755
--- a/ci/lint/06_script.sh
+++ b/ci/lint/06_script.sh
@@ -1,15 +1,23 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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
-GIT_HEAD=$(git rev-parse HEAD)
-if [ -n "$CIRRUS_PR" ]; then
- COMMIT_RANGE="${CIRRUS_BASE_SHA}..$GIT_HEAD"
+if [ -n "$LOCAL_BRANCH" ]; then
+ # To faithfully recreate CI linting locally, specify all commits on the current
+ # branch.
+ COMMIT_RANGE="$(git merge-base HEAD master)..HEAD"
+elif [ -n "$CIRRUS_PR" ]; then
+ COMMIT_RANGE="HEAD~..HEAD"
+ echo
+ git log --no-merges --oneline "$COMMIT_RANGE"
+ echo
test/lint/commit-script-check.sh "$COMMIT_RANGE"
+else
+ COMMIT_RANGE="SKIP_EMPTY_NOT_A_PR"
fi
export COMMIT_RANGE
@@ -36,8 +44,3 @@ if [ "$CIRRUS_REPO_FULL_NAME" = "bitcoin/bitcoin" ] && [ "$CIRRUS_PR" = "" ] ; t
${CI_RETRY_EXE} gpg --keyserver hkps://keys.openpgp.org --recv-keys "${KEYS[@]}" &&
./contrib/verify-commits/verify-commits.py;
fi
-
-if [ -n "$COMMIT_RANGE" ]; then
- echo
- git log --no-merges --oneline "$COMMIT_RANGE"
-fi
diff --git a/ci/lint/Dockerfile b/ci/lint/Dockerfile
new file mode 100644
index 0000000000..03c20c7286
--- /dev/null
+++ b/ci/lint/Dockerfile
@@ -0,0 +1,29 @@
+# See test/lint/README.md for usage.
+#
+# This container basically has to live in this directory in order to pull in the CI
+# install scripts. If it lived in the root directory, it would have to pull in the
+# entire repo as docker context during build; if it lived elsewhere, it wouldn't be
+# able to make back-references to pull in the install scripts. So here it lives.
+
+FROM python:3.7-buster
+
+ENV DEBIAN_FRONTEND=noninteractive
+ENV LC_ALL=C.UTF-8
+
+# This is used by the 04_install.sh script; we can't read the Python version from
+# .python-version for the same reasons as above, and it's more efficient to pull a
+# preexisting Python image than it is to build from source.
+ENV SKIP_PYTHON_INSTALL=1
+
+# Must be built from ./ci/lint/ for these paths to work.
+COPY ./docker-entrypoint.sh /entrypoint.sh
+COPY ./04_install.sh /install.sh
+
+RUN /install.sh && \
+ echo 'alias lint="./ci/lint/06_script.sh"' >> ~/.bashrc && \
+ chmod 755 /entrypoint.sh && \
+ rm -rf /var/lib/apt/lists/*
+
+
+WORKDIR /bitcoin
+ENTRYPOINT ["/entrypoint.sh"]
diff --git a/ci/lint/docker-entrypoint.sh b/ci/lint/docker-entrypoint.sh
new file mode 100755
index 0000000000..3fdbbb0761
--- /dev/null
+++ b/ci/lint/docker-entrypoint.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+export LC_ALL=C
+
+# Fixes permission issues when there is a container UID/GID mismatch with the owner
+# of the mounted bitcoin src dir.
+git config --global --add safe.directory /bitcoin
+
+if [ -z "$1" ]; then
+ LOCAL_BRANCH=1 bash -ic "./ci/lint/06_script.sh"
+else
+ exec "$@"
+fi
diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh
index 5a150d5f80..e6905b6dbe 100755
--- a/ci/test/00_setup_env.sh
+++ b/ci/test/00_setup_env.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,11 +8,10 @@ export LC_ALL=C.UTF-8
# The root dir.
# The ci system copies this folder.
-# This is where the depends build is done.
BASE_ROOT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../../ >/dev/null 2>&1 && pwd )
export BASE_ROOT_DIR
# The depends dir.
-# This folder exists on the ci host and ci guest. Changes are propagated back and forth.
+# This folder exists only on the ci guest, and on the ci host as a volume.
export DEPENDS_DIR=${DEPENDS_DIR:-$BASE_ROOT_DIR/depends}
# A folder for the ci system to put temporary files (ccache, datadirs for tests, ...)
# This folder only exists on the ci host.
@@ -45,10 +44,9 @@ export RUN_SECURITY_TESTS=${RUN_SECURITY_TESTS:-false}
export TEST_RUNNER_TIMEOUT_FACTOR=${TEST_RUNNER_TIMEOUT_FACTOR:-40}
export TEST_RUNNER_ENV=${TEST_RUNNER_ENV:-}
export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false}
-export EXPECTED_TESTS_DURATION_IN_SECONDS=${EXPECTED_TESTS_DURATION_IN_SECONDS:-1000}
export CONTAINER_NAME=${CONTAINER_NAME:-ci_unnamed}
-export DOCKER_NAME_TAG=${DOCKER_NAME_TAG:-ubuntu:20.04}
+export CI_IMAGE_NAME_TAG=${CI_IMAGE_NAME_TAG:-ubuntu:20.04}
# Randomize test order.
# See https://www.boost.org/doc/libs/1_71_0/libs/test/doc/html/boost_test/utf_reference/rt_param_reference/random.html
export BOOST_TEST_RANDOM=${BOOST_TEST_RANDOM:-1}
@@ -58,15 +56,17 @@ export CCACHE_SIZE=${CCACHE_SIZE:-100M}
export CCACHE_TEMPDIR=${CCACHE_TEMPDIR:-/tmp/.ccache-temp}
export CCACHE_COMPRESS=${CCACHE_COMPRESS:-1}
# The cache dir.
-# This folder exists on the ci host and ci guest. Changes are propagated back and forth.
+# This folder exists only on the ci guest, and on the ci host as a volume.
export CCACHE_DIR=${CCACHE_DIR:-$BASE_SCRATCH_DIR/.ccache}
# Folder where the build result is put (bin and lib).
export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out/$HOST}
# Folder where the build is done (dist and out-of-tree build).
export BASE_BUILD_DIR=${BASE_BUILD_DIR:-$BASE_SCRATCH_DIR/build}
+# The folder for previous release binaries.
+# This folder exists only on the ci guest, and on the ci host as a volume.
export PREVIOUS_RELEASES_DIR=${PREVIOUS_RELEASES_DIR:-$BASE_ROOT_DIR/releases/$HOST}
export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks}
-export DOCKER_PACKAGES=${DOCKER_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps bison}
+export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps bison}
export GOAL=${GOAL:-install}
export DIR_QA_ASSETS=${DIR_QA_ASSETS:-${BASE_SCRATCH_DIR}/qa-assets}
export PATH=${BASE_ROOT_DIR}/ci/retry:$PATH
diff --git a/ci/test/00_setup_env_android.sh b/ci/test/00_setup_env_android.sh
index 6732db36ad..1834bd0bc4 100755
--- a/ci/test/00_setup_env_android.sh
+++ b/ci/test/00_setup_env_android.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8
export HOST=aarch64-linux-android
export PACKAGES="unzip openjdk-8-jdk gradle"
export CONTAINER_NAME=ci_android
-export DOCKER_NAME_TAG="ubuntu:focal"
+export CI_IMAGE_NAME_TAG="ubuntu:jammy"
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh
index 932be4b43d..ac0c0be96a 100755
--- a/ci/test/00_setup_env_arm.sh
+++ b/ci/test/00_setup_env_arm.sh
@@ -18,7 +18,7 @@ if [ -n "$QEMU_USER_CMD" ]; then
fi
export CONTAINER_NAME=ci_arm_linux
# Use debian to avoid 404 apt errors when cross compiling
-export DOCKER_NAME_TAG="debian:bullseye"
+export CI_IMAGE_NAME_TAG="debian:bullseye"
export USE_BUSY_BOX=true
export RUN_UNIT_TESTS=true
export RUN_FUNCTIONAL_TESTS=false
diff --git a/ci/test/00_setup_env_i686_centos.sh b/ci/test/00_setup_env_i686_centos.sh
index 1ce3261f44..8a931d44e5 100755
--- a/ci/test/00_setup_env_i686_centos.sh
+++ b/ci/test/00_setup_env_i686_centos.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,10 +8,11 @@ export LC_ALL=C.UTF-8
export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_centos
-export DOCKER_NAME_TAG=quay.io/centos/centos:stream8
-export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison"
+export CI_IMAGE_NAME_TAG=quay.io/centos/centos:stream8
+export CI_BASE_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python38 python38-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison"
export PIP_PACKAGES="pyzmq"
export GOAL="install"
+export NO_WERROR=1 # GCC 8
export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports"
export CONFIG_SHELL="/bin/dash"
export TEST_RUNNER_ENV="LC_ALL=en_US.UTF-8"
diff --git a/ci/test/00_setup_env_i686_multiprocess.sh b/ci/test/00_setup_env_i686_multiprocess.sh
index 76de87d955..9e3ea0d383 100755
--- a/ci/test/00_setup_env_i686_multiprocess.sh
+++ b/ci/test/00_setup_env_i686_multiprocess.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_multiprocess
-export DOCKER_NAME_TAG=ubuntu:20.04
+export CI_IMAGE_NAME_TAG=ubuntu:20.04
export PACKAGES="cmake python3 llvm clang g++-multilib"
export DEP_OPTS="DEBUG=1 MULTIPROCESS=1"
export GOAL="install"
diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh
index c4f22c8f9e..fe42871c31 100755
--- a/ci/test/00_setup_env_mac.sh
+++ b/ci/test/00_setup_env_mac.sh
@@ -7,7 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_macos_cross
-export DOCKER_NAME_TAG=ubuntu:20.04 # Check that Focal can cross-compile to macos
+export CI_IMAGE_NAME_TAG=ubuntu:20.04 # Check that Focal can cross-compile to macos
export HOST=x86_64-apple-darwin
export PACKAGES="cmake libz-dev libtinfo5 python3-setuptools xorriso"
export XCODE_VERSION=12.2
diff --git a/ci/test/00_setup_env_mac_native_x86_64.sh b/ci/test/00_setup_env_mac_native_arm64.sh
index d176296e76..a6799d7b88 100755
--- a/ci/test/00_setup_env_mac_native_x86_64.sh
+++ b/ci/test/00_setup_env_mac_native_arm64.sh
@@ -1,17 +1,16 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
-export HOST=x86_64-apple-darwin
-export PIP_PACKAGES="zmq lief"
+export HOST=arm64-apple-darwin
+export PIP_PACKAGES="zmq"
export GOAL="install"
-export BITCOIN_CONFIG="--with-gui --enable-reduce-exports"
+export BITCOIN_CONFIG="--with-gui --with-miniupnpc --with-natpmp --enable-reduce-exports"
export CI_OS_NAME="macos"
export NO_DEPENDS=1
export OSX_SDK=""
export CCACHE_SIZE=300M
-export RUN_SECURITY_TESTS="true"
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index 4f1792a9f0..bb3f6997f3 100755
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -1,19 +1,26 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
-# We install an up-to-date 'bpfcc-tools' package from an untrusted PPA.
-# This can be dropped with the next Ubuntu or Debian release that includes up-to-date packages.
-# See the if-then in ci/test/04_install.sh too.
-export ADD_UNTRUSTED_BPFCC_PPA=true
+# Only install BCC tracing packages in Cirrus CI.
+if [[ "${CIRRUS_CI}" == "true" ]]; then
+ # We install an up-to-date 'bpfcc-tools' package from an untrusted PPA.
+ # This can be dropped with the next Ubuntu or Debian release that includes up-to-date packages.
+ # See the if-then in ci/test/04_install.sh too.
+ export ADD_UNTRUSTED_BPFCC_PPA=true
+ export BPFCC_PACKAGE="bpfcc-tools"
+else
+ export ADD_UNTRUSTED_BPFCC_PPA=false
+ export BPFCC_PACKAGE=""
+fi
export CONTAINER_NAME=ci_native_asan
-export PACKAGES="systemtap-sdt-dev bpfcc-tools clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
-export DOCKER_NAME_TAG=ubuntu:22.04 # May not run in docker unless --enable-usdt is dropped
+export PACKAGES="systemtap-sdt-dev clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}"
+export CI_IMAGE_NAME_TAG=ubuntu:22.04
export NO_DEPENDS=1
export GOAL="install"
-export BITCOIN_CONFIG="--enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
+export BITCOIN_CONFIG="--enable-c++20 --enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh
index d7caec8359..a2d393bb5a 100755
--- a/ci/test/00_setup_env_native_fuzz.sh
+++ b/ci/test/00_setup_env_native_fuzz.sh
@@ -1,12 +1,12 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
-export DOCKER_NAME_TAG="ubuntu:22.04"
+export CI_IMAGE_NAME_TAG="ubuntu:22.04"
export CONTAINER_NAME=ci_native_fuzz
export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libsqlite3-dev"
export NO_DEPENDS=1
diff --git a/ci/test/00_setup_env_native_fuzz_with_msan.sh b/ci/test/00_setup_env_native_fuzz_with_msan.sh
index 071bac8fb3..7886f6efc9 100755
--- a/ci/test/00_setup_env_native_fuzz_with_msan.sh
+++ b/ci/test/00_setup_env_native_fuzz_with_msan.sh
@@ -1,23 +1,23 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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
-export DOCKER_NAME_TAG="ubuntu:20.04"
+export CI_IMAGE_NAME_TAG="ubuntu:20.04"
LIBCXX_DIR="${BASE_SCRATCH_DIR}/msan/build/"
export MSAN_FLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O1 -fno-optimize-sibling-calls"
LIBCXX_FLAGS="-nostdinc++ -stdlib=libc++ -L${LIBCXX_DIR}lib -lc++abi -I${LIBCXX_DIR}include -I${LIBCXX_DIR}include/c++/v1 -lpthread -Wl,-rpath,${LIBCXX_DIR}lib -Wno-unused-command-line-argument"
export MSAN_AND_LIBCXX_FLAGS="${MSAN_FLAGS} ${LIBCXX_FLAGS}"
-export CONTAINER_NAME="ci_native_msan"
+export CONTAINER_NAME="ci_native_fuzz_msan"
export PACKAGES="clang-12 llvm-12 cmake"
# BDB generates false-positives and will be removed in future
-export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}' libevent_cflags='${MSAN_FLAGS}' sqlite_cflags='${MSAN_FLAGS}' zeromq_cxxflags='-std=c++17 ${MSAN_AND_LIBCXX_FLAGS}'"
+export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export GOAL="install"
-export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory --disable-hardening --with-asm=no --prefix=${DEPENDS_DIR}/x86_64-pc-linux-gnu/ CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
+export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory --disable-hardening --with-asm=no CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export USE_MEMORY_SANITIZER="true"
export RUN_UNIT_TESTS="false"
export RUN_FUNCTIONAL_TESTS="false"
diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
index 97c530e19e..75c10046b7 100755
--- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
+++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
@@ -1,12 +1,12 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
-export DOCKER_NAME_TAG="ubuntu:22.04"
+export CI_IMAGE_NAME_TAG="ubuntu:22.04"
export CONTAINER_NAME=ci_native_fuzz_valgrind
export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libsqlite3-dev valgrind"
export NO_DEPENDS=1
diff --git a/ci/test/00_setup_env_native_msan.sh b/ci/test/00_setup_env_native_msan.sh
index 34a792ec8f..1f9209bafb 100755
--- a/ci/test/00_setup_env_native_msan.sh
+++ b/ci/test/00_setup_env_native_msan.sh
@@ -1,12 +1,12 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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
-export DOCKER_NAME_TAG="ubuntu:20.04"
+export CI_IMAGE_NAME_TAG="ubuntu:20.04"
LIBCXX_DIR="${BASE_SCRATCH_DIR}/msan/build/"
export MSAN_FLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O1 -fno-optimize-sibling-calls"
LIBCXX_FLAGS="-nostdinc++ -stdlib=libc++ -L${LIBCXX_DIR}lib -lc++abi -I${LIBCXX_DIR}include -I${LIBCXX_DIR}include/c++/v1 -lpthread -Wl,-rpath,${LIBCXX_DIR}lib -Wno-unused-command-line-argument"
@@ -15,9 +15,9 @@ export MSAN_AND_LIBCXX_FLAGS="${MSAN_FLAGS} ${LIBCXX_FLAGS}"
export CONTAINER_NAME="ci_native_msan"
export PACKAGES="clang-12 llvm-12 cmake"
# BDB generates false-positives and will be removed in future
-export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}' libevent_cflags='${MSAN_FLAGS}' sqlite_cflags='${MSAN_FLAGS}' zeromq_cxxflags='-std=c++17 ${MSAN_AND_LIBCXX_FLAGS}'"
+export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export GOAL="install"
-export BITCOIN_CONFIG="--with-sanitizers=memory --disable-hardening --with-asm=no --prefix=${DEPENDS_DIR}/x86_64-pc-linux-gnu/ CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
+export BITCOIN_CONFIG="--with-sanitizers=memory --disable-hardening --with-asm=no CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export USE_MEMORY_SANITIZER="true"
export RUN_FUNCTIONAL_TESTS="false"
export CCACHE_SIZE=250M
diff --git a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh
index 63560a5f5c..06bc2401c5 100755
--- a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh
+++ b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh
@@ -1,14 +1,17 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
export CONTAINER_NAME=ci_native_nowallet_libbitcoinkernel
-export DOCKER_NAME_TAG=ubuntu:18.04 # Use bionic to have one config run the tests in python3.6, see doc/dependencies.md
-export PACKAGES="python3-zmq clang-8 llvm-8 libc++abi-8-dev libc++-8-dev" # Use clang-8 to test C++17 compatibility, see doc/dependencies.md
+export CI_IMAGE_NAME_TAG=debian:buster
+# Use minimum supported python3.7 and clang-8, see doc/dependencies.md
+export PACKAGES="-t buster-backports python3-zmq clang-8 llvm-8 libc++abi-8-dev libc++-8-dev"
+export APPEND_APT_SOURCES_LIST="deb http://deb.debian.org/debian buster-backports main"
export DEP_OPTS="NO_WALLET=1 CC=clang-8 CXX='clang++-8 -stdlib=libc++'"
export GOAL="install"
+export NO_WERROR=1
export BITCOIN_CONFIG="--enable-reduce-exports CC=clang-8 CXX='clang++-8 -stdlib=libc++' --enable-experimental-util-chainstate --with-experimental-kernel-lib --enable-shared"
diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh
index 8a6ea62d5c..5cc0addd33 100755
--- a/ci/test/00_setup_env_native_qt5.sh
+++ b/ci/test/00_setup_env_native_qt5.sh
@@ -1,19 +1,21 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
export CONTAINER_NAME=ci_native_qt5
-export DOCKER_NAME_TAG=debian:buster # Check that buster gcc-8 can compile our C++17 and run our functional tests in python3, see doc/dependencies.md
+export CI_IMAGE_NAME_TAG=debian:buster
+# Use minimum supported python3.7 and gcc-8, see doc/dependencies.md
export PACKAGES="gcc-8 g++-8 python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev"
export DEP_OPTS="NO_QT=1 NO_UPNP=1 NO_NATPMP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1 CC=gcc-8 CXX=g++-8"
export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
export RUN_UNIT_TESTS_SEQUENTIAL="true"
export RUN_UNIT_TESTS="false"
export GOAL="install"
+export NO_WERROR=1
export DOWNLOAD_PREVIOUS_RELEASES="true"
export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-reduce-exports \
--enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\" CC=gcc-8 CXX=g++-8"
diff --git a/ci/test/00_setup_env_native_tidy.sh b/ci/test/00_setup_env_native_tidy.sh
index 11a12e336a..06ffe14636 100755
--- a/ci/test/00_setup_env_native_tidy.sh
+++ b/ci/test/00_setup_env_native_tidy.sh
@@ -6,7 +6,7 @@
export LC_ALL=C.UTF-8
-export DOCKER_NAME_TAG="ubuntu:22.04"
+export CI_IMAGE_NAME_TAG="ubuntu:22.04"
export CONTAINER_NAME=ci_native_tidy
export PACKAGES="clang libclang-dev llvm-dev clang-tidy bear cmake libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev"
export NO_DEPENDS=1
@@ -15,5 +15,5 @@ export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=false
export RUN_TIDY=true
export GOAL="install"
-export BITCOIN_CONFIG="CC=clang CXX=clang++ --enable-c++20 --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'"
+export BITCOIN_CONFIG="CC=clang CXX=clang++ --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'"
export CCACHE_SIZE=200M
diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh
index 6bf8391209..61bcd98f0a 100755
--- a/ci/test/00_setup_env_native_tsan.sh
+++ b/ci/test/00_setup_env_native_tsan.sh
@@ -1,14 +1,14 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
export CONTAINER_NAME=ci_native_tsan
-export DOCKER_NAME_TAG=ubuntu:22.04
+export CI_IMAGE_NAME_TAG=ubuntu:22.04
export PACKAGES="clang-13 llvm-13 libc++abi-13-dev libc++-13-dev python3-zmq"
export DEP_OPTS="CC=clang-13 CXX='clang++-13 -stdlib=libc++'"
export GOAL="install"
-export BITCOIN_CONFIG="--enable-zmq CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION' CXXFLAGS='-g' --with-sanitizers=thread CC=clang-13 CXX='clang++-13 -stdlib=libc++'"
+export BITCOIN_CONFIG="--enable-zmq CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION' CXXFLAGS='-g' --with-sanitizers=thread"
diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh
index d8c08fca39..039a22b02e 100755
--- a/ci/test/00_setup_env_native_valgrind.sh
+++ b/ci/test/00_setup_env_native_valgrind.sh
@@ -1,12 +1,12 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
-export DOCKER_NAME_TAG="ubuntu:22.04"
+export CI_IMAGE_NAME_TAG="ubuntu:22.04"
export CONTAINER_NAME=ci_native_valgrind
export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev"
export USE_VALGRIND=1
diff --git a/ci/test/00_setup_env_s390x.sh b/ci/test/00_setup_env_s390x.sh
index 136edb6662..af18703ce1 100755
--- a/ci/test/00_setup_env_s390x.sh
+++ b/ci/test/00_setup_env_s390x.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,7 +18,7 @@ if [ -n "$QEMU_USER_CMD" ]; then
fi
# Use debian to avoid 404 apt errors
export CONTAINER_NAME=ci_s390x
-export DOCKER_NAME_TAG="debian:bookworm"
+export CI_IMAGE_NAME_TAG="debian:bookworm"
export TEST_RUNNER_ENV="LC_ALL=C"
export TEST_RUNNER_EXTRA="--exclude feature_init,rpc_bind,feature_bind_extra" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547
export RUN_FUNCTIONAL_TESTS=true
diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh
index 3600113551..3adfbf6e47 100755
--- a/ci/test/00_setup_env_win64.sh
+++ b/ci/test/00_setup_env_win64.sh
@@ -1,16 +1,16 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
export CONTAINER_NAME=ci_win64
-export DOCKER_NAME_TAG=ubuntu:22.04 # Check that Jammy can cross-compile to win64
+export CI_IMAGE_NAME_TAG=ubuntu:22.04 # Check that Jammy can cross-compile to win64
export HOST=x86_64-w64-mingw32
export DPKG_ADD_ARCH="i386"
export PACKAGES="python3 nsis g++-mingw-w64-x86-64-posix wine-binfmt wine64 wine32 file"
export RUN_FUNCTIONAL_TESTS=false
export GOAL="deploy"
-export BITCOIN_CONFIG="--enable-reduce-exports --disable-external-signer --disable-gui-tests"
+export BITCOIN_CONFIG="--enable-reduce-exports --enable-external-signer --disable-gui-tests"
diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh
new file mode 100755
index 0000000000..c2469d7ca9
--- /dev/null
+++ b/ci/test/01_base_install.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018-2022 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
+
+CI_EXEC_ROOT () { bash -c "$*"; }
+export -f CI_EXEC_ROOT
+
+if [ -n "$DPKG_ADD_ARCH" ]; then
+ CI_EXEC_ROOT dpkg --add-architecture "$DPKG_ADD_ARCH"
+fi
+
+if [[ $CI_IMAGE_NAME_TAG == *centos* ]]; then
+ ${CI_RETRY_EXE} CI_EXEC_ROOT dnf -y install epel-release
+ ${CI_RETRY_EXE} CI_EXEC_ROOT dnf -y --allowerasing install "$CI_BASE_PACKAGES" "$PACKAGES"
+elif [ "$CI_USE_APT_INSTALL" != "no" ]; then
+ if [[ "${ADD_UNTRUSTED_BPFCC_PPA}" == "true" ]]; then
+ # Ubuntu 22.04 LTS and Debian 11 both have an outdated bpfcc-tools packages.
+ # The iovisor PPA is outdated as well. The next Ubuntu and Debian releases will contain updated
+ # packages. Meanwhile, use an untrusted PPA to install an up-to-date version of the bpfcc-tools
+ # package.
+ # TODO: drop this once we can use newer images in GCE
+ CI_EXEC_ROOT add-apt-repository ppa:hadret/bpfcc
+ fi
+ if [[ -n "${APPEND_APT_SOURCES_LIST}" ]]; then
+ CI_EXEC_ROOT echo "${APPEND_APT_SOURCES_LIST}" \>\> /etc/apt/sources.list
+ fi
+ ${CI_RETRY_EXE} CI_EXEC_ROOT apt-get update
+ ${CI_RETRY_EXE} CI_EXEC_ROOT apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$CI_BASE_PACKAGES"
+fi
diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh
index b256ae21a5..62bc3a963d 100755
--- a/ci/test/04_install.sh
+++ b/ci/test/04_install.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,14 +20,28 @@ export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/t
export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1"
env | grep -E '^(BITCOIN_CONFIG|BASE_|QEMU_|CCACHE_|LC_ALL|BOOST_TEST_RANDOM|DEBIAN_FRONTEND|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS|PREVIOUS_RELEASES_DIR)' | tee /tmp/env
if [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764)
- DOCKER_ADMIN="--cap-add SYS_PTRACE"
+ CI_CONTAINER_CAP="--cap-add SYS_PTRACE"
fi
export P_CI_DIR="$PWD"
+export BINS_SCRATCH_DIR="${BASE_SCRATCH_DIR}/bins/"
if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
- echo "Creating $DOCKER_NAME_TAG container to run in"
- ${CI_RETRY_EXE} docker pull "$DOCKER_NAME_TAG"
+ echo "Creating $CI_IMAGE_NAME_TAG container to run in"
+ LOCAL_UID=$(id -u)
+ LOCAL_GID=$(id -g)
+
+ # the name isn't important, so long as we use the same UID
+ LOCAL_USER=nonroot
+ DOCKER_BUILDKIT=1 ${CI_RETRY_EXE} docker build \
+ --file "${BASE_ROOT_DIR}/ci/test_imagefile" \
+ --build-arg "CI_IMAGE_NAME_TAG=${CI_IMAGE_NAME_TAG}" \
+ --build-arg "FILE_ENV=${FILE_ENV}" \
+ --tag="${CONTAINER_NAME}" \
+ "${BASE_ROOT_DIR}"
+ docker volume create "${CONTAINER_NAME}_ccache" || true
+ docker volume create "${CONTAINER_NAME}_depends" || true
+ docker volume create "${CONTAINER_NAME}_previous_releases" || true
if [ -n "${RESTART_CI_DOCKER_BEFORE_RUN}" ] ; then
echo "Restart docker before run to stop and clear all containers started with --rm"
@@ -35,50 +49,47 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
fi
# shellcheck disable=SC2086
- DOCKER_ID=$(docker run $DOCKER_ADMIN --rm --interactive --detach --tty \
+ CI_CONTAINER_ID=$(docker run $CI_CONTAINER_CAP --rm --interactive --detach --tty \
--mount type=bind,src=$BASE_ROOT_DIR,dst=/ro_base,readonly \
- --mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR \
- --mount type=bind,src=$DEPENDS_DIR,dst=$DEPENDS_DIR \
- --mount type=bind,src=$PREVIOUS_RELEASES_DIR,dst=$PREVIOUS_RELEASES_DIR \
+ --mount "type=volume,src=${CONTAINER_NAME}_ccache,dst=$CCACHE_DIR" \
+ --mount "type=volume,src=${CONTAINER_NAME}_depends,dst=$DEPENDS_DIR" \
+ --mount "type=volume,src=${CONTAINER_NAME}_previous_releases,dst=$PREVIOUS_RELEASES_DIR" \
-w $BASE_ROOT_DIR \
--env-file /tmp/env \
--name $CONTAINER_NAME \
- $DOCKER_NAME_TAG)
- export DOCKER_CI_CMD_PREFIX="docker exec $DOCKER_ID"
+ $CONTAINER_NAME)
+ export CI_CONTAINER_ID
+
+ # Create a non-root user inside the container which matches the local user.
+ #
+ # This prevents the root user in the container modifying the local file system permissions
+ # on the mounted directories
+ docker exec "$CI_CONTAINER_ID" useradd -u "$LOCAL_UID" -o -m "$LOCAL_USER"
+ docker exec "$CI_CONTAINER_ID" groupmod -o -g "$LOCAL_GID" "$LOCAL_USER"
+ docker exec "$CI_CONTAINER_ID" chown -R "$LOCAL_USER":"$LOCAL_USER" "${BASE_ROOT_DIR}"
+ export CI_EXEC_CMD_PREFIX_ROOT="docker exec -u 0 $CI_CONTAINER_ID"
+ export CI_EXEC_CMD_PREFIX="docker exec -u $LOCAL_UID $CI_CONTAINER_ID"
else
echo "Running on host system without docker wrapper"
+ "${BASE_ROOT_DIR}/ci/test/01_base_install.sh"
fi
CI_EXEC () {
- $DOCKER_CI_CMD_PREFIX bash -c "export PATH=$BASE_SCRATCH_DIR/bins/:\$PATH && cd \"$P_CI_DIR\" && $*"
+ $CI_EXEC_CMD_PREFIX bash -c "export PATH=${BINS_SCRATCH_DIR}:\$PATH && cd \"$P_CI_DIR\" && $*"
+}
+CI_EXEC_ROOT () {
+ $CI_EXEC_CMD_PREFIX_ROOT bash -c "export PATH=${BINS_SCRATCH_DIR}:\$PATH && cd \"$P_CI_DIR\" && $*"
}
export -f CI_EXEC
+export -f CI_EXEC_ROOT
-if [ -n "$DPKG_ADD_ARCH" ]; then
- CI_EXEC dpkg --add-architecture "$DPKG_ADD_ARCH"
-fi
-
-if [[ $DOCKER_NAME_TAG == *centos* ]]; then
- ${CI_RETRY_EXE} CI_EXEC dnf -y install epel-release
- ${CI_RETRY_EXE} CI_EXEC dnf -y --allowerasing install "$DOCKER_PACKAGES" "$PACKAGES"
-elif [ "$CI_USE_APT_INSTALL" != "no" ]; then
- if [[ "${ADD_UNTRUSTED_BPFCC_PPA}" == "true" ]]; then
- # Ubuntu 22.04 LTS and Debian 11 both have an outdated bpfcc-tools packages.
- # The iovisor PPA is outdated as well. The next Ubuntu and Debian releases will contain updated
- # packages. Meanwhile, use an untrusted PPA to install an up-to-date version of the bpfcc-tools
- # package.
- # TODO: drop this once we can use newer images in GCE
- CI_EXEC add-apt-repository ppa:hadret/bpfcc
- fi
- ${CI_RETRY_EXE} CI_EXEC apt-get update
- ${CI_RETRY_EXE} CI_EXEC apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$DOCKER_PACKAGES"
-fi
+CI_EXEC mkdir -p "${BINS_SCRATCH_DIR}"
if [ -n "$PIP_PACKAGES" ]; then
if [ "$CI_OS_NAME" == "macos" ]; then
sudo -H pip3 install --upgrade pip
# shellcheck disable=SC2086
- IN_GETOPT_BIN="/usr/local/opt/gnu-getopt/bin/getopt" ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
+ IN_GETOPT_BIN="$(brew --prefix gnu-getopt)/bin/getopt" ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
else
# shellcheck disable=SC2086
${CI_RETRY_EXE} CI_EXEC pip3 install --user $PIP_PACKAGES
@@ -112,8 +123,8 @@ fi
CI_EXEC mkdir -p "${BASE_SCRATCH_DIR}/sanitizer-output/"
if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then
- CI_EXEC "update-alternatives --install /usr/bin/clang++ clang++ \$(which clang++-12) 100"
- CI_EXEC "update-alternatives --install /usr/bin/clang clang \$(which clang-12) 100"
+ CI_EXEC_ROOT "update-alternatives --install /usr/bin/clang++ clang++ \$(which clang++-12) 100"
+ CI_EXEC_ROOT "update-alternatives --install /usr/bin/clang clang \$(which clang-12) 100"
CI_EXEC "mkdir -p ${BASE_SCRATCH_DIR}/msan/build/"
CI_EXEC "git clone --depth=1 https://github.com/llvm/llvm-project -b llvmorg-12.0.0 ${BASE_SCRATCH_DIR}/msan/llvm-project"
CI_EXEC "cd ${BASE_SCRATCH_DIR}/msan/build/ && cmake -DLLVM_ENABLE_PROJECTS='libcxx;libcxxabi' -DCMAKE_BUILD_TYPE=Release -DLLVM_USE_SANITIZER=MemoryWithOrigins -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_TARGETS_TO_BUILD=X86 ../llvm-project/llvm/"
@@ -126,7 +137,7 @@ if [[ "${RUN_TIDY}" == "true" ]]; then
CI_EXEC "mkdir -p ${DIR_IWYU}/build/"
CI_EXEC "git clone --depth=1 https://github.com/include-what-you-use/include-what-you-use -b clang_14 ${DIR_IWYU}/include-what-you-use"
CI_EXEC "cd ${DIR_IWYU}/build && cmake -G 'Unix Makefiles' -DCMAKE_PREFIX_PATH=/usr/lib/llvm-14 ../include-what-you-use"
- CI_EXEC "cd ${DIR_IWYU}/build && make install $MAKEJOBS"
+ CI_EXEC_ROOT "cd ${DIR_IWYU}/build && make install $MAKEJOBS"
fi
fi
@@ -137,12 +148,10 @@ fi
if [ "$USE_BUSY_BOX" = "true" ]; then
echo "Setup to use BusyBox utils"
- CI_EXEC mkdir -p "${BASE_SCRATCH_DIR}/bins/"
# tar excluded for now because it requires passing in the exact archive type in ./depends (fixed in later BusyBox version)
- # find excluded for now because it does not recognize the -delete option in ./depends (fixed in later BusyBox version)
# ar excluded for now because it does not recognize the -q option in ./depends (unknown if fixed)
# shellcheck disable=SC1010
- CI_EXEC for util in \$\(busybox --list \| grep -v "^ar$" \| grep -v "^tar$" \| grep -v "^find$"\)\; do ln -s \$\(command -v busybox\) "${BASE_SCRATCH_DIR}/bins/\$util"\; done
+ CI_EXEC for util in \$\(busybox --list \| grep -v "^ar$" \| grep -v "^tar$" \)\; do ln -s \$\(command -v busybox\) "${BINS_SCRATCH_DIR}/\$util"\; done
# Print BusyBox version
CI_EXEC patch --help
fi
diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh
index ef3dff86ca..f49305597d 100755
--- a/ci/test/05_before_script.sh
+++ b/ci/test/05_before_script.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@ if [ "$CI_OS_NAME" == "macos" ]; then
echo > "${HOME}/Library/Application Support/Bitcoin"
else
CI_EXEC echo \> \$HOME/.bitcoin
+ CI_EXEC_ROOT echo \> \$HOME/.bitcoin
fi
CI_EXEC mkdir -p "${DEPENDS_DIR}/SDKs" "${DEPENDS_DIR}/sdk-sources"
@@ -37,7 +38,7 @@ if [ -n "$ANDROID_HOME" ] && [ ! -d "$ANDROID_HOME" ]; then
fi
if [ -z "$NO_DEPENDS" ]; then
- if [[ $DOCKER_NAME_TAG == *centos* ]]; then
+ if [[ $CI_IMAGE_NAME_TAG == *centos* ]]; then
# CentOS has problems building the depends if the config shell is not explicitly set
# (i.e. for libevent a Makefile with an empty SHELL variable is generated, leading to
# an error as the first command is executed)
diff --git a/ci/test/06_script_a.sh b/ci/test/06_script_a.sh
index 13693a2ecf..5856d33d2d 100755
--- a/ci/test/06_script_a.sh
+++ b/ci/test/06_script_a.sh
@@ -1,12 +1,15 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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
-BITCOIN_CONFIG_ALL="--enable-suppress-external-warnings --disable-dependency-tracking --prefix=$DEPENDS_DIR/$HOST"
+BITCOIN_CONFIG_ALL="--enable-suppress-external-warnings --disable-dependency-tracking"
+if [ -z "$NO_DEPENDS" ]; then
+ BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} CONFIG_SITE=$DEPENDS_DIR/$HOST/share/config.site"
+fi
if [ -z "$NO_WERROR" ]; then
BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-werror"
fi
@@ -23,7 +26,7 @@ if [ -n "$ANDROID_TOOLS_URL" ]; then
exit 0
fi
-BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-external-signer --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib"
+BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-external-signer --prefix=$BASE_OUTDIR"
if [ -n "$CONFIG_SHELL" ]; then
CI_EXEC "$CONFIG_SHELL" -c "./autogen.sh"
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index 5bdb392ba3..7a01672d18 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,12 +9,14 @@ export LC_ALL=C.UTF-8
if [[ $HOST = *-mingw32 ]]; then
# Generate all binaries, so that they can be wrapped
CI_EXEC make "$MAKEJOBS" -C src/secp256k1 VERBOSE=1
+ CI_EXEC make "$MAKEJOBS" -C src minisketch/test.exe VERBOSE=1
CI_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-wine.sh"
fi
if [ -n "$QEMU_USER_CMD" ]; then
# Generate all binaries, so that they can be wrapped
CI_EXEC make "$MAKEJOBS" -C src/secp256k1 VERBOSE=1
+ CI_EXEC make "$MAKEJOBS" -C src minisketch/test VERBOSE=1
CI_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-qemu.sh"
fi
@@ -31,7 +33,7 @@ if [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then
fi
if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
- CI_EXEC LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" "${TEST_RUNNER_ENV}" test/functional/test_runner.py --ci "$MAKEJOBS" --tmpdirprefix "${BASE_SCRATCH_DIR}/test_runner/" --ansi --combinedlogslen=4000 --timeout-factor="${TEST_RUNNER_TIMEOUT_FACTOR}" "${TEST_RUNNER_EXTRA}" --quiet --failfast
+ CI_EXEC LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" "${TEST_RUNNER_ENV}" test/functional/test_runner.py --ci "$MAKEJOBS" --tmpdirprefix "${BASE_SCRATCH_DIR}/test_runner/" --ansi --combinedlogslen=99999999 --timeout-factor="${TEST_RUNNER_TIMEOUT_FACTOR}" "${TEST_RUNNER_EXTRA}" --quiet --failfast
fi
if [ "${RUN_TIDY}" = "true" ]; then
@@ -40,24 +42,34 @@ if [ "${RUN_TIDY}" = "true" ]; then
( CI_EXEC run-clang-tidy -quiet "${MAKEJOBS}" ) | grep -C5 "error"
export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST/"
CI_EXEC "python3 ${DIR_IWYU}/include-what-you-use/iwyu_tool.py"\
+ " src/common/init.cpp"\
+ " src/common/url.cpp"\
" src/compat"\
" src/dbwrapper.cpp"\
" src/init"\
" src/kernel"\
" src/node/chainstate.cpp"\
+ " src/node/chainstatemanager_args.cpp"\
" src/node/mempool_args.cpp"\
+ " src/node/minisketchwrapper.cpp"\
+ " src/node/utxo_snapshot.cpp"\
" src/node/validation_cache_args.cpp"\
" src/policy/feerate.cpp"\
" src/policy/packages.cpp"\
" src/policy/settings.cpp"\
" src/primitives/transaction.cpp"\
+ " src/random.cpp"\
" src/rpc/fees.cpp"\
" src/rpc/signmessage.cpp"\
" src/test/fuzz/txorphan.cpp"\
- " src/threadinterrupt.cpp"\
+ " src/test/fuzz/util/"\
+ " src/test/util/coins.cpp"\
+ " src/uint256.cpp"\
" src/util/bip32.cpp"\
" src/util/bytevectorhash.cpp"\
+ " src/util/check.cpp"\
" src/util/error.cpp"\
+ " src/util/exception.cpp"\
" src/util/getuniquepath.cpp"\
" src/util/hasher.cpp"\
" src/util/message.cpp"\
@@ -67,8 +79,14 @@ if [ "${RUN_TIDY}" = "true" ]; then
" src/util/strencodings.cpp"\
" src/util/string.cpp"\
" src/util/syserror.cpp"\
- " src/util/url.cpp"\
- " -p . ${MAKEJOBS} -- -Xiwyu --cxx17ns -Xiwyu --mapping_file=${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp"
+ " src/util/threadinterrupt.cpp"\
+ " src/zmq"\
+ " -p . ${MAKEJOBS}"\
+ " -- -Xiwyu --cxx17ns -Xiwyu --mapping_file=${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp"\
+ " |& tee /tmp/iwyu_ci.out"
+ export P_CI_DIR="${BASE_ROOT_DIR}/src"
+ CI_EXEC "python3 ${DIR_IWYU}/include-what-you-use/fix_includes.py --nosafe_headers < /tmp/iwyu_ci.out"
+ CI_EXEC "git --no-pager diff"
fi
if [ "$RUN_SECURITY_TESTS" = "true" ]; then
@@ -78,3 +96,8 @@ fi
if [ "$RUN_FUZZ_TESTS" = "true" ]; then
CI_EXEC LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" test/fuzz/test_runner.py "${FUZZ_TESTS_CONFIG}" "$MAKEJOBS" -l DEBUG "${DIR_FUZZ_IN}"
fi
+
+if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
+ echo "Stop and remove CI container by ID"
+ docker container kill "${CI_CONTAINER_ID}"
+fi
diff --git a/ci/test/wrap-qemu.sh b/ci/test/wrap-qemu.sh
index eb31edbce8..e028ede378 100755
--- a/ci/test/wrap-qemu.sh
+++ b/ci/test/wrap-qemu.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/ci/test/wrap-wine.sh b/ci/test/wrap-wine.sh
index 1662f8f6a3..90e53887bc 100755
--- a/ci/test/wrap-wine.sh
+++ b/ci/test/wrap-wine.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/ci/test_imagefile b/ci/test_imagefile
new file mode 100644
index 0000000000..4854708d1a
--- /dev/null
+++ b/ci/test_imagefile
@@ -0,0 +1,10 @@
+ARG CI_IMAGE_NAME_TAG
+FROM ${CI_IMAGE_NAME_TAG}
+
+ARG FILE_ENV
+ENV FILE_ENV=${FILE_ENV}
+
+COPY ./ci/retry/retry /usr/bin/retry
+COPY ./ci/test/00_setup_env.sh ./${FILE_ENV} ./ci/test/01_base_install.sh /ci_base_install/ci/test/
+
+RUN ["bash", "-c", "cd /ci_base_install/ && set -o errexit && source ./ci/test/00_setup_env.sh && ./ci/test/01_base_install.sh"]
diff --git a/configure.ac b/configure.ac
index 82cb469864..cbe3dbcf19 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ define(_CLIENT_VERSION_MINOR, 99)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_IS_RELEASE, false)
-define(_COPYRIGHT_YEAR, 2022)
+define(_COPYRIGHT_YEAR, 2023)
define(_COPYRIGHT_HOLDERS,[The %s developers])
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]])
AC_INIT([Bitcoin Core],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_BUILD)m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/])
@@ -76,6 +76,12 @@ dnl we have those under control, re-enable that functionality.
case $host in
*mingw*)
lt_cv_deplibs_check_method="pass_all"
+
+ dnl Remove unwanted -DDLL_EXPORT from these variables.
+ dnl We do not use this macro, but system headers may export unwanted symbols
+ dnl if it's set.
+ lt_cv_prog_compiler_pic="-DPIC"
+ lt_cv_prog_compiler_pic_CXX="-DPIC"
;;
esac
@@ -120,8 +126,8 @@ AC_PATH_TOOL([AR], [ar])
AC_PATH_TOOL([GCOV], [gcov])
AC_PATH_TOOL([LLVM_COV], [llvm-cov])
AC_PATH_PROG([LCOV], [lcov])
-dnl Python 3.6 is specified in .python-version and should be used if available, see doc/dependencies.md
-AC_PATH_PROGS([PYTHON], [python3.6 python3.7 python3.8 python3.9 python3.10 python3.11 python3 python])
+dnl Python 3.7 is specified in .python-version and should be used if available, see doc/dependencies.md
+AC_PATH_PROGS([PYTHON], [python3.7 python3.8 python3.9 python3.10 python3.11 python3.12 python3 python])
AC_PATH_PROG([GENHTML], [genhtml])
AC_PATH_PROG([GIT], [git])
AC_PATH_PROG([CCACHE], [ccache])
@@ -163,24 +169,12 @@ AC_ARG_WITH([miniupnpc],
[use_upnp=$withval],
[use_upnp=auto])
-AC_ARG_ENABLE([upnp-default],
- [AS_HELP_STRING([--enable-upnp-default],
- [if UPNP is enabled, turn it on at startup (default is no)])],
- [use_upnp_default=$enableval],
- [use_upnp_default=no])
-
AC_ARG_WITH([natpmp],
[AS_HELP_STRING([--with-natpmp],
[enable NAT-PMP (default is yes if libnatpmp is found)])],
[use_natpmp=$withval],
[use_natpmp=auto])
-AC_ARG_ENABLE([natpmp-default],
- [AS_HELP_STRING([--enable-natpmp-default],
- [if NAT-PMP is enabled, turn it on at startup (default is no)])],
- [use_natpmp_default=$enableval],
- [use_natpmp_default=no])
-
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--disable-tests],[do not compile tests (default is to compile)]),
[use_tests=$enableval],
@@ -448,7 +442,7 @@ if test "$CXXFLAGS_overridden" = "no"; then
AX_CHECK_COMPILE_FLAG([-Wvla], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wvla"], [], [$CXXFLAG_WERROR])
AX_CHECK_COMPILE_FLAG([-Wshadow-field], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wshadow-field"], [], [$CXXFLAG_WERROR])
AX_CHECK_COMPILE_FLAG([-Wthread-safety], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wthread-safety"], [], [$CXXFLAG_WERROR])
- AX_CHECK_COMPILE_FLAG([-Wloop-analysis], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wrange-loop-analysis"], [], [$CXXFLAG_WERROR])
+ AX_CHECK_COMPILE_FLAG([-Wloop-analysis], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wloop-analysis"], [], [$CXXFLAG_WERROR])
AX_CHECK_COMPILE_FLAG([-Wredundant-decls], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wredundant-decls"], [], [$CXXFLAG_WERROR])
AX_CHECK_COMPILE_FLAG([-Wunused-member-function], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wunused-member-function"], [], [$CXXFLAG_WERROR])
AX_CHECK_COMPILE_FLAG([-Wdate-time], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wdate-time"], [], [$CXXFLAG_WERROR])
@@ -588,8 +582,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
CXXFLAGS="$TEMP_CXXFLAGS"
# ARM
-AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_CRC_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR])
-AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_SHANI_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR])
+AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc], [ARM_CRC_CXXFLAGS="-march=armv8-a+crc"], [], [$CXXFLAG_WERROR])
+AX_CHECK_COMPILE_FLAG([-march=armv8-a+crypto], [ARM_SHANI_CXXFLAGS="-march=armv8-a+crypto"], [], [$CXXFLAG_WERROR])
TEMP_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$ARM_CRC_CXXFLAGS $CXXFLAGS"
@@ -763,10 +757,6 @@ case $host in
BDB_LIBS="-L$bdb_prefix/lib -ldb_cxx-4.8"
fi
- if test "$use_sqlite" != "no" && $BREW list --versions sqlite3 >/dev/null; then
- export PKG_CONFIG_PATH="$($BREW --prefix sqlite3 2>/dev/null)/lib/pkgconfig:$PKG_CONFIG_PATH"
- fi
-
if $BREW list --versions qt@5 >/dev/null; then
export PKG_CONFIG_PATH="$($BREW --prefix qt@5 2>/dev/null)/lib/pkgconfig:$PKG_CONFIG_PATH"
fi
@@ -951,7 +941,9 @@ if test "$TARGET_OS" != "windows"; then
AX_CHECK_COMPILE_FLAG([-fPIC], [PIC_FLAGS="-fPIC"])
fi
-dnl All versions of gcc that we commonly use for building are subject to bug
+dnl Versions of gcc prior to 12.1 (commit
+dnl https://github.com/gcc-mirror/gcc/commit/551aa75778a4c5165d9533cd447c8fc822f583e1)
+dnl are subject to a bug, see the gccbug_90348 test case and
dnl https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90348. To work around that, set
dnl -fstack-reuse=none for all gcc builds. (Only gcc understands this flag)
AX_CHECK_COMPILE_FLAG([-fstack-reuse=none], [HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-reuse=none"])
@@ -977,11 +969,11 @@ if test "$use_hardening" != "no"; then
dnl However, FORTIFY_SOURCE requires that there is some level of optimization, otherwise it does nothing and just creates a compiler warning.
dnl Since FORTIFY_SOURCE is a no-op without optimizations, do not enable it when enable_debug is yes.
if test "$enable_debug" != "yes"; then
- AX_CHECK_PREPROC_FLAG([-D_FORTIFY_SOURCE=2],[
+ AX_CHECK_PREPROC_FLAG([-D_FORTIFY_SOURCE=3],[
AX_CHECK_PREPROC_FLAG([-U_FORTIFY_SOURCE],[
HARDENED_CPPFLAGS="$HARDENED_CPPFLAGS -U_FORTIFY_SOURCE"
])
- HARDENED_CPPFLAGS="$HARDENED_CPPFLAGS -D_FORTIFY_SOURCE=2"
+ HARDENED_CPPFLAGS="$HARDENED_CPPFLAGS -D_FORTIFY_SOURCE=3"
])
fi
@@ -1010,7 +1002,7 @@ if test "$TARGET_OS" = "darwin"; then
AX_CHECK_LINK_FLAG([-Wl,-bind_at_load], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-bind_at_load"], [], [$LDFLAG_WERROR])
fi
-AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h unistd.h sys/types.h sys/stat.h sys/select.h sys/prctl.h sys/sysctl.h vm/vm_param.h sys/vmmeter.h sys/resources.h])
+AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h sys/select.h sys/prctl.h sys/sysctl.h vm/vm_param.h sys/vmmeter.h sys/resources.h])
AC_CHECK_DECLS([getifaddrs, freeifaddrs],[CHECK_SOCKET],,
[#include <sys/types.h>
@@ -1417,7 +1409,7 @@ if test "$use_usdt" != "no"; then
fi
AM_CONDITIONAL([ENABLE_USDT_TRACEPOINTS], [test "$use_usdt" = "yes"])
-if test "$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests" = "nonononononono"; then
+if test "$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests" = "nononono"; then
use_upnp=no
use_natpmp=no
use_zmq=no
@@ -1432,14 +1424,15 @@ if test "$use_upnp" != "no"; then
[AC_CHECK_LIB([miniupnpc], [upnpDiscover], [MINIUPNPC_LIBS="$MINIUPNPC_LIBS -lminiupnpc"], [have_miniupnpc=no], [$MINIUPNPC_LIBS])],
[have_miniupnpc=no]
)
- dnl The minimum supported miniUPnPc API version is set to 10. This keeps compatibility
- dnl with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages.
+
+ dnl The minimum supported miniUPnPc API version is set to 17. This excludes
+ dnl versions with known vulnerabilities.
if test "$have_miniupnpc" != "no"; then
AC_MSG_CHECKING([whether miniUPnPc API version is supported])
AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[
@%:@include <miniupnpc/miniupnpc.h>
]], [[
- #if MINIUPNPC_API_VERSION >= 10
+ #if MINIUPNPC_API_VERSION >= 17
// Everything is okay
#else
# error miniUPnPc API version is too old
@@ -1448,7 +1441,7 @@ if test "$use_upnp" != "no"; then
AC_MSG_RESULT([yes])
],[
AC_MSG_RESULT([no])
- AC_MSG_WARN([miniUPnPc API version < 10 is unsupported, disabling UPnP support.])
+ AC_MSG_WARN([miniUPnPc API version < 17 is unsupported, disabling UPnP support.])
have_miniupnpc=no
])
fi
@@ -1465,7 +1458,7 @@ if test "$use_natpmp" != "no"; then
CPPFLAGS="$TEMP_CPPFLAGS"
fi
-if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench" = "nonononononono"; then
+if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench$enable_fuzz_binary" = "nonononononononono"; then
use_boost=no
else
use_boost=yes
@@ -1483,9 +1476,11 @@ if test "$use_boost" = "yes"; then
BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION"
dnl Prevent use of std::unary_function, which was removed in C++17,
- dnl and will generate warnings with newer compilers.
- dnl See: https://github.com/boostorg/container_hash/issues/22.
- BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_CXX98_FUNCTION_BASE"
+ dnl and will generate warnings with newer compilers for Boost
+ dnl older than 1.80.
+ dnl See: https://github.com/boostorg/config/pull/430.
+ AX_CHECK_PREPROC_FLAG([-DBOOST_NO_CXX98_FUNCTION_BASE], [BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_CXX98_FUNCTION_BASE"], [], [$CXXFLAG_WERROR],
+ [AC_LANG_PROGRAM([[#include <boost/config.hpp>]])])
if test "$enable_debug" = "yes" || test "$enable_fuzz" = "yes"; then
BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE"
@@ -1497,45 +1492,45 @@ if test "$use_boost" = "yes"; then
fi
if test "$use_external_signer" != "no"; then
- case $host in
- *mingw*)
- dnl Boost Process uses Boost Filesystem when targeting Windows. Also,
- dnl since Boost 1.71.0, Process does not work with mingw-w64 without
- dnl workarounds. See 67669ab425b52a2b6be3d2f3b3b7e3939b676a2c.
- if test "$use_external_signer" = "yes"; then
- AC_MSG_ERROR([External signing is not supported on Windows])
- fi
- use_external_signer="no";
- ;;
- *)
- AC_MSG_CHECKING([whether Boost.Process can be used])
- TEMP_CXXFLAGS="$CXXFLAGS"
- dnl Boost 1.78 requires the following workaround.
- dnl See: https://github.com/boostorg/process/issues/235
- CXXFLAGS="$CXXFLAGS -Wno-error=narrowing"
- TEMP_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
- TEMP_LDFLAGS="$LDFLAGS"
- dnl Boost 1.73 and older require the following workaround.
- LDFLAGS="$LDFLAGS $PTHREAD_CFLAGS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <boost/process.hpp>]])],
- [have_boost_process="yes"],
- [have_boost_process="no"])
- LDFLAGS="$TEMP_LDFLAGS"
- CPPFLAGS="$TEMP_CPPFLAGS"
- CXXFLAGS="$TEMP_CXXFLAGS"
- AC_MSG_RESULT([$have_boost_process])
- if test "$have_boost_process" = "yes"; then
- use_external_signer="yes"
- AC_DEFINE([ENABLE_EXTERNAL_SIGNER], [1], [Define if external signer support is enabled])
- else
- if test "$use_external_signer" = "yes"; then
- AC_MSG_ERROR([External signing is not supported for this Boost version])
- fi
- use_external_signer="no";
- fi
- ;;
- esac
+ AC_MSG_CHECKING([whether Boost.Process can be used])
+ TEMP_CXXFLAGS="$CXXFLAGS"
+ dnl Boost 1.78 requires the following workaround.
+ dnl See: https://github.com/boostorg/process/issues/235
+ CXXFLAGS="$CXXFLAGS -Wno-error=narrowing"
+ TEMP_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+ TEMP_LDFLAGS="$LDFLAGS"
+ dnl Boost 1.73 and older require the following workaround.
+ LDFLAGS="$LDFLAGS $PTHREAD_CFLAGS"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #define BOOST_PROCESS_USE_STD_FS
+ #include <boost/process.hpp>
+ ]],[[
+ namespace bp = boost::process;
+ bp::opstream stdin_stream;
+ bp::ipstream stdout_stream;
+ bp::child c("dummy", bp::std_out > stdout_stream, bp::std_err > stdout_stream, bp::std_in < stdin_stream);
+ stdin_stream << std::string{"test"} << std::endl;
+ if (c.running()) c.terminate();
+ c.wait();
+ c.exit_code();
+ ]])],
+ [have_boost_process="yes"],
+ [have_boost_process="no"])
+ LDFLAGS="$TEMP_LDFLAGS"
+ CPPFLAGS="$TEMP_CPPFLAGS"
+ CXXFLAGS="$TEMP_CXXFLAGS"
+ AC_MSG_RESULT([$have_boost_process])
+ if test "$have_boost_process" = "yes"; then
+ use_external_signer="yes"
+ AC_DEFINE([ENABLE_EXTERNAL_SIGNER], [1], [Define if external signer support is enabled])
+ AC_DEFINE([BOOST_PROCESS_USE_STD_FS], [1], [Defined to avoid Boost::Process trying to use Boost Filesystem])
+ else
+ if test "$use_external_signer" = "yes"; then
+ AC_MSG_ERROR([External signing is not supported for this Boost version])
+ fi
+ use_external_signer="no";
+ fi
fi
AM_CONDITIONAL([ENABLE_EXTERNAL_SIGNER], [test "$use_external_signer" = "yes"])
@@ -1769,15 +1764,8 @@ if test "$have_miniupnpc" = "no"; then
else
if test "$use_upnp" != "no"; then
AC_MSG_RESULT([yes])
- AC_MSG_CHECKING([whether to build with UPnP enabled by default])
use_upnp=yes
- upnp_setting=0
- if test "$use_upnp_default" != "no"; then
- use_upnp_default=yes
- upnp_setting=1
- fi
- AC_MSG_RESULT([$use_upnp_default])
- AC_DEFINE_UNQUOTED([USE_UPNP],[$upnp_setting],[UPnP support not compiled if undefined, otherwise value (0 or 1) determines default state])
+ AC_DEFINE([USE_UPNP], [1], [Define to 1 if UPnP support should be compiled in.])
if test "$TARGET_OS" = "windows"; then
MINIUPNPC_CPPFLAGS="$MINIUPNPC_CPPFLAGS -DSTATICLIB -DMINIUPNP_STATICLIB"
fi
@@ -1797,15 +1785,8 @@ if test "$have_natpmp" = "no"; then
else
if test "$use_natpmp" != "no"; then
AC_MSG_RESULT([yes])
- AC_MSG_CHECKING([whether to build with NAT-PMP enabled by default])
use_natpmp=yes
- natpmp_setting=0
- if test "$use_natpmp_default" != "no"; then
- use_natpmp_default=yes
- natpmp_setting=1
- fi
- AC_MSG_RESULT($use_natpmp_default)
- AC_DEFINE_UNQUOTED([USE_NATPMP], [$natpmp_setting], [NAT-PMP support not compiled if undefined, otherwise value (0 or 1) determines default state])
+ AC_DEFINE([USE_NATPMP], [1], [Define to 1 if UPnP support should be compiled in.])
if test "$TARGET_OS" = "windows"; then
NATPMP_CPPFLAGS="$NATPMP_CPPFLAGS -DSTATICLIB -DNATPMP_STATICLIB"
fi
@@ -1874,7 +1855,7 @@ else
AC_MSG_RESULT([no])
fi
-if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nonononononononono"; then
+if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nononononononononono"; then
AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests])
fi
@@ -1988,10 +1969,6 @@ AC_SUBST(HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR)
AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/config.ini])
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])])
-AC_CONFIG_LINKS([contrib/devtools/security-check.py:contrib/devtools/security-check.py])
-AC_CONFIG_LINKS([contrib/devtools/symbol-check.py:contrib/devtools/symbol-check.py])
-AC_CONFIG_LINKS([contrib/devtools/test-security-check.py:contrib/devtools/test-security-check.py])
-AC_CONFIG_LINKS([contrib/devtools/test-symbol-check.py:contrib/devtools/test-symbol-check.py])
AC_CONFIG_LINKS([contrib/devtools/iwyu/bitcoin.core.imp:contrib/devtools/iwyu/bitcoin.core.imp])
AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py])
AC_CONFIG_LINKS([contrib/macdeploy/background.tiff:contrib/macdeploy/background.tiff])
@@ -2012,15 +1989,7 @@ CPPFLAGS_TEMP="$CPPFLAGS"
unset CPPFLAGS
CPPFLAGS="$CPPFLAGS_TEMP"
-LDFLAGS_TEMP="$LDFLAGS"
-unset LDFLAGS
-LDFLAGS="$LDFLAGS_TEMP"
-
-LIBS_TEMP="$LIBS"
-unset LIBS
-LIBS="$LIBS_TEMP"
-
-ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig"
+ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --disable-module-ecdh"
AC_CONFIG_SUBDIRS([src/secp256k1])
AC_OUTPUT
diff --git a/contrib/README.md b/contrib/README.md
index ae1372e95d..3c6e978061 100644
--- a/contrib/README.md
+++ b/contrib/README.md
@@ -26,9 +26,6 @@ The [Debian](/contrib/debian) subfolder contains the copyright file.
All other packaging related files can be found in the [bitcoin-core/packaging](https://github.com/bitcoin-core/packaging) repository.
-### [Builder keys](/contrib/builder-keys)
-PGP keys used for signing Bitcoin Core [release](/doc/release-process.md) results.
-
### [MacDeploy](/contrib/macdeploy) ###
Scripts and notes for Mac builds.
@@ -40,3 +37,9 @@ Utilities to generate test vectors for the data-driven Bitcoin tests.
### [Verify Binaries](/contrib/verifybinaries) ###
This script attempts to download and verify the signature file SHA256SUMS.asc from bitcoin.org.
+
+Command Line Tools
+---------------------
+
+### [Completions](/contrib/completions) ###
+Shell completions for bash and fish.
diff --git a/contrib/builder-keys/README.md b/contrib/builder-keys/README.md
deleted file mode 100644
index a6179d6012..0000000000
--- a/contrib/builder-keys/README.md
+++ /dev/null
@@ -1,33 +0,0 @@
-## PGP keys of builders and Developers
-
-The file `keys.txt` contains fingerprints of the public keys of builders and
-active developers.
-
-The associated keys are mainly used to sign git commits or the build results
-of Guix builds.
-
-The most recent version of each pgp key can be found on most pgp key servers.
-
-Fetch the latest version from the key server to see if any key was revoked in
-the meantime.
-To fetch the latest version of all pgp keys in your gpg homedir,
-
-```sh
-gpg --refresh-keys
-```
-
-To fetch keys of builders and active developers, feed the list of fingerprints
-of the primary keys into gpg:
-
-On \*NIX:
-```sh
-while read fingerprint keyholder_name; do gpg --keyserver hkps://keys.openpgp.org --recv-keys ${fingerprint}; done < ./keys.txt
-```
-
-On Windows (requires Gpg4win >= 4.0.0):
-```
-FOR /F "tokens=1" %i IN (keys.txt) DO gpg --keyserver hkps://keys.openpgp.org --recv-keys %i
-```
-
-Add your key to the list if you provided Guix attestations for two major or
-minor releases of Bitcoin Core.
diff --git a/contrib/builder-keys/keys.txt b/contrib/builder-keys/keys.txt
deleted file mode 100644
index f8377cce33..0000000000
--- a/contrib/builder-keys/keys.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-9D3CC86A72F8494342EA5FD10A41BDC3F4FAFF1C Aaron Clauson (sipsorcery)
-617C90010B3BD370B0AC7D424BB42E31C79111B8 Akira Takizawa (akx20000)
-E944AE667CF960B1004BC32FCA662BE18B877A60 Andreas Schildbach (aschildbach)
-152812300785C96444D3334D17565732E08E5E41 Andrew Chow (achow101)
-590B7292695AFFA5B672CBB2E13FC145CD3F4304 Antoine Poinsot (darosior)
-0AD83877C1F0CD1EE9BD660AD7CC770B81FD22A8 Ben Carman (benthecarman)
-912FD3228387123DC97E0E57D5566241A0295FA9 BtcDrak (btcdrak)
-04017A2A6D9A0CCDC81D8EC296AB007F1A7ED999 Carl Dong (dongcarl)
-C519EBCF3B926298946783EFF6430754120EC2F4 Christian Decker (cdecker)
-18AE2F798E0D239755DA4FD24B79F986CBDF8736 Chun Kuan Le (ken2812221)
-101598DC823C1B5F9A6624ABA5E0907A0380E6C3 CoinForensics (CoinForensics)
-F20F56EF6A067F70E8A5C99FFF95FAA971697405 centaur (centaur)
-C060A6635913D98A3587D7DB1C2491FFEB0EF770 Cory Fields (cfields)
-BF6273FAEF7CC0BA1F562E50989F6B3048A116B5 Dev Random (devrandom)
-6D3170C1DC2C6FD0AEEBCA6743811D1A26623924 Douglas Roark (droark)
-948444FCE03B05BA5AB0591EC37B1C1D44C786EE Duncan Dean (dunxen)
-1C6621605EC50319C463D56C7F81D87985D61612 Emanuele Cisbani (cisba)
-9A1689B60D1B3CCE9262307A2F40A9BF167FBA47 Erik Mossberg (erkmos)
-D35176BE9264832E4ACA8986BF0792FBE95DC863 fivepiece (fivepiece)
-6F993B250557E7B016ADE5713BDCDA2D87A881D9 Fuzzbawls (Fuzzbawls)
-01CDF4627A3B88AAE4A571C87588242FBE38D3A8 Gavin Andresen (gavinandresen)
-6B002C6EA3F91B1B0DF0C9BC8F617F1200A6D25C Gloria Zhao (glozow)
-D1DBF2C4B96F2DEBF4C16654410108112E7EA81F Hennadii Stepanov (hebasto)
-A2FD494D0021AA9B4FA58F759102B7AE654A4A5A Ilyas Ridhuan (IlyasRidhuan)
-2688F5A9A4BE0F295E921E8A25F27A38A47AD566 James O'Beirne (jamesob)
-D3F22A3A4C366C2DCB66D3722DA9C5A7FA81EA35 Jarol Rodriguez (jarolrod)
-7480909378D544EA6B6DCEB7535B12980BB8A4D3 Jeffri H Frontz (jhfrontz)
-D3CC177286005BB8FF673294C5242A1AB3936517 jl2012 (jl2012)
-82921A4B88FD454B7EB8CE3C796C4109063D4EAF Jon Atack (jonatack)
-32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC Jonas Schnelli (jonasschnelli)
-4B4E840451149DD7FB0D633477DFAB5C3108B9A8 Jorge Timon (jtimon)
-C42AFF7C61B3E44A1454CD3557AF762DB3353322 Karl-Johan Alm (kallewoof)
-70A1D47DD44F59DF8B22244333E472FE870C7E5D Kristaps Kaupe (kristapsk)
-30DE693AE0DE9E37B3E7EB6BBFF0F67810C1EED1 Lisa Neigut (niftynei)
-E463A93F5F3117EEDE6C7316BD02942421F4889F Luke Dashjr (luke-jr)
-B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B Marco Falke (marco)
-07DF3E57A548CCFB7530709189BBB8663E2E65CE Matt Corallo (BlueMatt)
-CA03882CB1FC067B5D3ACFE4D300116E1C875A3D MeshCollider (meshcollider)
-E777299FC265DD04793070EB944D35F9AC3DB76A Michael Ford (fanquake)
-AD5764F4ADCE1B99BDFD179E12335A271D4D62EC Michael Tidwell (miketwenty1)
-9692B91BBF0E8D34DFD33B1882C5C009628ECF0C Michagogo (michagogo)
-C57E4B42223FDE851D4F69DD28DF2724F241D8EE midnightmagic (midnightmagic)
-F4FC70F07310028424EFC20A8E4256593F177720 Oliver Gugger (guggero, Oliver Gugger)
-D62A803E27E7F43486035ADBBCD04D8E9CCCAC2A Paul Rabahy (prab)
-37EC7D7B0A217CDB4B4E007E7FAB114267E4FA04 Peter Todd (petertodd)
-D762373D24904A3E42F33B08B9A408E71DAAC974 Pieter Wuille [Location: Leuven, Belgium] (sipa)
-133EAC179436F14A5CF1B794860FEB804E669320 Pieter Wuille (sipa)
-6A8F9C266528E25AEB1D7731C2371D91CB716EA7 Sebastian Falbesoner (theStack)
-A8FC55F3B04BA3146F3492E79303B33A305224CB Sebastian Kung (TheCharlatan)
-ED9BDF7AD6A55E232E84524257FF9BDBCC301009 Sjors Provoost (sjors)
-867345026B6763E8B07EE73AB6737117397F5C4F Stephan Oeste (Emzy)
-9EDAFF80E080659604F4A76B2EBB056FD847F8A7 Stephan Oeste (Emzy)
-6DEEF79B050C4072509B743F8C275BC595448867 Tomas Kanocz (KanoczTomas)
-AEC1884398647C47413C1C3FB1179EB7347DC10D Warren Togami (wtogami)
-74E2DEF5D77260B98BC19438099BAD163C70FBFA Will Clark (will8clark)
-79D00BAC68B56D422F945A8F8E3A8F3247DBCBBF Willy Ko (willyko)
-71A3B16735405025D447E8F274810B012346C9A6 Wladimir J. van der Laan (laanwj)
diff --git a/contrib/bitcoin-cli.bash-completion b/contrib/completions/bash/bitcoin-cli.bash-completion
index ddea58a05c..89e01bc09a 100644
--- a/contrib/bitcoin-cli.bash-completion
+++ b/contrib/completions/bash/bitcoin-cli.bash-completion
@@ -1,5 +1,5 @@
# bash programmable completion for bitcoin-cli(1)
-# Copyright (c) 2012-2019 The Bitcoin Core developers
+# Copyright (c) 2012-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/bitcoin-tx.bash-completion b/contrib/completions/bash/bitcoin-tx.bash-completion
index a83d2979ed..51a9fe31cb 100644
--- a/contrib/bitcoin-tx.bash-completion
+++ b/contrib/completions/bash/bitcoin-tx.bash-completion
@@ -1,5 +1,5 @@
# bash programmable completion for bitcoin-tx(1)
-# Copyright (c) 2016 The Bitcoin Core developers
+# Copyright (c) 2016-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/bitcoind.bash-completion b/contrib/completions/bash/bitcoind.bash-completion
index ec1d9512d4..c11d99ef31 100644
--- a/contrib/bitcoind.bash-completion
+++ b/contrib/completions/bash/bitcoind.bash-completion
@@ -1,5 +1,5 @@
# bash programmable completion for bitcoind(1) and bitcoin-qt(1)
-# Copyright (c) 2012-2019 The Bitcoin Core developers
+# Copyright (c) 2012-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/completions/fish/bitcoin-cli.fish b/contrib/completions/fish/bitcoin-cli.fish
new file mode 100644
index 0000000000..2f034c475c
--- /dev/null
+++ b/contrib/completions/fish/bitcoin-cli.fish
@@ -0,0 +1,99 @@
+# Disable files from being included in completions by default
+complete --command bitcoin-cli --no-files
+
+function __fish_bitcoin_cli_get_commands_helper
+ set --local cmd (commandline -oc)
+
+ # Don't return commands if '-help or -?' in commandline
+ if string match --quiet --regex -- '^-help$|^-\?$' $cmd
+ return
+ end
+
+ # Strip help cmd from token to avoid duplication errors
+ set --local cmd (string match --invert --regex -- '^help$' $cmd)
+ # Strip -stdin* options to avoid waiting for input while we fetch completions
+ # TODO: this appears to be broken when run as tab completion (requires ctrl+c to exit)
+ set --local cmd (string match --invert --regex -- '^-stdin.*$' $cmd)
+
+ # Match, format and return commands
+ for command in ($cmd help 2>&1 | string match --invert -r '^\=\=.*' | string match --invert -r '^\\s*$')
+ echo $command
+ end
+end
+
+function __fish_bitcoin_cli_get_commands
+ argparse 'nohelp' 'commandsonly' -- $argv
+ set --local commands
+
+ # Exclude description, exclude help
+ if set -q _flag_nohelp; and set -q _flag_commandsonly
+ set --append commands (__fish_bitcoin_cli_get_commands_helper | string replace -r ' .*$' '' | string match --invert -r 'help')
+ # Include description, exclude help
+ else if set -q _flag_nohelp
+ set --append commands (__fish_bitcoin_cli_get_commands_helper | string replace ' ' \t | string match --invert -r 'help')
+ # Exclude description, include help
+ else if set -q _flag_commandsonly
+ set --append commands (__fish_bitcoin_cli_get_commands_helper | string replace -r ' .*$' '')
+ # Include description, include help
+ else
+ set --append commands (__fish_bitcoin_cli_get_commands_helper | string replace ' ' \t)
+ end
+
+ if string match -q -r '^.*error.*$' $commands[1]
+ # RPC offline or RPC wallet not loaded
+ return
+ else
+ for command in $commands
+ echo $command
+ end
+ end
+end
+
+
+function __fish_bitcoin_cli_get_options
+ argparse 'nofiles' -- $argv
+ set --local cmd (commandline -oc)
+ # Don't return options if '-help or -?' in commandline
+ if string match --quiet --regex -- '^-help$|-\?$' $cmd
+ return
+ end
+ set --local options
+
+ if set -q _flag_nofiles
+ set --append options ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match --invert -r '^.*=$')
+ else
+ set --append options ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match -r '^.*=$')
+ end
+
+ for option in $options
+ echo $option
+ end
+end
+
+# Add options with file completion
+# Don't offer after a command is given
+complete \
+ --command bitcoin-cli \
+ --no-files \
+ --condition "not __fish_seen_subcommand_from (__fish_bitcoin_cli_get_commands --commandsonly)" \
+ --arguments "(__fish_bitcoin_cli_get_options)"
+# Enable file completions only if the commandline now contains a `*.=` style option
+complete --command bitcoin-cli \
+ --condition 'string match --regex -- ".*=" (commandline -pt)' \
+ --force-files
+
+# Add options without file completion
+# Don't offer after a command is given
+complete \
+ --command bitcoin-cli \
+ --no-files \
+ --condition "not __fish_seen_subcommand_from (__fish_bitcoin_cli_get_commands --commandsonly)" \
+ --arguments "(__fish_bitcoin_cli_get_options --nofiles)"
+
+# Add commands
+# Permit command completions after `bitcoin-cli help` but not after other commands
+complete \
+ --command bitcoin-cli \
+ --no-files \
+ --condition "not __fish_seen_subcommand_from (__fish_bitcoin_cli_get_commands --commandsonly --nohelp)" \
+ --arguments "(__fish_bitcoin_cli_get_commands)"
diff --git a/contrib/completions/fish/bitcoin-qt.fish b/contrib/completions/fish/bitcoin-qt.fish
new file mode 100644
index 0000000000..15a355ae88
--- /dev/null
+++ b/contrib/completions/fish/bitcoin-qt.fish
@@ -0,0 +1,35 @@
+# Disable files from being included in completions by default
+complete --command bitcoin-qt --no-files
+
+# Extract options
+function __fish_bitcoinqt_get_options
+ argparse 'nofiles' -- $argv
+ set --local cmd (commandline -opc)[1]
+ set --local options
+
+ if set -q _flag_nofiles
+ set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match --invert -r '^.*=$')
+ else
+ set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match -r '^.*=$')
+ end
+
+ for option in $options
+ echo $option
+ end
+end
+
+
+# Add options with file completion
+complete \
+ --command bitcoin-qt \
+ --arguments "(__fish_bitcoinqt_get_options)"
+# Enable file completions only if the commandline now contains a `*.=` style option
+complete -c bitcoin-qt \
+ --condition 'string match --regex -- ".*=" (commandline -pt)' \
+ --force-files
+
+# Add options without file completion
+complete \
+ --command bitcoin-qt \
+ --arguments "(__fish_bitcoinqt_get_options --nofiles)"
+
diff --git a/contrib/completions/fish/bitcoin-tx.fish b/contrib/completions/fish/bitcoin-tx.fish
new file mode 100644
index 0000000000..0ff262b948
--- /dev/null
+++ b/contrib/completions/fish/bitcoin-tx.fish
@@ -0,0 +1,65 @@
+# Disable files from being included in completions by default
+complete --command bitcoin-tx --no-files
+
+# Modified version of __fish_seen_subcommand_from
+# Uses regex to detect cmd= syntax
+function __fish_bitcoin_seen_cmd
+ set -l cmd (commandline -oc)
+ set -e cmd[1]
+ for i in $cmd
+ for j in $argv
+ if string match --quiet --regex -- "^$j.*" $i
+ return 0
+ end
+ end
+ end
+ return 1
+end
+
+# Extract options
+function __fish_bitcoin_tx_get_options
+ set --local cmd (commandline -oc)[1]
+ if string match --quiet --regex -- '^-help$|-\?$' $cmd
+ return
+ end
+
+ for option in ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=')
+ echo $option
+ end
+end
+
+# Extract commands
+function __fish_bitcoin_tx_get_commands
+ argparse 'commandsonly' -- $argv
+ set --local cmd (commandline -oc)[1]
+ set --local commands
+
+ if set -q _flag_commandsonly
+ set --append commands ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '' | string replace -r '=.*' '')
+ else
+ set --append commands ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '')
+ end
+
+ for command in $commands
+ echo $command
+ end
+end
+
+# Add options
+complete \
+ --command bitcoin-tx \
+ --condition "not __fish_bitcoin_seen_cmd (__fish_bitcoin_tx_get_commands --commandsonly)" \
+ --arguments "(__fish_bitcoin_tx_get_options)" \
+ --no-files
+
+# Add commands
+complete \
+ --command bitcoin-tx \
+ --arguments "(__fish_bitcoin_tx_get_commands)" \
+ --no-files
+
+# Add file completions for load and set commands
+complete \
+ --command bitcoin-tx \
+ --condition 'string match --regex -- "(load|set)=" (commandline -pt)' \
+ --force-files
diff --git a/contrib/completions/fish/bitcoin-util.fish b/contrib/completions/fish/bitcoin-util.fish
new file mode 100644
index 0000000000..0650bf2cb6
--- /dev/null
+++ b/contrib/completions/fish/bitcoin-util.fish
@@ -0,0 +1,38 @@
+# Disable files from being included in completions by default
+complete --command bitcoin-util --no-files
+
+# Extract options
+function __fish_bitcoin_util_get_options
+ set --local cmd (commandline -opc)[1]
+ set --local options
+
+ set --append options ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=')
+
+ for option in $options
+ echo $option
+ end
+end
+
+# Extract commands
+function __fish_bitcoin_util_get_commands
+ set --local cmd (commandline -opc)[1]
+ set --local commands
+
+ set --append commands ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '')
+ for command in $commands
+ echo $command
+ end
+end
+
+# Add options
+complete \
+ --command bitcoin-util \
+ --condition "not __fish_seen_subcommand_from (__fish_bitcoin_util_get_commands)" \
+ --arguments "(__fish_bitcoin_util_get_options)"
+
+# Add commands
+complete \
+ --command bitcoin-util \
+ --condition "not __fish_seen_subcommand_from (__fish_bitcoin_util_get_commands)" \
+ --arguments "(__fish_bitcoin_util_get_commands)"
+
diff --git a/contrib/completions/fish/bitcoin-wallet.fish b/contrib/completions/fish/bitcoin-wallet.fish
new file mode 100644
index 0000000000..82d8277c9b
--- /dev/null
+++ b/contrib/completions/fish/bitcoin-wallet.fish
@@ -0,0 +1,35 @@
+# Disable files from being included in completions by default
+complete --command bitcoin-wallet --no-files
+
+# Extract options
+function __fish_bitcoin_wallet_get_options
+ set --local cmd (commandline -opc)[1]
+ for option in ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=')
+ echo $option
+ end
+end
+
+# Extract commands
+function __fish_bitcoin_wallet_get_commands
+ set --local cmd (commandline -opc)[1]
+ for command in ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '')
+ echo $command
+ end
+end
+
+# Add options
+complete \
+ --command bitcoin-wallet \
+ --condition "not __fish_seen_subcommand_from (__fish_bitcoin_wallet_get_commands)" \
+ --arguments "(__fish_bitcoin_wallet_get_options)"
+
+# Add commands
+complete \
+ --command bitcoin-wallet \
+ --condition "not __fish_seen_subcommand_from (__fish_bitcoin_wallet_get_commands)" \
+ --arguments "(__fish_bitcoin_wallet_get_commands)"
+
+# Add file completions for load and set commands
+complete --command bitcoin-wallet \
+ --condition "string match -r -- '(dumpfile|datadir)*=' (commandline -pt)" \
+ --force-files
diff --git a/contrib/completions/fish/bitcoind.fish b/contrib/completions/fish/bitcoind.fish
new file mode 100644
index 0000000000..fa245ae17f
--- /dev/null
+++ b/contrib/completions/fish/bitcoind.fish
@@ -0,0 +1,35 @@
+# Disable files from being included in completions by default
+complete --command bitcoind --no-files
+
+# Extract options
+function __fish_bitcoind_get_options
+ argparse 'nofiles' -- $argv
+ set --local cmd (commandline -opc)[1]
+ set --local options
+
+ if set -q _flag_nofiles
+ set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match --invert -r '^.*=$')
+ else
+ set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match -r '^.*=$')
+ end
+
+ for option in $options
+ echo $option
+ end
+end
+
+
+# Add options with file completion
+complete \
+ --command bitcoind \
+ --arguments "(__fish_bitcoind_get_options)"
+# Enable file completions only if the commandline now contains a `*.=` style option
+complete --command bitcoind \
+ --condition 'string match --regex -- ".*=" (commandline -pt)' \
+ --force-files
+
+# Add options without file completion
+complete \
+ --command bitcoind \
+ --arguments "(__fish_bitcoind_get_options --nofiles)"
+
diff --git a/contrib/debian/copyright b/contrib/debian/copyright
index 95a281ce05..ca430170a1 100644
--- a/contrib/debian/copyright
+++ b/contrib/debian/copyright
@@ -5,24 +5,16 @@ Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com>
Source: https://github.com/bitcoin/bitcoin
Files: *
-Copyright: 2009-2022, Bitcoin Core Developers
+Copyright: 2009-2023, Bitcoin Core Developers
License: Expat
-Comment: The Bitcoin Core Developers encompasses the current developers listed on bitcoin.org,
- as well as the numerous contributors to the project.
+Comment: The Bitcoin Core Developers encompasses all contributors to the
+ project, listed in the release notes or the git log.
Files: debian/*
Copyright: 2010-2011, Jonas Smedegaard <dr@jones.dk>
2011, Matt Corallo <matt@bluematt.me>
License: GPL-2+
-Files: src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
-Copyright: 2008 Don Anderson <dda@sleepycat.com>
-License: GNU-All-permissive-License
-
-Files: src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4
-Copyright: 2008 Paolo Bonzini <bonzini@gnu.org>
-License: GNU-All-permissive-License
-
Files: src/qt/res/icons/add.png
src/qt/res/icons/address-book.png
src/qt/res/icons/chevron.png
@@ -112,12 +104,6 @@ License: Expat
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-License: GNU-All-permissive-License
- Copying and distribution of this file, with or without modification, are
- permitted in any medium without royalty provided the copyright notice
- and this notice are preserved. This file is offered as-is, without any
- warranty.
-
License: GPL-2+
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py
index 98eee67f43..420bf7ff33 100755
--- a/contrib/devtools/clang-format-diff.py
+++ b/contrib/devtools/clang-format-diff.py
@@ -146,7 +146,7 @@ def main():
stdout=subprocess.PIPE,
stderr=None,
stdin=subprocess.PIPE,
- universal_newlines=True)
+ text=True)
stdout, stderr = p.communicate()
if p.returncode != 0:
sys.exit(p.returncode)
diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py
index 680de1f1b3..3dddffe324 100755
--- a/contrib/devtools/copyright_header.py
+++ b/contrib/devtools/copyright_header.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/devtools/gen-manpages.py b/contrib/devtools/gen-manpages.py
index 38cdb3acb8..2860e7db99 100755
--- a/contrib/devtools/gen-manpages.py
+++ b/contrib/devtools/gen-manpages.py
@@ -23,7 +23,7 @@ help2man = os.getenv('HELP2MAN', 'help2man')
# If not otherwise specified, get top directory from git.
topdir = os.getenv('TOPDIR')
if not topdir:
- r = subprocess.run([git, 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE, check=True, universal_newlines=True)
+ r = subprocess.run([git, 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE, check=True, text=True)
topdir = r.stdout.rstrip()
# Get input and output directories.
@@ -36,7 +36,7 @@ versions = []
for relpath in BINARIES:
abspath = os.path.join(builddir, relpath)
try:
- r = subprocess.run([abspath, "--version"], stdout=subprocess.PIPE, check=True, universal_newlines=True)
+ r = subprocess.run([abspath, "--version"], stdout=subprocess.PIPE, check=True, text=True)
except IOError:
print(f'{abspath} not found or not an executable', file=sys.stderr)
sys.exit(1)
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 05c0af029e..6cd022ef17 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
@@ -34,7 +34,7 @@ def check_ELF_RELRO(binary) -> bool:
flags = binary.get(lief.ELF.DYNAMIC_TAGS.FLAGS)
if flags.value & lief.ELF.DYNAMIC_FLAGS.BIND_NOW:
have_bindnow = True
- except:
+ except Exception:
have_bindnow = False
return have_gnu_relro and have_bindnow
@@ -146,6 +146,12 @@ def check_PE_control_flow(binary) -> bool:
return True
return False
+def check_PE_Canary(binary) -> bool:
+ '''
+ Check for use of stack canary
+ '''
+ return binary.has_symbol('__stack_chk_fail')
+
def check_MACHO_NOUNDEFS(binary) -> bool:
'''
Check for no undefined references.
@@ -203,6 +209,7 @@ BASE_PE = [
('NX', check_NX),
('RELOC_SECTION', check_PE_RELOC_SECTION),
('CONTROL_FLOW', check_PE_control_flow),
+ ('Canary', check_PE_Canary),
]
BASE_MACHO = [
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 4b1cceb57c..f26236dd59 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -15,19 +15,19 @@ from typing import List, Dict
import lief #type:ignore
-# Debian 9 (Stretch) EOL: 2022. https://wiki.debian.org/DebianReleases#Production_Releases
+# Debian 10 (Buster) EOL: 2024. https://wiki.debian.org/LTS
#
-# - g++ version 6.3.0 (https://packages.debian.org/search?suite=stretch&arch=any&searchon=names&keywords=g%2B%2B)
-# - libc version 2.24 (https://packages.debian.org/search?suite=stretch&arch=any&searchon=names&keywords=libc6)
+# - libgcc version 8.3.0 (https://packages.debian.org/search?suite=buster&arch=any&searchon=names&keywords=libgcc1)
+# - libc version 2.28 (https://packages.debian.org/search?suite=buster&arch=any&searchon=names&keywords=libc6)
#
-# Ubuntu 16.04 (Xenial) EOL: 2026. https://wiki.ubuntu.com/Releases
+# Ubuntu 18.04 (Bionic) EOL: 2028. https://wiki.ubuntu.com/ReleaseTeam
#
-# - g++ version 5.3.1
-# - libc version 2.23
+# - libgcc version 8.4.0 (https://packages.ubuntu.com/bionic/libgcc1)
+# - libc version 2.27 (https://packages.ubuntu.com/bionic/libc6)
#
# CentOS Stream 8 EOL: 2024. https://wiki.centos.org/About/Product
#
-# - g++ version 8.5.0 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/)
+# - libgcc version 8.5.0 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/)
# - libc version 2.28 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/)
#
# See https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html for more info.
@@ -35,10 +35,10 @@ import lief #type:ignore
MAX_VERSIONS = {
'GCC': (4,8,0),
'GLIBC': {
- lief.ELF.ARCH.x86_64: (2,18),
- lief.ELF.ARCH.ARM: (2,18),
- lief.ELF.ARCH.AARCH64:(2,18),
- lief.ELF.ARCH.PPC64: (2,18),
+ lief.ELF.ARCH.x86_64: (2,27),
+ lief.ELF.ARCH.ARM: (2,27),
+ lief.ELF.ARCH.AARCH64:(2,27),
+ lief.ELF.ARCH.PPC64: (2,27),
lief.ELF.ARCH.RISCV: (2,27),
},
'LIBATOMIC': (1,0),
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index d3d225f3ab..54718fd7a1 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
@@ -39,7 +39,7 @@ def call_security_check(cc, source, executable, options):
env_flags += filter(None, os.environ.get(var, '').split(' '))
subprocess.run([*cc,source,'-o',executable] + env_flags + options, check=True)
- p = subprocess.run(['./contrib/devtools/security-check.py',executable], stdout=subprocess.PIPE, universal_newlines=True)
+ p = subprocess.run([os.path.join(os.path.dirname(__file__), 'security-check.py'), executable], stdout=subprocess.PIPE, text=True)
return (p.returncode, p.stdout.rstrip())
def get_arch(cc, source, executable):
@@ -94,19 +94,19 @@ class TestSecurityChecks(unittest.TestCase):
cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc')
write_testcode(source)
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--disable-nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE']),
- (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--disable-nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fno-stack-protector']),
+ (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION CONTROL_FLOW Canary'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fstack-protector-all', '-lssp']),
(1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA RELOC_SECTION CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fstack-protector-all', '-lssp']),
(1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']),
(1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW')) # -pie -fPIE does nothing unless --dynamicbase is also supplied
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']),
(1, executable+': failed HIGH_ENTROPY_VA CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']),
(1, executable+': failed CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE', '-fcf-protection=full']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE', '-fcf-protection=full','-fstack-protector-all', '-lssp']),
(0, ''))
clean_files(source, executable)
diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py
index 2881e3efac..e304880140 100755
--- a/contrib/devtools/test-symbol-check.py
+++ b/contrib/devtools/test-symbol-check.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
@@ -23,13 +23,13 @@ def call_symbol_check(cc: List[str], source, executable, options):
env_flags += filter(None, os.environ.get(var, '').split(' '))
subprocess.run([*cc,source,'-o',executable] + env_flags + options, check=True)
- p = subprocess.run(['./contrib/devtools/symbol-check.py',executable], stdout=subprocess.PIPE, universal_newlines=True)
+ p = subprocess.run([os.path.join(os.path.dirname(__file__), 'symbol-check.py'), executable], stdout=subprocess.PIPE, text=True)
os.remove(source)
os.remove(executable)
return (p.returncode, p.stdout.rstrip())
def get_machine(cc: List[str]):
- p = subprocess.run([*cc,'-dumpmachine'], stdout=subprocess.PIPE, universal_newlines=True)
+ p = subprocess.run([*cc,'-dumpmachine'], stdout=subprocess.PIPE, text=True)
return p.stdout.rstrip()
class TestSymbolChecks(unittest.TestCase):
@@ -38,31 +38,6 @@ class TestSymbolChecks(unittest.TestCase):
executable = 'test1'
cc = determine_wellknown_cmd('CC', 'gcc')
- # there's no way to do this test for RISC-V at the moment; we build for
- # RISC-V in a glibc 2.27 environment and we allow all symbols from 2.27.
- if 'riscv' in get_machine(cc):
- self.skipTest("test not available for RISC-V")
-
- # nextup was introduced in GLIBC 2.24, so is newer than our supported
- # glibc (2.18), and available in our release build environment (2.24).
- with open(source, 'w', encoding="utf8") as f:
- f.write('''
- #define _GNU_SOURCE
- #include <math.h>
-
- double nextup(double x);
-
- int main()
- {
- nextup(3.14);
- return 0;
- }
- ''')
-
- self.assertEqual(call_symbol_check(cc, source, executable, ['-lm']),
- (1, executable + ': symbol nextup from unsupported version GLIBC_2.24(3)\n' +
- executable + ': failed IMPORTED_SYMBOLS'))
-
# -lutil is part of the libc6 package so a safe bet that it's installed
# it's also out of context enough that it's unlikely to ever become a real dependency
source = 'test2.c'
diff --git a/contrib/guix/INSTALL.md b/contrib/guix/INSTALL.md
index a9a41ddff6..bbd88e58f3 100644
--- a/contrib/guix/INSTALL.md
+++ b/contrib/guix/INSTALL.md
@@ -167,6 +167,10 @@ For reference, the graphic below outlines Guix v1.3.0's dependency graph:
![bootstrap map](https://user-images.githubusercontent.com/6399679/125064185-a9a59880-e0b0-11eb-82c1-9b8e5dc9950d.png)
+#### Consider /tmp on tmpfs
+
+If you use an NVME (SSD) drive, you may encounter [cryptic build errors](#coreutils-fail-teststail-2inotify-dir-recreate). Mounting a [tmpfs at /tmp](https://ubuntu.com/blog/data-driven-analysis-tmp-on-tmpfs) should prevent this and may improve performance as a bonus.
+
#### Guile
##### Choosing a Guile version and sticking to it
@@ -334,6 +338,8 @@ packages in Debian at the time of writing.
|-----------------------|---------------------|
| guile-gcrypt | libgcrypt-dev |
| guile-git | libgit2-dev |
+| guile-gnutls | (none) |
+| guile-json | (none) |
| guile-lzlib | liblz-dev |
| guile-ssh | libssh-dev |
| guile-sqlite3 | libsqlite3-dev |
@@ -384,8 +390,9 @@ cd guix
```
You will likely want to build the latest release, however, if the latest release
-when you're reading this is still 1.2.0 then you may want to use 95aca29 instead
-to avoid a problem in the GnuTLS test suite.
+when you're reading this is still 1.3.0 then you may want to use 998eda30 instead
+to avoid the issues described in [#25099](
+https://github.com/bitcoin/bitcoin/pull/25099).
```
git branch -a -l 'origin/version-*' # check for the latest release
@@ -609,6 +616,8 @@ systemctl enable guix-daemon
systemctl start guix-daemon
```
+Remember to set `--no-substitute` in `$libdir/systemd/system/guix-daemon.service` and other customizations if you used them for `guix-daemon-original.service`.
+
##### If you installed Guix via the Debian/Ubuntu distribution packages
You will need to create a `guix-daemon-latest` service which points to the new
@@ -717,6 +726,19 @@ $ bzcat /var/log/guix/drvs/../...-foo-3.6.12.drv.bz2 | less
times, it may be `/tmp/...drv-1` or `/tmp/...drv-2`. Always consult the build
failure output for the most accurate, up-to-date information.
+### openssl-1.1.1l and openssl-1.1.1n
+
+OpenSSL includes tests that will fail once some certificate has expired. A workaround
+is to change your system clock:
+
+```sh
+sudo timedatectl set-ntp no
+sudo date --set "28 may 2022 15:00:00"
+sudo --login guix build --cores=1 /gnu/store/g9alz81w4q03ncm542487xd001s6akd4-openssl-1.1.1l.drv
+sudo --login guix build --cores=1 /gnu/store/mw6ax0gk33gh082anrdrxp2flrbskxv6-openssl-1.1.1n.drv
+sudo timedatectl set-ntp yes
+```
+
### python(-minimal): [Errno 84] Invalid or incomplete multibyte or wide character
This error occurs when your `$TMPDIR` (default: /tmp) exists on a filesystem
@@ -774,7 +796,7 @@ The inotify-dir-create test fails on "remote" filesystems such as overlayfs
as non-remote.
A relatively easy workaround to this is to make sure that a somewhat traditional
-filesystem is mounted at `/tmp` (where `guix-daemon` performs its builds). For
+filesystem is mounted at `/tmp` (where `guix-daemon` performs its builds), see [/tmp on tmpfs](#consider-tmp-on-tmpfs). For
Docker users, this might mean [using a volume][docker/volumes], [binding
mounting][docker/bind-mnt] from host, or (for those with enough RAM and swap)
[mounting a tmpfs][docker/tmpfs] using the `--tmpfs` flag.
@@ -782,7 +804,7 @@ mounting][docker/bind-mnt] from host, or (for those with enough RAM and swap)
Please see the following links for more details:
- An upstream coreutils bug has been filed: [debbugs#47940](https://debbugs.gnu.org/cgi/bugreport.cgi?bug=47940)
-- A Guix bug detailing the underlying problem has been filed: [guix-issues#47935](https://issues.guix.gnu.org/47935)
+- A Guix bug detailing the underlying problem has been filed: [guix-issues#47935](https://issues.guix.gnu.org/47935), [guix-issues#49985](https://issues.guix.gnu.org/49985#5)
- A commit to skip this test in Guix has been merged into the core-updates branch:
[savannah/guix@6ba1058](https://git.savannah.gnu.org/cgit/guix.git/commit/?id=6ba1058df0c4ce5611c2367531ae5c3cdc729ab4)
@@ -799,3 +821,39 @@ Please see the following links for more details:
[docker/volumes]: https://docs.docker.com/storage/volumes/
[docker/bind-mnt]: https://docs.docker.com/storage/bind-mounts/
[docker/tmpfs]: https://docs.docker.com/storage/tmpfs/
+
+# Purging/Uninstalling Guix
+
+In the extraordinarily rare case where you messed up your Guix installation in
+an irreversible way, you may want to completely purge Guix from your system and
+start over.
+
+1. Uninstall Guix itself according to the way you installed it (e.g. `sudo apt
+ purge guix` for Ubuntu packaging, `sudo make uninstall` for a build from source).
+2. Remove all build users and groups
+
+ You may check for relevant users and groups using:
+
+ ```
+ getent passwd | grep guix
+ getent group | grep guix
+ ```
+
+ Then, you may remove users and groups using:
+
+ ```
+ sudo userdel <user>
+ sudo groupdel <group>
+ ```
+
+3. Remove all possible Guix-related directories
+ - `/var/guix/`
+ - `/var/log/guix/`
+ - `/gnu/`
+ - `/etc/guix/`
+ - `/home/*/.config/guix/`
+ - `/home/*/.cache/guix/`
+ - `/home/*/.guix-profile/`
+ - `/root/.config/guix/`
+ - `/root/.cache/guix/`
+ - `/root/.guix-profile/`
diff --git a/contrib/guix/README.md b/contrib/guix/README.md
index ed6ac8d589..c0feb486ff 100644
--- a/contrib/guix/README.md
+++ b/contrib/guix/README.md
@@ -430,55 +430,6 @@ used.
If you start `guix-daemon` using an init script, you can edit said script to
supply this flag.
-
-# Purging/Uninstalling Guix
-
-In the extraordinarily rare case where you messed up your Guix installation in
-an irreversible way, you may want to completely purge Guix from your system and
-start over.
-
-1. Uninstall Guix itself according to the way you installed it (e.g. `sudo apt
- purge guix` for Ubuntu packaging, `sudo make uninstall` for a build from source).
-2. Remove all build users and groups
-
- You may check for relevant users and groups using:
-
- ```
- getent passwd | grep guix
- getent group | grep guix
- ```
-
- Then, you may remove users and groups using:
-
- ```
- sudo userdel <user>
- sudo groupdel <group>
- ```
-
-3. Remove all possible Guix-related directories
- - `/var/guix/`
- - `/var/log/guix/`
- - `/gnu/`
- - `/etc/guix/`
- - `/home/*/.config/guix/`
- - `/home/*/.cache/guix/`
- - `/home/*/.guix-profile/`
- - `/root/.config/guix/`
- - `/root/.cache/guix/`
- - `/root/.guix-profile/`
-
[b17e]: https://bootstrappable.org/
[r12e/source-date-epoch]: https://reproducible-builds.org/docs/source-date-epoch/
-
-[guix/install.sh]: https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh
-[guix/bin-install]: https://www.gnu.org/software/guix/manual/en/html_node/Binary-Installation.html
-[guix/env-setup]: https://www.gnu.org/software/guix/manual/en/html_node/Build-Environment-Setup.html
-[guix/substitutes]: https://www.gnu.org/software/guix/manual/en/html_node/Substitutes.html
-[guix/substitute-server-auth]: https://www.gnu.org/software/guix/manual/en/html_node/Substitute-Server-Authorization.html
-[guix/time-machine]: https://guix.gnu.org/manual/en/html_node/Invoking-guix-time_002dmachine.html
-
-[debian/guix-bullseye]: https://packages.debian.org/bullseye/guix
-[ubuntu/guix-hirsute]: https://packages.ubuntu.com/hirsute/guix
-[fanquake/guix-docker]: https://github.com/fanquake/core-review/tree/master/guix
-
[env-vars-list]: #recognized-environment-variables
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index f39f83d443..08a6c72a95 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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
@@ -69,16 +69,12 @@ unset CPLUS_INCLUDE_PATH
unset OBJC_INCLUDE_PATH
unset OBJCPLUS_INCLUDE_PATH
-export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC}/lib64:${NATIVE_GCC_STATIC}/lib:${NATIVE_GCC_STATIC}/lib64"
+export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC_STATIC}/lib"
export C_INCLUDE_PATH="${NATIVE_GCC}/include"
export CPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include"
export OBJC_INCLUDE_PATH="${NATIVE_GCC}/include"
export OBJCPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include"
-prepend_to_search_env_var() {
- export "${1}=${2}${!1:+:}${!1}"
-}
-
# Set environment variables to point the CROSS toolchain to the right
# includes/libs for $HOST
case "$HOST" in
@@ -242,13 +238,6 @@ case "$HOST" in
*mingw*) HOST_LDFLAGS="-Wl,--no-insert-timestamp" ;;
esac
-# Using --no-tls-get-addr-optimize retains compatibility with glibc 2.18, by
-# avoiding a PowerPC64 optimisation available in glibc 2.22 and later.
-# https://sourceware.org/binutils/docs-2.35/ld/PowerPC64-ELF64.html
-case "$HOST" in
- *powerpc64*) HOST_LDFLAGS="${HOST_LDFLAGS} -Wl,--no-tls-get-addr-optimize" ;;
-esac
-
# Make $HOST-specific native binaries from depends available in $PATH
export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
mkdir -p "$DISTSRC"
diff --git a/contrib/guix/libexec/codesign.sh b/contrib/guix/libexec/codesign.sh
index 9a5d3a1ce5..f6322d761c 100755
--- a/contrib/guix/libexec/codesign.sh
+++ b/contrib/guix/libexec/codesign.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 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
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 8e5c89cc5e..dc42563cdd 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -139,15 +139,17 @@ chain for " target " development."))
;; https://gcc.gnu.org/install/configure.html
(define (hardened-gcc gcc)
(package-with-extra-configure-variable (
- package-with-extra-configure-variable gcc
- "--enable-default-ssp" "yes")
- "--enable-default-pie" "yes"))
+ package-with-extra-configure-variable (
+ package-with-extra-configure-variable gcc
+ "--enable-initfini-array" "yes")
+ "--enable-default-ssp" "yes")
+ "--enable-default-pie" "yes"))
(define* (make-bitcoin-cross-toolchain target
#:key
(base-gcc-for-libc base-gcc)
(base-kernel-headers base-linux-kernel-headers)
- (base-libc (make-glibc-with-bind-now (make-glibc-without-werror glibc-2.24)))
+ (base-libc (hardened-glibc (make-glibc-without-werror glibc-2.27)))
(base-gcc (make-gcc-rpath-link (hardened-gcc base-gcc))))
"Convenience wrapper around MAKE-CROSS-TOOLCHAIN with default values
desirable for building Bitcoin Core release binaries."
@@ -537,33 +539,14 @@ inspecting signatures in Mach-O binaries.")
(define (make-glibc-without-werror glibc)
(package-with-extra-configure-variable glibc "enable_werror" "no"))
-(define (make-glibc-with-stack-protector glibc)
- (package-with-extra-configure-variable glibc "--enable-stack-protector" "all"))
-
-(define (make-glibc-with-bind-now glibc)
- (package-with-extra-configure-variable glibc "--enable-bind-now" "yes"))
-
-(define-public glibc-2.24
- (package
- (inherit glibc-2.31)
- (version "2.24")
- (source (origin
- (method git-fetch)
- (uri (git-reference
- (url "https://sourceware.org/git/glibc.git")
- (commit "0d7f1ed30969886c8dde62fbf7d2c79967d4bace")))
- (file-name (git-file-name "glibc" "0d7f1ed30969886c8dde62fbf7d2c79967d4bace"))
- (sha256
- (base32
- "0g5hryia5v1k0qx97qffgwzrz4lr4jw3s5kj04yllhswsxyjbic3"))
- (patches (search-our-patches "glibc-ldd-x86_64.patch"
- "glibc-versioned-locpath.patch"
- "glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch"
- "glibc-2.24-no-build-time-cxx-header-run.patch"
- "glibc-2.24-fcommon.patch"
- "glibc-2.24-guix-prefix.patch"))))))
+;; https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html
+(define (hardened-glibc glibc)
+ (package-with-extra-configure-variable (
+ package-with-extra-configure-variable glibc
+ "--enable-stack-protector" "all")
+ "--enable-bind-now" "yes"))
-(define-public glibc-2.27/bitcoin-patched
+(define-public glibc-2.27
(package
(inherit glibc-2.31)
(version "2.27")
@@ -571,22 +554,23 @@ inspecting signatures in Mach-O binaries.")
(method git-fetch)
(uri (git-reference
(url "https://sourceware.org/git/glibc.git")
- (commit "23158b08a0908f381459f273a984c6fd328363cb")))
- (file-name (git-file-name "glibc" "23158b08a0908f381459f273a984c6fd328363cb"))
+ (commit "73886db6218e613bd6d4edf529f11e008a6c2fa6")))
+ (file-name (git-file-name "glibc" "73886db6218e613bd6d4edf529f11e008a6c2fa6"))
(sha256
(base32
- "1b2n1gxv9f4fd5yy68qjbnarhf8mf4vmlxk10i3328c1w5pmp0ca"))
+ "0azpb9cvnbv25zg8019rqz48h8i2257ngyjg566dlnp74ivrs9vq"))
(patches (search-our-patches "glibc-ldd-x86_64.patch"
+ "glibc-versioned-locpath.patch"
"glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch"
- "glibc-2.27-dont-redefine-nss-database.patch"
+ "glibc-2.27-fcommon.patch"
"glibc-2.27-guix-prefix.patch"))))))
(packages->manifest
(append
(list ;; The Basics
- bash
+ bash-minimal
which
- coreutils
+ coreutils-minimal
util-linux
;; File(system) inspection
file
@@ -627,12 +611,7 @@ inspecting signatures in Mach-O binaries.")
(make-nsis-for-gcc-10 nsis-x86_64)
osslsigncode))
((string-contains target "-linux-")
- (list (cond ((string-contains target "riscv64-")
- (make-bitcoin-cross-toolchain target
- #:base-libc (make-glibc-with-stack-protector
- (make-glibc-with-bind-now (make-glibc-without-werror glibc-2.27/bitcoin-patched)))))
- (else
- (make-bitcoin-cross-toolchain target)))))
+ (list (make-bitcoin-cross-toolchain target)))
((string-contains target "darwin")
- (list clang-toolchain-10 binutils cmake xorriso python-signapple))
+ (list clang-toolchain-10 binutils cmake-minimal xorriso python-signapple))
(else '())))))
diff --git a/contrib/guix/patches/glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch b/contrib/guix/patches/glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch
deleted file mode 100644
index 5c4d0c6ebe..0000000000
--- a/contrib/guix/patches/glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-https://sourceware.org/git/?p=glibc.git;a=commit;h=a68ba2f3cd3cbe32c1f31e13c20ed13487727b32
-
-commit 6b02af31e9a721bb15a11380cd22d53b621711f8
-Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
-Date: Wed Oct 18 17:26:23 2017 +0100
-
- [AARCH64] Rewrite elf_machine_load_address using _DYNAMIC symbol
-
- This patch rewrites aarch64 elf_machine_load_address to use special _DYNAMIC
- symbol instead of _dl_start.
-
- The static address of _DYNAMIC symbol is stored in the first GOT entry.
- Here is the change which makes this solution work (part of binutils 2.24):
- https://sourceware.org/ml/binutils/2013-06/msg00248.html
-
- i386, x86_64 targets use the same method to do this as well.
-
- The original implementation relies on a trick that R_AARCH64_ABS32 relocation
- being resolved at link time and the static address fits in the 32bits.
- However, in LP64, normally, the address is defined to be 64 bit.
-
- Here is the C version one which should be portable in all cases.
-
- * sysdeps/aarch64/dl-machine.h (elf_machine_load_address): Use
- _DYNAMIC symbol to calculate load address.
-
-diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
-index e86d8b5b63..5a5b8a5de5 100644
---- a/sysdeps/aarch64/dl-machine.h
-+++ b/sysdeps/aarch64/dl-machine.h
-@@ -49,26 +49,11 @@ elf_machine_load_address (void)
- /* To figure out the load address we use the definition that for any symbol:
- dynamic_addr(symbol) = static_addr(symbol) + load_addr
-
-- The choice of symbol is arbitrary. The static address we obtain
-- by constructing a non GOT reference to the symbol, the dynamic
-- address of the symbol we compute using adrp/add to compute the
-- symbol's address relative to the PC.
-- This depends on 32bit relocations being resolved at link time
-- and that the static address fits in the 32bits. */
--
-- ElfW(Addr) static_addr;
-- ElfW(Addr) dynamic_addr;
--
-- asm (" \n"
--" adrp %1, _dl_start; \n"
--" add %1, %1, #:lo12:_dl_start \n"
--" ldr %w0, 1f \n"
--" b 2f \n"
--"1: \n"
--" .word _dl_start \n"
--"2: \n"
-- : "=r" (static_addr), "=r" (dynamic_addr));
-- return dynamic_addr - static_addr;
-+ _DYNAMIC sysmbol is used here as its link-time address stored in
-+ the special unrelocated first GOT entry. */
-+
-+ extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
-+ return (ElfW(Addr)) &_DYNAMIC - elf_machine_dynamic ();
- }
-
- /* Set up the loaded object described by L so its unrelocated PLT
diff --git a/contrib/guix/patches/glibc-2.24-guix-prefix.patch b/contrib/guix/patches/glibc-2.24-guix-prefix.patch
deleted file mode 100644
index 875e8cd611..0000000000
--- a/contrib/guix/patches/glibc-2.24-guix-prefix.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-Without ffile-prefix-map, the debug symbols will contain paths for the
-guix store which will include the hashes of each package. However, the
-hash for the same package will differ when on different architectures.
-In order to be reproducible regardless of the architecture used to build
-the package, map all guix store prefixes to something fixed, e.g. /usr.
-
-We might be able to drop this in favour of using --with-nonshared-cflags
-when we being using newer versions of glibc.
-
---- a/Makeconfig
-+++ b/Makeconfig
-@@ -950,6 +950,10 @@ object-suffixes-for-libc += .oS
- # shared objects. We don't want to use CFLAGS-os because users may, for
- # example, make that processor-specific.
- CFLAGS-.oS = $(CFLAGS-.o) $(PIC-ccflag)
-+
-+# Map Guix store paths to /usr
-+CFLAGS-.oS += `find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -ffile-prefix-map={}=/usr" \;`
-+
- CPPFLAGS-.oS = $(CPPFLAGS-.o) -DPIC -DLIBC_NONSHARED=1
- libtype.oS = lib%_nonshared.a
- endif
---
-2.35.1
-
diff --git a/contrib/guix/patches/glibc-2.24-no-build-time-cxx-header-run.patch b/contrib/guix/patches/glibc-2.24-no-build-time-cxx-header-run.patch
deleted file mode 100644
index 11fe7fdc99..0000000000
--- a/contrib/guix/patches/glibc-2.24-no-build-time-cxx-header-run.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-https://sourceware.org/git/?p=glibc.git;a=commit;h=fc3e1337be1c6935ab58bd13520f97a535cf70cc
-
-commit dc23a45db566095e83ff0b7a57afc87fb5ca89a1
-Author: Florian Weimer <fweimer@redhat.com>
-Date: Wed Sep 21 10:45:32 2016 +0200
-
- Avoid running $(CXX) during build to obtain header file paths
-
- This reduces the build time somewhat and is particularly noticeable
- during rebuilds with few code changes.
-
-diff --git a/Makerules b/Makerules
-index 7e4077ee50..c338850de5 100644
---- a/Makerules
-+++ b/Makerules
-@@ -121,14 +121,10 @@ ifneq (,$(CXX))
- # will be used instead of /usr/include/stdlib.h and /usr/include/math.h.
- before-compile := $(common-objpfx)cstdlib $(common-objpfx)cmath \
- $(before-compile)
--cstdlib=$(shell echo "\#include <cstdlib>" | $(CXX) -M -MP -x c++ - \
-- | sed -n "/cstdlib:/{s/:$$//;p}")
--$(common-objpfx)cstdlib: $(cstdlib)
-+$(common-objpfx)cstdlib: $(c++-cstdlib-header)
- $(INSTALL_DATA) $< $@T
- $(move-if-change) $@T $@
--cmath=$(shell echo "\#include <cmath>" | $(CXX) -M -MP -x c++ - \
-- | sed -n "/cmath:/{s/:$$//;p}")
--$(common-objpfx)cmath: $(cmath)
-+$(common-objpfx)cmath: $(c++-cmath-header)
- $(INSTALL_DATA) $< $@T
- $(move-if-change) $@T $@
- endif
-diff --git a/config.make.in b/config.make.in
-index 95c6f36876..04a8b3ed7f 100644
---- a/config.make.in
-+++ b/config.make.in
-@@ -45,6 +45,8 @@ defines = @DEFINES@
- sysheaders = @sysheaders@
- sysincludes = @SYSINCLUDES@
- c++-sysincludes = @CXX_SYSINCLUDES@
-+c++-cstdlib-header = @CXX_CSTDLIB_HEADER@
-+c++-cmath-header = @CXX_CMATH_HEADER@
- all-warnings = @all_warnings@
- enable-werror = @enable_werror@
-
-diff --git a/configure b/configure
-index 17625e1041..6ff252744b 100755
---- a/configure
-+++ b/configure
-@@ -635,6 +635,8 @@ BISON
- INSTALL_INFO
- PERL
- BASH_SHELL
-+CXX_CMATH_HEADER
-+CXX_CSTDLIB_HEADER
- CXX_SYSINCLUDES
- SYSINCLUDES
- AUTOCONF
-@@ -5054,6 +5056,18 @@ fi
-
-
-
-+# Obtain some C++ header file paths. This is used to make a local
-+# copy of those headers in Makerules.
-+if test -n "$CXX"; then
-+ find_cxx_header () {
-+ echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}"
-+ }
-+ CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)"
-+ CXX_CMATH_HEADER="$(find_cxx_header cmath)"
-+fi
-+
-+
-+
- # Test if LD_LIBRARY_PATH contains the notation for the current directory
- # since this would lead to problems installing/building glibc.
- # LD_LIBRARY_PATH contains the current directory if one of the following
-diff --git a/configure.ac b/configure.ac
-index 33bcd62180..9938ab0dc2 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1039,6 +1039,18 @@ fi
- AC_SUBST(SYSINCLUDES)
- AC_SUBST(CXX_SYSINCLUDES)
-
-+# Obtain some C++ header file paths. This is used to make a local
-+# copy of those headers in Makerules.
-+if test -n "$CXX"; then
-+ find_cxx_header () {
-+ echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}"
-+ }
-+ CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)"
-+ CXX_CMATH_HEADER="$(find_cxx_header cmath)"
-+fi
-+AC_SUBST(CXX_CSTDLIB_HEADER)
-+AC_SUBST(CXX_CMATH_HEADER)
-+
- # Test if LD_LIBRARY_PATH contains the notation for the current directory
- # since this would lead to problems installing/building glibc.
- # LD_LIBRARY_PATH contains the current directory if one of the following
diff --git a/contrib/guix/patches/glibc-2.27-dont-redefine-nss-database.patch b/contrib/guix/patches/glibc-2.27-dont-redefine-nss-database.patch
deleted file mode 100644
index 16a595d613..0000000000
--- a/contrib/guix/patches/glibc-2.27-dont-redefine-nss-database.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-commit 78a90c2f74a2012dd3eff302189e47ff6779a757
-Author: Andreas Schwab <schwab@linux-m68k.org>
-Date: Fri Mar 2 23:07:14 2018 +0100
-
- Fix multiple definitions of __nss_*_database (bug 22918)
-
- (cherry picked from commit eaf6753f8aac33a36deb98c1031d1bad7b593d2d)
-
-diff --git a/nscd/gai.c b/nscd/gai.c
-index d081747797..576fd0045b 100644
---- a/nscd/gai.c
-+++ b/nscd/gai.c
-@@ -45,3 +45,6 @@
- #ifdef HAVE_LIBIDN
- # include <libidn/idn-stub.c>
- #endif
-+
-+/* Some variables normally defined in libc. */
-+service_user *__nss_hosts_database attribute_hidden;
-diff --git a/nss/nsswitch.c b/nss/nsswitch.c
-index d5e655974f..b0f0c11a3e 100644
---- a/nss/nsswitch.c
-+++ b/nss/nsswitch.c
-@@ -62,7 +62,7 @@ static service_library *nss_new_service (name_database *database,
-
- /* Declare external database variables. */
- #define DEFINE_DATABASE(name) \
-- extern service_user *__nss_##name##_database attribute_hidden; \
-+ service_user *__nss_##name##_database attribute_hidden; \
- weak_extern (__nss_##name##_database)
- #include "databases.def"
- #undef DEFINE_DATABASE
-diff --git a/nss/nsswitch.h b/nss/nsswitch.h
-index eccb535ef5..63573b9ebc 100644
---- a/nss/nsswitch.h
-+++ b/nss/nsswitch.h
-@@ -226,10 +226,10 @@ libc_hidden_proto (__nss_hostname_digits_dots)
- #define MAX_NR_ADDRS 48
-
- /* Prototypes for __nss_*_lookup2 functions. */
--#define DEFINE_DATABASE(arg) \
-- service_user *__nss_##arg##_database attribute_hidden; \
-- int __nss_##arg##_lookup2 (service_user **, const char *, \
-- const char *, void **); \
-+#define DEFINE_DATABASE(arg) \
-+ extern service_user *__nss_##arg##_database attribute_hidden; \
-+ int __nss_##arg##_lookup2 (service_user **, const char *, \
-+ const char *, void **); \
- libc_hidden_proto (__nss_##arg##_lookup2)
- #include "databases.def"
- #undef DEFINE_DATABASE
-diff --git a/posix/tst-rfc3484-2.c b/posix/tst-rfc3484-2.c
-index f509534ca9..8c64ac59ff 100644
---- a/posix/tst-rfc3484-2.c
-+++ b/posix/tst-rfc3484-2.c
-@@ -58,6 +58,7 @@ _res_hconf_init (void)
- #undef USE_NSCD
- #include "../sysdeps/posix/getaddrinfo.c"
-
-+service_user *__nss_hosts_database attribute_hidden;
-
- /* This is the beginning of the real test code. The above defines
- (among other things) the function rfc3484_sort. */
-diff --git a/posix/tst-rfc3484-3.c b/posix/tst-rfc3484-3.c
-index ae44087a10..1c61aaf844 100644
---- a/posix/tst-rfc3484-3.c
-+++ b/posix/tst-rfc3484-3.c
-@@ -58,6 +58,7 @@ _res_hconf_init (void)
- #undef USE_NSCD
- #include "../sysdeps/posix/getaddrinfo.c"
-
-+service_user *__nss_hosts_database attribute_hidden;
-
- /* This is the beginning of the real test code. The above defines
- (among other things) the function rfc3484_sort. */
-diff --git a/posix/tst-rfc3484.c b/posix/tst-rfc3484.c
-index 7f191abbbc..8f45848e44 100644
---- a/posix/tst-rfc3484.c
-+++ b/posix/tst-rfc3484.c
-@@ -58,6 +58,7 @@ _res_hconf_init (void)
- #undef USE_NSCD
- #include "../sysdeps/posix/getaddrinfo.c"
-
-+service_user *__nss_hosts_database attribute_hidden;
-
- /* This is the beginning of the real test code. The above defines
- (among other things) the function rfc3484_sort. */
diff --git a/contrib/guix/patches/glibc-2.24-fcommon.patch b/contrib/guix/patches/glibc-2.27-fcommon.patch
index 2bc32ede90..f3baacab98 100644
--- a/contrib/guix/patches/glibc-2.24-fcommon.patch
+++ b/contrib/guix/patches/glibc-2.27-fcommon.patch
@@ -18,15 +18,15 @@ Date: Fri May 6 11:03:04 2022 +0100
https://sourceware.org/git/?p=glibc.git;a=commit;h=7650321ce037302bfc2f026aa19e0213b8d02fe6
diff --git a/Makeconfig b/Makeconfig
-index ee379f5852..63c4a2f234 100644
+index 86a71e5802..aa2166be60 100644
--- a/Makeconfig
+++ b/Makeconfig
-@@ -824,7 +824,7 @@ ifeq "$(strip $(+cflags))" ""
- +cflags := $(default_cflags)
+@@ -896,7 +896,7 @@ ifeq "$(strip $(+cflags))" ""
endif # $(+cflags) == ""
--+cflags += $(cflags-cpu) $(+gccwarn) $(+merge-constants) $(+math-flags)
-++cflags += $(cflags-cpu) $(+gccwarn) $(+merge-constants) $(+math-flags) -fcommon
+ +cflags += $(cflags-cpu) $(+gccwarn) $(+merge-constants) $(+math-flags) \
+- $(+stack-protector)
++ $(+stack-protector) -fcommon
+gcc-nowarn := -w
# Don't duplicate options if we inherited variables from the parent.
diff --git a/contrib/guix/patches/glibc-2.27-guix-prefix.patch b/contrib/guix/patches/glibc-2.27-guix-prefix.patch
index d777af74f0..6648bc6c05 100644
--- a/contrib/guix/patches/glibc-2.27-guix-prefix.patch
+++ b/contrib/guix/patches/glibc-2.27-guix-prefix.patch
@@ -20,6 +20,3 @@ when we being using newer versions of glibc.
libtype.o := lib%.a
object-suffixes += .o
ifeq (yes,$(build-shared))
---
-2.35.1
-
diff --git a/contrib/guix/patches/glibc-ldd-x86_64.patch b/contrib/guix/patches/glibc-ldd-x86_64.patch
index b1b6d5a548..a23b095caa 100644
--- a/contrib/guix/patches/glibc-ldd-x86_64.patch
+++ b/contrib/guix/patches/glibc-ldd-x86_64.patch
@@ -1,8 +1,8 @@
By default, 'RTDLLIST' in 'ldd' refers to 'lib64/ld-linux-x86-64.so', whereas
it's in 'lib/' for us. This patch fixes that.
---- glibc-2.17/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed 2012-12-25 04:02:13.000000000 +0100
-+++ glibc-2.17/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed 2013-09-15 23:08:03.000000000 +0200
+--- a/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed
++++ b/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed
@@ -1,3 +1,3 @@
/LD_TRACE_LOADED_OBJECTS=1/a\
add_env="$add_env LD_LIBRARY_VERSION=\\$verify_out"
diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh
deleted file mode 100755
index 2850c4b993..0000000000
--- a/contrib/install_db4.sh
+++ /dev/null
@@ -1,260 +0,0 @@
-#!/bin/sh
-# Copyright (c) 2017-2021 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-# Install libdb4.8 (Berkeley DB).
-
-export LC_ALL=C
-set -e
-
-if [ -z "${1}" ]; then
- echo "Usage: $0 <base-dir> [<extra-bdb-configure-flag> ...]"
- echo
- echo "Must specify a single argument: the directory in which db4 will be built."
- echo "This is probably \`pwd\` if you're at the root of the bitcoin repository."
- exit 1
-fi
-
-expand_path() {
- cd "${1}" && pwd -P
-}
-
-BDB_PREFIX="$(expand_path "${1}")/db4"; shift;
-BDB_VERSION='db-4.8.30.NC'
-BDB_HASH='12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef'
-BDB_URL="https://download.oracle.com/berkeley-db/${BDB_VERSION}.tar.gz"
-
-check_exists() {
- command -v "$1" >/dev/null
-}
-
-sha256_check() {
- # Args: <sha256_hash> <filename>
- #
- if check_exists sha256sum; then
- echo "${1} ${2}" | sha256sum -c
- elif check_exists sha256; then
- if [ "$(uname)" = "FreeBSD" ]; then
- sha256 -c "${1}" "${2}"
- else
- echo "${1} ${2}" | sha256 -c
- fi
- else
- echo "${1} ${2}" | shasum -a 256 -c
- fi
-}
-
-http_get() {
- # Args: <url> <filename> <sha256_hash>
- #
- # It's acceptable that we don't require SSL here because we manually verify
- # content hashes below.
- #
- if [ -f "${2}" ]; then
- echo "File ${2} already exists; not downloading again"
- elif check_exists curl; then
- curl --insecure --retry 5 "${1}" -o "${2}"
- elif check_exists wget; then
- wget --no-check-certificate "${1}" -O "${2}"
- else
- echo "Simple transfer utilities 'curl' and 'wget' not found. Please install one of them and try again."
- exit 1
- fi
-
- sha256_check "${3}" "${2}"
-}
-
-# Ensure the commands we use exist on the system
-if ! check_exists patch; then
- echo "Command-line tool 'patch' not found. Install patch and try again."
- exit 1
-fi
-
-mkdir -p "${BDB_PREFIX}"
-http_get "${BDB_URL}" "${BDB_VERSION}.tar.gz" "${BDB_HASH}"
-tar -xzvf ${BDB_VERSION}.tar.gz -C "$BDB_PREFIX"
-cd "${BDB_PREFIX}/${BDB_VERSION}/"
-
-# Apply a patch necessary when building with clang and c++11 (see https://community.oracle.com/thread/3952592)
-patch --ignore-whitespace -p1 << 'EOF'
-commit 3311d68f11d1697565401eee6efc85c34f022ea7
-Author: fanquake <fanquake@gmail.com>
-Date: Mon Aug 17 20:03:56 2020 +0800
-
- Fix C++11 compatibility
-
-diff --git a/dbinc/atomic.h b/dbinc/atomic.h
-index 0034dcc..7c11d4a 100644
---- a/dbinc/atomic.h
-+++ b/dbinc/atomic.h
-@@ -70,7 +70,7 @@ typedef struct {
- * These have no memory barriers; the caller must include them when necessary.
- */
- #define atomic_read(p) ((p)->value)
--#define atomic_init(p, val) ((p)->value = (val))
-+#define atomic_init_db(p, val) ((p)->value = (val))
-
- #ifdef HAVE_ATOMIC_SUPPORT
-
-@@ -144,7 +144,7 @@ typedef LONG volatile *interlocked_val;
- #define atomic_inc(env, p) __atomic_inc(p)
- #define atomic_dec(env, p) __atomic_dec(p)
- #define atomic_compare_exchange(env, p, o, n) \
-- __atomic_compare_exchange((p), (o), (n))
-+ __atomic_compare_exchange_db((p), (o), (n))
- static inline int __atomic_inc(db_atomic_t *p)
- {
- int temp;
-@@ -176,7 +176,7 @@ static inline int __atomic_dec(db_atomic_t *p)
- * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
- * which configure could be changed to use.
- */
--static inline int __atomic_compare_exchange(
-+static inline int __atomic_compare_exchange_db(
- db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval)
- {
- atomic_value_t was;
-@@ -206,7 +206,7 @@ static inline int __atomic_compare_exchange(
- #define atomic_dec(env, p) (--(p)->value)
- #define atomic_compare_exchange(env, p, oldval, newval) \
- (DB_ASSERT(env, atomic_read(p) == (oldval)), \
-- atomic_init(p, (newval)), 1)
-+ atomic_init_db(p, (newval)), 1)
- #else
- #define atomic_inc(env, p) __atomic_inc(env, p)
- #define atomic_dec(env, p) __atomic_dec(env, p)
-diff --git a/mp/mp_fget.c b/mp/mp_fget.c
-index 5fdee5a..0b75f57 100644
---- a/mp/mp_fget.c
-+++ b/mp/mp_fget.c
-@@ -617,7 +617,7 @@ alloc: /* Allocate a new buffer header and data space. */
-
- /* Initialize enough so we can call __memp_bhfree. */
- alloc_bhp->flags = 0;
-- atomic_init(&alloc_bhp->ref, 1);
-+ atomic_init_db(&alloc_bhp->ref, 1);
- #ifdef DIAGNOSTIC
- if ((uintptr_t)alloc_bhp->buf & (sizeof(size_t) - 1)) {
- __db_errx(env,
-@@ -911,7 +911,7 @@ alloc: /* Allocate a new buffer header and data space. */
- MVCC_MPROTECT(bhp->buf, mfp->stat.st_pagesize,
- PROT_READ);
-
-- atomic_init(&alloc_bhp->ref, 1);
-+ atomic_init_db(&alloc_bhp->ref, 1);
- MUTEX_LOCK(env, alloc_bhp->mtx_buf);
- alloc_bhp->priority = bhp->priority;
- alloc_bhp->pgno = bhp->pgno;
-diff --git a/mp/mp_mvcc.c b/mp/mp_mvcc.c
-index 34467d2..f05aa0c 100644
---- a/mp/mp_mvcc.c
-+++ b/mp/mp_mvcc.c
-@@ -276,7 +276,7 @@ __memp_bh_freeze(dbmp, infop, hp, bhp, need_frozenp)
- #else
- memcpy(frozen_bhp, bhp, SSZA(BH, buf));
- #endif
-- atomic_init(&frozen_bhp->ref, 0);
-+ atomic_init_db(&frozen_bhp->ref, 0);
- if (mutex != MUTEX_INVALID)
- frozen_bhp->mtx_buf = mutex;
- else if ((ret = __mutex_alloc(env, MTX_MPOOL_BH,
-@@ -428,7 +428,7 @@ __memp_bh_thaw(dbmp, infop, hp, frozen_bhp, alloc_bhp)
- #endif
- alloc_bhp->mtx_buf = mutex;
- MUTEX_LOCK(env, alloc_bhp->mtx_buf);
-- atomic_init(&alloc_bhp->ref, 1);
-+ atomic_init_db(&alloc_bhp->ref, 1);
- F_CLR(alloc_bhp, BH_FROZEN);
- }
-
-diff --git a/mp/mp_region.c b/mp/mp_region.c
-index e6cece9..ddbe906 100644
---- a/mp/mp_region.c
-+++ b/mp/mp_region.c
-@@ -224,7 +224,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg)
- MTX_MPOOL_FILE_BUCKET, 0, &htab[i].mtx_hash)) != 0)
- return (ret);
- SH_TAILQ_INIT(&htab[i].hash_bucket);
-- atomic_init(&htab[i].hash_page_dirty, 0);
-+ atomic_init_db(&htab[i].hash_page_dirty, 0);
- }
-
- /*
-@@ -269,7 +269,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg)
- hp->mtx_hash = (mtx_base == MUTEX_INVALID) ? MUTEX_INVALID :
- mtx_base + i;
- SH_TAILQ_INIT(&hp->hash_bucket);
-- atomic_init(&hp->hash_page_dirty, 0);
-+ atomic_init_db(&hp->hash_page_dirty, 0);
- #ifdef HAVE_STATISTICS
- hp->hash_io_wait = 0;
- hp->hash_frozen = hp->hash_thawed = hp->hash_frozen_freed = 0;
-diff --git a/mutex/mut_method.c b/mutex/mut_method.c
-index 2588763..5c6d516 100644
---- a/mutex/mut_method.c
-+++ b/mutex/mut_method.c
-@@ -426,7 +426,7 @@ atomic_compare_exchange(env, v, oldval, newval)
- MUTEX_LOCK(env, mtx);
- ret = atomic_read(v) == oldval;
- if (ret)
-- atomic_init(v, newval);
-+ atomic_init_db(v, newval);
- MUTEX_UNLOCK(env, mtx);
-
- return (ret);
-diff --git a/mutex/mut_tas.c b/mutex/mut_tas.c
-index f3922e0..e40fcdf 100644
---- a/mutex/mut_tas.c
-+++ b/mutex/mut_tas.c
-@@ -46,7 +46,7 @@ __db_tas_mutex_init(env, mutex, flags)
-
- #ifdef HAVE_SHARED_LATCHES
- if (F_ISSET(mutexp, DB_MUTEX_SHARED))
-- atomic_init(&mutexp->sharecount, 0);
-+ atomic_init_db(&mutexp->sharecount, 0);
- else
- #endif
- if (MUTEX_INIT(&mutexp->tas)) {
-@@ -486,7 +486,7 @@ __db_tas_mutex_unlock(env, mutex)
- F_CLR(mutexp, DB_MUTEX_LOCKED);
- /* Flush flag update before zeroing count */
- MEMBAR_EXIT();
-- atomic_init(&mutexp->sharecount, 0);
-+ atomic_init_db(&mutexp->sharecount, 0);
- } else {
- DB_ASSERT(env, sharecount > 0);
- MEMBAR_EXIT();
-EOF
-
-# The packaged config.guess and config.sub are ancient (2009) and can cause build issues.
-# Replace them with modern versions.
-# See https://github.com/bitcoin/bitcoin/issues/16064
-CONFIG_GUESS_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f'
-CONFIG_GUESS_HASH='c8f530e01840719871748a8071113435bdfdf75b74c57e78e47898edea8754ae'
-CONFIG_SUB_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f'
-CONFIG_SUB_HASH='3969f7d5f6967ccc6f792401b8ef3916a1d1b1d0f0de5a4e354c95addb8b800e'
-
-rm -f "dist/config.guess"
-rm -f "dist/config.sub"
-
-http_get "${CONFIG_GUESS_URL}" dist/config.guess "${CONFIG_GUESS_HASH}"
-http_get "${CONFIG_SUB_URL}" dist/config.sub "${CONFIG_SUB_HASH}"
-
-cd build_unix/
-
-"${BDB_PREFIX}/${BDB_VERSION}/dist/configure" \
- --enable-cxx --disable-shared --disable-replication --with-pic --prefix="${BDB_PREFIX}" \
- "${@}"
-
-make install
-
-echo
-echo "db4 build complete."
-echo
-# shellcheck disable=SC2016
-echo 'When compiling bitcoind, run `./configure` in the following way:'
-echo
-echo " export BDB_PREFIX='${BDB_PREFIX}'"
-# shellcheck disable=SC2016
-echo ' ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" ...'
diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py
index b72c7b0d08..24f6b29a26 100755
--- a/contrib/linearize/linearize-data.py
+++ b/contrib/linearize/linearize-data.py
@@ -2,7 +2,7 @@
#
# linearize-data.py: Construct a linear, no-fork version of the chain.
#
-# Copyright (c) 2013-2021 The Bitcoin Core developers
+# Copyright (c) 2013-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py
index 5959300e74..695bafad34 100755
--- a/contrib/linearize/linearize-hashes.py
+++ b/contrib/linearize/linearize-hashes.py
@@ -2,7 +2,7 @@
#
# linearize-hashes.py: List blocks in a linear, no-fork version of the chain.
#
-# Copyright (c) 2013-2019 The Bitcoin Core developers
+# Copyright (c) 2013-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
@@ -78,7 +78,7 @@ def get_block_hashes(settings, max_blocks_per_call=10000):
if rpc.response_is_error(resp_obj):
print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr)
sys.exit(1)
- assert(resp_obj['id'] == x) # assume replies are in-sequence
+ assert resp_obj['id'] == x # assume replies are in-sequence
if settings['rev_hash_bytes'] == 'true':
resp_obj['result'] = bytes.fromhex(resp_obj['result'])[::-1].hex()
print(resp_obj['result'])
diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh
index f393331084..626381cf43 100755
--- a/contrib/macdeploy/detached-sig-create.sh
+++ b/contrib/macdeploy/detached-sig-create.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index 2420539b7c..f8677ba7b8 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -187,7 +187,7 @@ def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]:
if verbose:
print(f"Inspecting with otool: {binaryPath}")
otoolbin=os.getenv("OTOOL", "otool")
- otool = run([otoolbin, "-L", binaryPath], stdout=PIPE, stderr=PIPE, universal_newlines=True)
+ otool = run([otoolbin, "-L", binaryPath], stdout=PIPE, stderr=PIPE, text=True)
if otool.returncode != 0:
sys.stderr.write(otool.stderr)
sys.stderr.flush()
@@ -577,17 +577,17 @@ if config.dmg is not None:
tempname: str = appname + ".temp.dmg"
- run(["hdiutil", "create", tempname, "-srcfolder", "dist", "-format", "UDRW", "-size", str(size), "-volname", appname], check=True, universal_newlines=True)
+ run(["hdiutil", "create", tempname, "-srcfolder", "dist", "-format", "UDRW", "-size", str(size), "-volname", appname], check=True, text=True)
if verbose:
print("Attaching temp image...")
- output = run(["hdiutil", "attach", tempname, "-readwrite"], check=True, universal_newlines=True, stdout=PIPE).stdout
+ output = run(["hdiutil", "attach", tempname, "-readwrite"], check=True, text=True, stdout=PIPE).stdout
print("+ Finalizing .dmg disk image +")
- run(["hdiutil", "detach", f"/Volumes/{appname}"], universal_newlines=True)
+ run(["hdiutil", "detach", f"/Volumes/{appname}"], text=True)
- run(["hdiutil", "convert", tempname, "-format", "UDZO", "-o", appname, "-imagekey", "zlib-level=9"], check=True, universal_newlines=True)
+ run(["hdiutil", "convert", tempname, "-format", "UDZO", "-o", appname, "-imagekey", "zlib-level=9"], check=True, text=True)
os.unlink(tempname)
diff --git a/contrib/message-capture/message-capture-parser.py b/contrib/message-capture/message-capture-parser.py
index 33759ee713..d6ddc1c149 100755
--- a/contrib/message-capture/message-capture-parser.py
+++ b/contrib/message-capture/message-capture-parser.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Parse message capture binary files. To be used in conjunction with -capturemessages."""
diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md
index b2ea7522ac..b0bbe96493 100644
--- a/contrib/seeds/README.md
+++ b/contrib/seeds/README.md
@@ -13,6 +13,6 @@ data. Run the following commands from the `/contrib/seeds` directory:
curl https://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt
curl https://bitcoin.sipa.be/asmap-filled.dat > asmap-filled.dat
- python3 makeseeds.py -a asmap-filled.dat < seeds_main.txt > nodes_main.txt
+ python3 makeseeds.py -a asmap-filled.dat -s seeds_main.txt > nodes_main.txt
cat nodes_main_manual.txt >> nodes_main.txt
python3 generate-seeds.py . > ../../src/chainparamsseeds.h
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
index 44345e3987..a6f435af0d 100755
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -70,13 +70,13 @@ def name_to_bip155(addr):
if i == 0 or i == (len(addr)-1): # skip empty component at beginning or end
continue
x += 1 # :: skips to suffix
- assert(x < 2)
+ assert x < 2
else: # two bytes per component
val = int(comp, 16)
sub[x].append(val >> 8)
sub[x].append(val & 0xff)
nullbytes = 16 - len(sub[0]) - len(sub[1])
- assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0))
+ assert (x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)
addr_bytes = bytes(sub[0] + ([0] * nullbytes) + sub[1])
if addr_bytes[0] == 0xfc:
# Assume that seeds with fc00::/8 addresses belong to CJDNS,
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
index eda58c370f..23d38ee48d 100755
--- a/contrib/seeds/makeseeds.py
+++ b/contrib/seeds/makeseeds.py
@@ -173,6 +173,7 @@ def ip_stats(ips: List[Dict]) -> str:
def parse_args():
argparser = argparse.ArgumentParser(description='Generate a list of bitcoin node seed ip addresses.')
argparser.add_argument("-a","--asmap", help='the location of the asmap asn database file (required)', required=True)
+ argparser.add_argument("-s","--seeds", help='the location of the DNS seeds file (required)', required=True)
return argparser.parse_args()
def main():
@@ -184,7 +185,8 @@ def main():
print('Done.', file=sys.stderr)
print('Loading and parsing DNS seeds…', end='', file=sys.stderr, flush=True)
- lines = sys.stdin.readlines()
+ with open(args.seeds, 'r', encoding='utf8') as f:
+ lines = f.readlines()
ips = [parseline(line) for line in lines]
print('Done.', file=sys.stderr)
diff --git a/contrib/signet/getcoins.py b/contrib/signet/getcoins.py
index a069f5fad3..19751ae269 100755
--- a/contrib/signet/getcoins.py
+++ b/contrib/signet/getcoins.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -129,7 +129,7 @@ if args.captcha != '': # Retrieve a captcha
# Convert SVG image to PPM, and load it
try:
- rv = subprocess.run([args.imagemagick, 'svg:-', '-depth', '8', 'ppm:-'], input=res.content, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ rv = subprocess.run([args.imagemagick, 'svg:-', '-depth', '8', 'ppm:-'], input=res.content, check=True, capture_output=True)
except FileNotFoundError:
raise SystemExit(f"The binary {args.imagemagick} could not be found. Please make sure ImageMagick (or a compatible fork) is installed and that the correct path is specified.")
@@ -142,7 +142,7 @@ if args.captcha != '': # Retrieve a captcha
try:
res = session.post(args.faucet, data=data)
-except:
+except Exception:
raise SystemExit(f"Unexpected error when contacting faucet: {sys.exc_info()[0]}")
# Display the output as per the returned status code
diff --git a/contrib/tracing/log_utxocache_flush.py b/contrib/tracing/log_utxocache_flush.py
index 8c073bea0d..6c568998e9 100755
--- a/contrib/tracing/log_utxocache_flush.py
+++ b/contrib/tracing/log_utxocache_flush.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp
index d6856b4274..9a8edba445 100644
--- a/contrib/valgrind.supp
+++ b/contrib/valgrind.supp
@@ -99,14 +99,6 @@
fun:_Z11LogInstancev
}
{
- Suppress secp256k1_context_create still reachable memory warning
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:malloc
- ...
- fun:secp256k1_context_create
-}
-{
Suppress BCLog::Logger::StartLogging() still reachable memory warning
Memcheck:Leak
match-leak-kinds: reachable
diff --git a/contrib/verify-commits/README.md b/contrib/verify-commits/README.md
index b8b15280ba..020890c366 100644
--- a/contrib/verify-commits/README.md
+++ b/contrib/verify-commits/README.md
@@ -27,6 +27,10 @@ Note that the above isn't a good UI/UX yet, and needs significant improvements
to make it more convenient and reduce the chance of errors; pull-reqs
improving this process would be much appreciated.
+Unless `--clean-merge 0` is specified, `verify-commits.py` will attempt to verify that
+each merge commit applies cleanly (with some exceptions). This requires using at least
+git v2.38.0.
+
Configuration files
-------------------
diff --git a/contrib/verify-commits/allow-incorrect-sha512-commits b/contrib/verify-commits/allow-incorrect-sha512-commits
index c572806f26..e69de29bb2 100644
--- a/contrib/verify-commits/allow-incorrect-sha512-commits
+++ b/contrib/verify-commits/allow-incorrect-sha512-commits
@@ -1,2 +0,0 @@
-f8feaa4636260b599294c7285bcf1c8b7737f74e
-8040ae6fc576e9504186f2ae3ff2c8125de1095c
diff --git a/contrib/verify-commits/allow-revsig-commits b/contrib/verify-commits/allow-revsig-commits
index 0bb299b8fa..e69de29bb2 100644
--- a/contrib/verify-commits/allow-revsig-commits
+++ b/contrib/verify-commits/allow-revsig-commits
@@ -1,645 +0,0 @@
-a06ede9a138d0fb86b0de17c42b936d9fe6e2158
-923dc447eaa8e017985b2afbbb12dd1283fbea0e
-71148b8947fe8b4d756822420a7f31c380159425
-6696b4635ceb9b47aaa63244bff9032fa7b08354
-812714fd80e96e28cd288c553c83838cecbfc2d9
-8a445c5651edb9a1f51497055b7ddf4402be9188
-e126d0c12ca66278d9e7b12187c5ff4fc02a7e6c
-3908fc4728059719bed0e1c7b1c8b388c2d4a8da
-8b66bf74e2a349e71eaa183af81fa63eaee76ad2
-05950427d310654774031764a7141a1a4fd9c6e4
-07fd147b9f12e9205afd66a624edce357977d615
-12e31127948fa4bb01c3bddc1b8c85b432f7465b
-8c87f175d335e9d9e93f987d871ae9f05f6a10a7
-46b249e578e8a3dfbe85bc7253a12e82ef4b658b
-a55716abe5662ec74c2f8af93023f1e7cca901fc
-f646275b90b1de93bc62b4c4d045d75ac0b96eee
-c252685aa5867631e9a5ef07ccae7c7c25cae8ff
-a7d55c93385359952d85decd5037843ac70ba3d4
-7dac1e5e9e887f5f6ff146e812a05bd3bf281eae
-2a524b8e8fe69ef487fd8ea1b4f7a03f473ed201
-ce5c1f4acae43477989cdf9a82ed33703919cda2
-2db4cbcc437f51f5dac82cc4de46f383b92e6f11
-7aa700424cbda387536373d8dfec88aee43f950e
-b99a093afed880f23fb279c443cc6ae5e379cc43
-b83264d9c7a8ddb79f64bd9540caddc8632ef31f
-57e337d40e94ba33d8cd265c134d6ef857b32b59
-a1dcf2e1087beaf3981739fd2bb74f35ecad630a
-d38b0d7a6b6056cba26999b702815775e2437d87
-815640ec6af9a38d6a2da4a4400056e2f4105080
-09c4fd157c5b88df2d97fad4826c79b094db90c9
-2efcfa5acfacb958973d9e8125e1d81f102e2dfd
-dc6dee41f7cf2ba93fcd0fea7c157e4b2775d439
-ad826b3df9f763b49f1e3e3d50c4efdd438c7547
-c1a52276848d8caa9a9789dff176408c1aa6b1ed
-3bf06e9bac57b5b5a746677b75e297a7b154bdbd
-72ae6f8cf0224370e8121d6769b21e612ca15d6f
-a143b88dbd4971ecfdd1d39a494489c8f2db0344
-76fec09d878d6dbf214bdb6228d480bd9195db4c
-93566e0c37c5ae104095474fea89f00dcb40f551
-407d9232ef5cb1ebf6cff21f3d13e07ea4158eeb
-9346f8429957e356d21c665bab59fe45bcf1f74e
-6eeac6e30d65f9a972067c1ea8c49978c8e631ac
-dc6b9406bdfab2af8c86cb080cb3e6cf8f2385d8
-9f554e03ebe5701c1b75ff03b3d6152095c0cad3
-05009935f9ac070197113954d680bc2c9150b9b3
-508404de98a8a5435f52916cef8f328e82651961
-ed0cc50afed146c27f6d8129c683c225fb940093
-6429cfa8a70308241c576aeb92ffe3db5203b2ef
-6898213409811b140843c3d89af43328c3b22fad
-5b2ea29cf4fd298346437bb16a54407f8c1f9dca
-e2a1a1ee895149c544d4ae295466611f0cec3094
-e82fb872ff5cc8fd22d43327c1ee3e755f61c562
-19b0f33de0efd9da788e8e4f3fdc2a9e159abdb1
-89de1538ce1f8c00f80e8d11f43e1b77e24d7dea
-de07fdcf77e97b8613091285e4d0a734f5de7492
-01680195f8aa586c55c44767397380def3a23b54
-05e1c85fb687c82ae477c72d4a7e2d6b0c692167
-c072b8fd95cd4fa84f08189a0cd8b173ea2dbb8e
-9a0ed08b40b15ae2b791aa8549b53e69934b4ea7
-53f8f226bd1d627c4a6dec5862a1d4ea5a933e45
-9d0f43b7ca7241d8a018fd35dd3bc01555235ec6
-f12d2b5a8ac397e4bcaefcc19898f8ff5705dea5
-8250de13587ed05ca45df3e12c5dc9bcb1500e2c
-d727f77e390426e9e463336bda08d50c451c7086
-484312bda2d43e3ea60047be076332299463adf8
-c7e05b35ab0a791c7a8e2d863e716fdec6f3f671
-b9c1cd81848da9de1baf9c2f29c19c50e549de13
-8ea7d31e384975019733b5778feabbd9955c79d8
-f798b891bcecea9548eedacae70eeb9906c1ddbf
-ebefe7a00b46579cdd1e033a8c7fd8ce9aa578e4
-ad087638ee4864d6244ec9381ff764bfa6ee5086
-66db2d62d59817320c9182fc18e75a93b76828ea
-7ce9ac5c83b1844a518ef2e12e87aae3cacdfe58
-4286f43025149cf44207c3ad98e4a1f068520ada
-cd0c5135ab2291aaa5410ac919bad3fc87249a4a
-66ed450d771a8fc01c159a8402648ebd1c35eb4c
-a82f03393a32842d49236e8666ee57805ca701f8
-f972b04d63eb8af79ff3cec1dc561ed13dfa6053
-ec45cc5e27668171b55271b0c735194c70e7da41
-715e9fd7454f7a48d7adba7d42f662c20a3e3367
-2e0a99037dcc35bc63ba0d54371bc678af737c8e
-7fa8d758598407f3bf0beb0118dc122ea5340736
-6a22373771edbc3c7513cacb9355f880c73c2cbf
-b89ef131147f71a96152a7b5c4374266cdf539b2
-01d8359983e2f77b5118fede3ffa947072c666c8
-58f0c929a3d70a4bff79cc200f1c186f71ef1675
-950be19727a581970591d8f8138dfe4725750382
-425278d17bd0edf8a3a7cc81e55016f7fd8e7726
-c028c7b7557da2baff7af8840108e8be4db8e0c6
-47a7cfb0aa2498f6801026d258a59f9de48f60b0
-f6b7df3155ddb4cedfbcf5d3eb3383d4614b3a85
-d72098038f3b55a714ed8adb34fab547b15eb0d5
-c49c825bd9f4764536b45df5a684d97173673fc7
-33799afe83eec4200ff140e9bf5eae83701a4d7f
-5c3f8ddcaa1164079105c452429fccf8127b01b6
-1f01443567b03ac75a91c810f1733f5c21b5699d
-b3e42b6d02e8d19658a9135e427ebceab5367779
-69b3a6dd9d9a0adf5506c8b9fde42187356bd4a8
-bafd075c5e6a1088ef0f1aa0b0b224e026a3d3e0
-7daa3adb242d9c8728fdb15c6af6596aaad5502f
-514993554c370f4cf30a109ac28d5d64893dbf0a
-c8d2473e6cb042e7275a10c49d3f6a4a91bf0166
-386f4385ab04b0b2c3d47bddc0dc0f2de7354964
-9f33dba05c01ecc5c56eb1284ab7d64d42f55171
-7466a26cab5d66665991433947964a638f5b957e
-b43aba89e356ff95b706e80d4802f60fc46a569a
-02b7e8319aef2a870264ad4fa2e3bb18664dcc36
-f686002a8eba820a40ac2f34a6e8f57b2b5cc54c
-2b1c50b9352ab1dc40b0f877db23c1fa4048fae3
-2405ce1df043f778b8efb9205009500cbc17313a
-4ad3b3c72c73d61e0a0cab541dca20acf651320d
-4ba3d4f4393d81148422d24d222fe7ed00130194
-8ee5c7b747171e335793c74cd9d2f7491da58164
-872c921c0a208b04bd0713758e52fcab5b7c1684
-00d1680498c5550e7db1f359202d3433a092fafd
-585db41e9ab7a6fb262c8bad7f427cdbdc497188
-18462960c0f13bd07d8f52b61e7d7bc17e991eea
-0630974647dacaf25e7fcb7f9cbb785bb078ede6
-0f58d7f3d62f012f2584f5e781fc73de4763dd9e
-3d16f581538b0974853e820508e8b3093269d2fd
-66e91420ab233cf1dac64504e0dc129019bf8c0d
-d8d9162f5bad39b2720dd2b2da237c6159e4755f
-29fad97c320c892ab6a480c81e2078ec22ab354b
-791c3ea61b4e49fd46a1a71b84ca99ddf69d2ff7
-a312e201ba56742499a5480b5f2115f01505c217
-ce56fdd2e8cdf94fd0ab76d71adbfa755e23ce7d
-480f42630cbd598c04fa59ee0e406f56904ecffb
-6012f1caf744ac9b53383d7d10a8f1b70ca2c0e1
-ded6a2afa549f693dcabb430ce0862f8631360c8
-07090c5339436f856e79a8036d1c85deeb453803
-0e265916d1c6a63e4a3821dab9db597b5ec64b46
-e4ffcacc2187d3419c8ea12b82fb06d82d8751d2
-e117cfe45eee9169409e74a44ef4a866be25bc35
-dcfe218626b05204e9fbc95ba5d95ca0eb72ec9b
-23481fa50301201ef5a60675ef899aa6ce94ca03
-27c59dc502f29cf1d76290556c21e366145e3b2e
-4a62ddd01873d18dbca96c81d756be1020249b45
-a233fb4f1d037e68ff70eef3a9f5b7bf1d631918
-b2089c51cc4af2f7e1c0ec75be9449ee222b1d69
-c997f8808256521397f1c003bb1e9896fee6eaa0
-5dc00f68c49c46a380a98d06233f90528b8e2557
-fe53d5f3636aed064823bc220d828c7ff08d1d52
-935eb8de039dec65669a96a1c3b86f4b03a1b86c
-0277173b1defb63216d40a8d8805ae6d5d563c26
-2a30e67d20f76bbcd9a7d445f616f005316e0a1a
-d32528e733f2711b34dbc41fbb2bb0f153bf7e9a
-4cad91663df381d0dff8526f3b4aa74569dfb626
-1b06ed136f17b526360617a70026aed5ded5746c
-895fbd768f0c89cea3f78acac58b233d4e3a145e
-f0295becbf3ef1fb78095306408789253fe0c114
-8d573198638e52e2dbd9abc609861430f9d2bcc3
-9d9c4185fadaf243bb97c226e2fef16b65299699
-eebe4580bc8d6484d79ecb24dd87412221cf2ea7
-9cf6393a4f82b9c81d3b4b468a17a89db10531a2
-598a9c4e4dcd03c6d80fba005de729a6a3aeba7e
-6970b30c6f1d2be7947295fe18f2390649b17a4b
-f359afcc410432ed5d30001acda0c66741ee8935
-126000ba9e7ff16271be2f4eef3df99ade8d624f
-b5e4b9b5100ec15217d43edb5f4149439f4b20a5
-b987ca4ee495a7fff82f0ac14ef0753bfb7586e2
-b03013396cb2f4bf25746388b3982a2c3616e16b
-9a97f39afaa890caa7987c6bc001b9a66e3e74e8
-cad504bf4c302f7a72e0a0e191f3fdbafda7340f
-45cf8a03cb57b8639a8d47323bde46ba22d9eeaf
-b7450cdbd89a1c862f4d4d8bf093f8a0b5448f9c
-0910cbe4ef31eb95fd76c7c2f820419fe64a3150
-92a810d04b906722c9efe60e3997243c71ff3d4c
-45173fa6fca9537abb0a0554f731d14b9f89c456
-fd4ca17360e6fc0c9bb76bf6b5b07c9102c12728
-ddff3447f29b62d79a33f728791f42fa9436216e
-36a5a4404836da323c755523fbd27563a8e84f94
-c991b304dee368f506cfee27ddaa333f1f82c518
-d38d1a3e75aa97ffa8755ddd431754a6d0942964
-a332a7d5a15214015f9553fdb2bcf80a1a4b8dc0
-604e08c83cf58ca7e7cda2ab284c1ace7bb12977
-18a1bbad98bd4321f15e7921d9aec91661499d90
-8049241e226c16bd07b029c0cb4b62ac40f0c923
-797441ee995aac59f55d59a93ecb55e8ecbe7dbc
-62fdf9b07087b80d2142799bdd2324f61483359d
-f60b4ad57912b78a96af08046a503f7905610a8c
-13e31dd6548d64a5992f439e74bb424bf88aca04
-fbce66a982679b5409a295be5c99a2eef429cabf
-9f2c2dba21855b8cb9b193b1819be73fa4a23a99
-a89221873a3ee2451c73b41bbe2d99d36f439d31
-3d6ad407770e13958e157bf026cae0bfb9254899
-901ba3e3819405306414628306746552b0aa1d28
-7a43fbb959c38e025e558e472ad57de357539894
-0d89fa0877930c6c8a539a656c1009ad8ab6755b
-54aedc013744c86b11157423fa3cffc9a51eef02
-f0c1f8abb0182da557d07372b938f3a0a4bb906f
-4ed818060ecf4a38a02c8cb48f6cbc78d2ee7708
-3bdf242fc68a8d767932c6214455d4d413effbc9
-5e468994fbb349e8eefc996954a31a67a34aaa15
-41aa9c4a801a01eca1fad22a7095372d23dace60
-2adbddb03840ad71e843c6c4a207a13e871cd1d4
-13e352dc53dec0127c5f94a60055d0ca829420dc
-95e14dc81dd30ee0d396ad08dca9a6980d16eee1
-61fb80660f73e5aa5b69302ecc7ac33da206ba5a
-05a761932edd05cf94ffe938908baf058f38632a
-ee92243e66f2df03b3a759a8ffb75dc06f0cea0d
-22cdf93c062eeaa0f8f9d6220f01b67240073dfb
-76b33491596736ca804e3a29bd8398d7a1516ab7
-6e4e98ee8ce2da3cca2e2fd210e9e8dbc9b1c936
-c838283ecdfb9490425bb071b7c22e542de46c7c
-5e3f5e4f25b65b583d3bfefac9e1148035781089
-f7388e93d3dd91a90239aedac4ec58404f103a2e
-0a2f46b0158b6fc7244a585913b0925c0acf707f
-dd561667cb7ccbbfed3134b05a565971ef6f5873
-6f01dcf63873a5e42798635ab4026c9a5f9fa213
-70fec9e36bcd1a3d93df019be084aaf89cecd7d7
-f9b74ef3fc74fd7d2aa94560820341f03cda8e12
-998c3046fab2b52bc9f141cfb588a18c05506a86
-89cc4f905e30b913ca20e4192d538cc5cbe2c38d
-87d90efd69b64f769116956a5db89e536e9e3714
-5aeaa9ccd1568a77e075dbe2bd2435bd60c87c91
-bfb270acfa30713dc8c968bb9ee40cf5a2360359
-1b8c88451b0554502435d3883c528ad0aad1b09b
-57ee73990f1ce29916adfd99f93eae1ccea1a43b
-808c84f89d0edcef9ddaab0b849a382719f6ec9e
-14b860bf64020451ced823b859da8cb912278ab9
-c63364610f4a041df1c1bd81d01b1f6856160749
-92eadc395071876d77f3babddc056b4325bdbabc
-e93fff1463ae906fc986bf98c3b118c82f171546
-9ccafb1d7bdd172a9b963444072a844da379c4f7
-b4a509a3f817121c3df98ddfd96b2769e18a3e5a
-dbc4ae03963014ab4b7957d62ba59dbd8f938c33
-8ddf60db7ad636b6a31b590251c671ded635fa1d
-f199b8a33d9443a258a1f49a1a29674cd9ee9a20
-e542728cde676f218c552d841d0af29b92f9800b
-763231051596b8e3455b839911ad6a3a1f1c3c74
-ff4cd6075b12fb32b9a906deea3ed033e3f9560a
-9c3c9cdae3e20b5bdea91a0631edac5116bbc89f
-93d20a734d2ee873832bed8ca5c05cf8e539c53c
-ef8340d25f7c5dd5682bdecea97ce84cfce1493c
-69c7ecef405d168f658a9cc7996da84c17f61e66
-4ce2f3d0d33346e9f0e96851689ee6550b2a72e3
-44e1fd926cfb0df0fbd8c41de8cd65ed8d5d6e18
-d6d2c8503c4039b682196d83a67dc28359c10c5c
-ae233c4ec3d14a97c6195059f52873cdba2b4755
-0f399a9ff227896265cafab9b2e9fab6cdb9b5b9
-f4ed44ab4a8f9a87ba678d5fd1449fbf636103dc
-7fcd61b2613c211bb042a82a889655178be6a212
-42973f834445d7735738bdba8847812ba3c34d95
-8df48b36ed3201d938b9974ecbee455d7dc2fb84
-96ac26e56627f0c24213fcd3a1cce9fc95f1f661
-cce94c518a46b7b0006f984bbe4d69e8749182d2
-801dd40666d1e6009920ad3ff755c7bb993b2a62
-ce829855cfca103dde55661fa1524e66b139d063
-b148803b181e30213e8a7f3bd89c8239e9dcb866
-c377feaad87f8109f85da6caf62602b30c20effc
-b37cab65c63e051ebc5b491da9bd687581df94df
-16e41844e7d6c5876d2caaeef6010656950c6ec5
-ee50c9e48786dea0d9df2e45805c25565c100fe3
-11dacc6154c42bc6fe3ba94c1823f8a46e4fe81a
-791a0e6ddade27d1b69f4861a6640de60b9553cf
-638e6c59da4fad987c437592174b188510193b2e
-52f8877525d5238f3440e73710507be889d14127
-2a56baf395bf11835d784c4f8634f4525deed6a1
-bc561b4b7d6a3f71649d37d5eb9047c29efa2b13
-31809d6f8514c4a8d5677e947e3f1ebb0db210b9
-a31e9ad4f027955d43c04a05517244647e250161
-777519bd96f68c18150a0f5942f8f97a91937f5e
-4eb1f39d421024d9666cec61deaf96715ffae4c6
-50fae68d416b4b8ec4ca192923dfd5ae9ea42773
-ce665863b137ac4a7470cf006a92aa7694faca71
-81f8c0378b2ab5ea0d7b65635cb529bd3c69127c
-108222b9c323a05cc9339368f10ddd0859f62b43
-28f788e47e58f2b462351d6989348a4e1a241b2b
-d81dccf191a48a6b59c3747d7b4ccbe3535dde40
-a90e6d2bffc422ddcdb771c53aac0bceb970a2c4
-91e49c51f1aecc9e1d75457f4920d52a4b0a133c
-60dd9cc470584960431de425e2a9ffbed0e8034a
-ede386c2193fc31351e193b3a8cf30030d6be62c
-a084767b40c0d3ba8fa8f8d60f1e8d99a9dc3457
-3f726c99f819f97f2ab21b94d34c6b3129cd883a
-77fc469fc78cdd87c29f398d46ac58dbb9ef62c0
-4ae6d0fbef60ccbecf8f23bb482e201b3678f7a3
-8858b6ddd3bce9daa08da6e05de3ca863a399c15
-22e301a3d56dc9e6878380ee92c7d19ca43119d2
-c484ec6c9b85ca4e331e395c564ae232fd0681dd
-a46a671e253528e450bd57645c400bf761da07ab
-655970d9c60ae6850daf452457e14e21047c0e1b
-b6a48914c50631914192aa11b19205436a9c664d
-7db65c363a0cc6ca7cdb04de9a973ab70013baad
-6366941275344dac7e2130b0c972e90117d37ed0
-4fb2586661471a1572c2df2a5a091011d45eb7c4
-d7be7b39fa1021ec4518186afe145ee948e12a94
-85aec87b11ec41295558175c63f1f5a849460fdf
-aeb31756276034dd506fdf97c8aaade0e7e584f5
-ac016e17d20253129a0287cee7e1d06b7ef15966
-bf74d377fb8e20140da6eac1407414928384bcea
-2c811e08db651a4aed6ea0f7c1972d60de6de8ab
-e5d26e47c7a482c072a7fe47bb84c56854734184
-96a63a3e0cefe920819bd42add0041837b1214a1
-e526ca6284b9e13be1b912b80dd73a34e739b539
-ecd21357f16106e541e9c2854ead2a906659b938
-4b5a7ce0c301ad971f383eb60f61bf9b4026efda
-929fd7276c0f0c30b9416f61a6f5f35d763d81e4
-fa8a0639f7b0ce04030b72b4d5be4f0aa36fc5cb
-f1f1605c22a6283bbfd757055fcf2b584a857709
-0c173a15ca1bf20999f74987988985508c9de463
-df0793f324e33066cc746c0cb1d053d35733d626
-2b0179d8a9b75397937126b36114df0dddeab40c
-bf0a08be281dc42241e7f264c2a20515eb4781bb
-3895e25a77363ae8b49358fb793f50fa8b271e2d
-1fc783fc08bc078239537535f174ab8a489772c0
-1d4805ce04645f3203b0cfd3d66ea710e7433eb4
-d3b58704d1d325875fc605580c1c02b825c1bbcc
-ed88e3194c4bc43aeafef929da7b419d03dea1ad
-dd07f47b79628668e29cc0143b21e790100ee445
-65cc7aacfbfc7b747926375280a1d839e88d576b
-080ec5209172ac9605f1434559dbb3c1e012b10a
-416af3edf5b5ab265acf95568f2bc9eabd3d96de
-e0a7801223fd573863939e76cb633f1dcc2d22c4
-4bc853b50fd9127687eb9e4f3b679dd261a4fa96
-c68a9a69278aa194fed96bd9733d32af3690a11e
-c38f540298f0e188df5ed68fd56c623b9ac8331b
-643fa0b22d70e459d7f7ec3d728ae4811dc5158f
-e053e05c130549f43953f1d70e724dc9ce3e1b85
-75e898c094eea533d1dfaf141c6afccc3072c49f
-2805d606bc46bf5589093a1b92d3542c13ce50c2
-32751807c9c06011eb689cba56b401a6302699c0
-30853e16d332816752dafcfca92147c7ffef5b54
-bea5b00cfe95cd37832305c0f93c339a22a7d79d
-c871f323b418fac27bf834843ca26985010df53f
-329fc1dce7a1c372c8b10c2f2f8732b2c60daff0
-1aefc94dd78d6e0c9209cb09fc16f53dedf42108
-8e5725666b519b61fcdc3141da5c6a57c1959909
-a4ca0b042365061020627a8c045cddacea3312ec
-8bd16ee12fc8ef6723e0572c29b979c15b92b4f4
-87abe20fc118721cc5efdbd94a8462468cd1da2b
-4b766fcdd4ca16399075d1e081a321b3b05ce516
-f6241b3e420e19f3f0507cbbc872fe9218916a02
-7ee523604851af62c0a47c07ee023a8710ef32f7
-776ba233e939fe41a74c6b2632b93a0679a32c71
-6a796b2b53fe542e0f340f250f4f20d69efed8d0
-23d78c4dd01bc74ba35db3e3df95280f6f1b2e22
-f4b15e2de97c4f8cdbb40bef4c9d0ab2807974d9
-fff72de5bf8ac7b70208e655f237b80e70e18851
-170bc2c381f86a523de2fc8b71d62ade66303c0d
-314ebdfcb38d4b4c977579f787d5e1a20d068c94
-e9274839bf316b1972d80d28e45759f898edbf86
-75171f099e82e3527d7c3469b15891bd92227ec2
-3c5e6c94caf40395e031fbde44a0cca46fdd76ec
-dc8fc0c73bebbc1c48ac5540026030c9cc00ec23
-492d22f92919d8d9d59568318c26c1e2ac4890cc
-80c3a734298e824f9321c4efdd446086a3baad89
-47535d7c3ec79c5978cdcc03a5351ddbbb22538d
-1b25b6df0f08f7474228c5b6ed13b58682e1e440
-c530c15180631cea95e9c292cf7fabde9dca9db3
-2723bcdce3248417e98e6c43207bef74d34076c1
-ed22eb4a62bd8d5369aaec87d4cbdc03c9f16368
-9111df9673beb6d6616d491a5478f09b5f14d040
-d86bb075bf6d1e78c1e4f3dd38b0ea828ef5ecfe
-50a1cc0f0aef1514b917a5a3f4476967170b429d
-6ce733747e160ca699711f2c47e686284ca9aa07
-b44adf92342ad4f9c343ba29c081a91687932936
-88799ea1b1c08f4bc1a487c9e3c2effd5e1650ae
-080d7c700fc3291560d79fc590e05b8e2bad984f
-12af74b289f8cdc6caf850dc6c802f9936b1e8b3
-8e4f7e72410df3ba430082c7cf385f26fd75b033
-8ac80412867118172dc4172494304e19969e9489
-f2734c2828f69d9cfd535e5eab0592a7674b2b61
-0b9fb682890b8fe10cec54072b809a5efe57d33d
-5b029aaedb5fcf7cadd249607dd28eb3f233ab8c
-79af9fbd8c3c0e54702a9c92b171f134bd4466c8
-c412fd805ddf3282dc2e1f28e30f51ffcb1f1da2
-111849345bb5140f86b48e730ceab4bff45fa2e9
-a0b1e57b20a17177ed5a9a54e4a8aab597a546b4
-ca209230c8e73745cf8cfc79f500c9c46e103306
-a230b0588788dbe1ac84622aea169c577b381241
-dfef6b6af08097f0676a2323085558fbbd3c48c6
-3192e5278abca7c1f3b4a2a7f77a0ce941c73985
-7c7ddd9ead99a8b5033a1a5d4698032c9e2b3a92
-10b930dde8f14e9cb661810e97a33bbf144fc55c
-9225de2cf652fe2bf6e50636824cdb641546f57d
-598ef9c44b3ea2cc142c175f077b493f39f5ba22
-c49355c7170a64bdd7864cc3ba9a64916b67fe7c
-857d1e171e051b254a617f27b39f6a551054cee2
-21833f9456f6ad5bc06321ad6d9590f42ce0195c
-8910b4717e5bb946ee6988f7fe9fd461f53a5935
-5703dff0939f05c7457cebd6fc61d88ab13afe41
-8bfa13b15b84cb372950fb7b25a1080173060b6a
-ac23a7c1f19b3d8c326ffe75c8e13edf285f90fe
-19be26afe3d04783a92d032b55bf3fb1e2ae63cc
-f7ec7cfd38b543ba81ac7bed5b77f9a19739460b
-36afd4db4442c45d4078b1a7ad16a1872b5bee0d
-88c2ae3ed2bb5d367dd408c9255cd8f1e7a36c7d
-a13a417cdcfdfd1f1b3bf997bb6ffe6e69b096b9
-d6064a89ac97dc0d2ce9da3982e1a4e25afaeda8
-7146d96de3e15a80cafbab2af48ff6f65d8e41bb
-5628c70f2a44567695e5331fe2293c5b7f35b629
-7ff4a538a8682cdf02a4bcd6f15499c841001b73
-aa5fa642b0e7ce2ea55e2298886f212f11a8894e
-8efd1c820b9a782d8608d54d924658536178295c
-50a226563cd8d7c0a5e8448e87fede0eb72a8354
-b860915f8b0dae98e57a254d11575ea41f5c5a79
-d304fef3746039183f51b3ac8f4774dcf3a64f59
-53ab12d9318d5d195ccc77028b0e3ae66dc6e1fd
-668de70be039a4f1ffcf20aeae2a22ee71fc55a8
-0fea960ca917b73aff853fe88476174c8a313863
-f89502306dcf6393a2c7b0efbb0fa728fc582137
-ff58b1c3bdff5e5f687f10f9e40ce495ca49674e
-0b96abc35f1a9d46a27eeddd7df418d107c29c57
-b0b57a17306a7e963a4fe463f84e2b150a00a859
-4105cb6fd964ad13099ca83b1fdf3d35f3961f74
-23281a4dc3afc42a001346caec4dbb8193f0bb53
-8daf103fa138f9a184448ebf1c2e03b9dbd96f21
-02e5308c1b9f3771bbe49bc5036215fa2bd66aa9
-a65ced1a66575c652baf5084644b8647f531be8c
-2456a835f0bc7796d9ff71f64837fa6790e2b7cc
-9ec1330b455c1ab2eb6b89f8a2ab885677d4ae8a
-0b738075bd43fbd4410e30a51e0498cbfd2b7513
-98c80e374b84e5a9c2d5c36889a0b1ebed5b814b
-25720fc394e27a951bcad26095fb5a711bfacb8f
-4cfd57d2e38207d78722ce8c9274ba8dd700d1cc
-0fc1c31a878e93d938c67db3f958e82e3c39659f
-df1ab5b4d67b46b5e9e840b1fbe0ff02520831f9
-5bc3b6cede8dabdf3f4f27ddb03723cbb7cde51a
-c2ea1e6561caba3abffce361abc800822b9e0efe
-caa2f106d704ec3ade63498031dd58d34510bc76
-dce853ef76ef90c46d84294225088d595467d08c
-dbc8a8c86ae50059fddb2d6834fa5f0c9bbf9b71
-0f921e6a0492c4e9f037a9ed91f474885032d68c
-041331e1da23e4136fd046ed870cdcc177464176
-e6ba5068f107ac234576e77cedbd748b665369c2
-76fcd9d5034143a5b041766552670d19f926097d
-72bf1b3d0962304850a3ef5fe375db4bff1d0a39
-919db037f1f5cc73cdcaef92dd9cb0e7f5c8dec3
-c36229b0b2e9d4554053f5c9fc451ac29a493b1f
-9e4bb312e6958d2baa309ba670e5eed1523c6f47
-d7ba4a233bd5a6f8fadee681c68a995e23fe36d7
-98514988a3d3e8b7dbf0463884a5c38f5ed5562d
-5412c08c3cf13577566064edd04da021c37b7cbe
-31bcc667863f368157efa1143a78623a5db8f0d1
-7bd1aa566fb4a4fe194f209085649f2c722b0cff
-c4522e71c7e1d8ecfd70112e9375b9d00d6733a8
-e22f409f18881b63a8e747036584a71217f40e6e
-97ec6e5c9098a1240655cfcab05b6cd5eedb6cd1
-bc121b0eb19713ec72002b5be03ba5ac35903a17
-c98f6b3d93a2cc1b49a6db425ea2b661089d0f9e
-0de7fd36de57a68e543b4c1f184fba192c398c73
-e662d281b837c25b2b70525aa8fe8af894339823
-44adf683ad232db8ce0cb89b3e236a1f5944cfb0
-cb2ed300a89ebf9f0654da869ced665ed8b2abe7
-0a6d48d9ed60b0b02177059ab116f8f46d2cbed3
-b42291334651fff46dbfe5947a726f65cb9d7dfe
-e5364991daecb73aca3bb5ac37f2619d7a89211b
-4a2b170c075ce703cbdc82519a48016a9ee3f99c
-924de0bd75a7f75df65d7d15f9d1587a2e794abf
-1253f8692fc3a11be9430685cd405236a68df6c3
-2b799ae9e1e0a540f9a5971ddf27d83254668279
-c9bdf9a75f9fde8cd011e4aa94be4ed4347078a3
-3d69ecb4edeb80003a1a41442e320898a30dbd9c
-f08222e882b18c1f279308636e03beceece2dbf1
-23e03f8d26d7bd03273a5dcbdcfe3905dfb49ffb
-03dd707dc027fbf6f24120213f8eb66571600374
-d0754799698de2c032abcb8198ee5d5401063213
-072116fceb2294b97d1c40f79305f2e3ff71812b
-e66cc1d58e16bf1650dd6479fed64ecaca8c6098
-f137753a2dcd8229f89d1d1ac28039364e5850b4
-61d191fbf953700ba8aeadc9c8cf4c195efbd10c
-76f3c02fb01a6df98fbd8c16ac21d159d4649d37
-6013c73b3312e11b447ed387426749014716f820
-6faffb8a83db3f209a303a4464dbdd597faad5a4
-cc9e8aca5f950c78dcfeff63c441ba993c1fe12f
-8ca69a2a88a77eb06149fa049ab1a7e6de38b321
-2f71490d21796594ca6f55e375558944de9db5a0
-08cc5fd666456cb476467473ed1880c90c92dedb
-e31a43c725ebe641d7c219c3886eee18eebf0bb8
-52b5a8785de760a204b2b0aab19dfaf79c2c3ff0
-483e8e4f4875a1a621ec9e9df2880d3037d95ed7
-1e5799c52535a3fc20e885916f1e7ed33ecc7f46
-a82e5d8220bbc8b5d786bed99b0876f530b9b7cc
-7fe6c5c993706e8395cdaf7977bee793c06f48f3
-2a0836f6d5e7c1d7e97bedb0e0ea33dcaf981f77
-ddc308068d69c6c9aa629ee3c4ce75e1d1cf08b5
-ec139a5621a9c9f03e1988391a3c7c6c5d849776
-c01a6c48b982d625fd9f4f69005878781d3d56fa
-95a983d56dbda457e3bf8766d59bac74c7aa5699
-760741a00833876976389ed7a6b73f36ee5b4c13
-6e5e5abba6f8bbbe61c22795df440dfafcfdc378
-cf2cecb18779ce83de9adebf382dff1c19b12840
-af9b7a9f2f73b1a2f9728106774dd13e8d1cdd8d
-115735d547fdeade822f547eb3e8c8f9961a9b07
-c2c69edf37b5c02aafa01d0407dadbf5ef8751b5
-a072d1a83787e786d074a4b5871b0b961781f7c6
-ed2cd59e258f756b2eaed7909a60956ade6ef7ee
-ae5575ba41c8a782805afb1c08730343cfc22397
-6ff2c8d29f6b5a5c2ce63f0a16f3bb0dbd049451
-a80de15113166354cdf208e3d8b6e25f4511a591
-06bd4f637f15e769f088d9051a5af94bbb0217a3
-6700cc993cc07fb0f5b8b577ff8c4afcf0b18274
-37f9a1f627c0995d89b62923e75cd092600894f9
-8844ef15ded02d5ed86fb95aaf251235fcef2396
-1b87e5b5b184a0a6c683eda23b36393822b57f03
-e2bf830bb6c1bfa038c943dd6f5d92a406bd723f
-423ca302a3ee87000530da3c105f269b8fabece7
-4e14afe42fdd468d5de11df8cc13defdcb8e83f8
-3e90fe6534206412ea22beaa445cf20d28fbe718
-88b77c7da0a672c89e24df37ea6e9085b4e2a05c
-0ad104190465d8d65c2344bbe10dcf3df025d86c
-5c7df7022bcd360e6af00b9458b1a3fd54e1cc9a
-59ad56851a342d2c62f6b38bf15002b23ab439e1
-d8cd7b137fb075616f31d2b43b85fa2e27ea7477
-655937ebcbf681ededf86b1f0f60aac45c73393d
-abdfd2d0e3ebec7dbead89317ee9192189a35809
-e439aeb30c0439001a781c5979aec41e1fc2aa50
-b9b26d9c3615d15669ae0a049c1dede39a9e59a9
-fdf146f3293c487afdc4d6d9f6b64099aa8bd28a
-16e3b175781caacee403a2dc40cd6c70448e12ef
-b30c62d4b954df05bf404cfbeb5b728282201496
-b3f377daaa86cd7755a552fa3adfeb195835f58e
-0a8f519a0626d7cd385114ce610d23215c051b3f
-544f3234384b2f6c290e987ad18576e1b50d7db9
-91482e5bf22d283d32c9f83c8057f10971848107
-e754c6e33194e9ed69ba5350c5139b0423b645fe
-dc1e54206d76e5fa378d28a18ae1fb2bcf714485
-b2863c0685a5c12f829095cbabaf26ccc49e46ec
-b14db5abab405a708f0166293f1ea12222a6bf03
-8010ded6da56842c09b14665343cd189d7e08401
-d387507aeca652a5569825af65243536f2ce26ea
-27bf14f6f3e0fb1f348f13c1b54fc6b67b3bef6e
-f8d470e24606297dab95e30b1d39ff664fbda31d
-b25a4c2284babdf1e8cf0ec3b1402200dd25f33f
-1329ef1f00e4fad83937ddd8721d0292ccfe7808
-9a1ad2c5cbdfa3114d05df57103c34f72e087f26
-1e90862f5d0b5f7dcc18fb018b2bbaa323dcca1d
-ad552a54c56a420be84b47154882c3e4c76f9bdd
-90b1c7e5c50551f39d4983008d1d5ab3b085803e
-d6b2235ca45e072961e25a35e6a159e97c9e556b
-2643fa50869f22672cbc72ac497d9c30234075b8
-01f909828d126d5443bc28758f51781eccdf5848
-f54f3738c8ce839c413d7b6b719be2ff341536ca
-418ae49ee1eac2c9d6cd4ba83c036a41f1afe922
-5a666428b0f11d62af2002bd54a45ff2f79f30cd
-a07e8caa5d5000286604458e6887f57fec7fdcbb
-8b262eb2d80bfa27ae8501078ce47bc1407e9c55
-5df84de583c900e00fef63bedaef32786f205a33
-4ba6da55743a55189164e29e45ac9e73a074d808
-88430cbab4dca36b6a867364cab319cde6a9ebca
-e0f7515f5500968c86e5a9f4912d83d4abc5b2b9
-9b8b1079ddab64ac955766536c38d23dc57bc499
-af20f9b1d485582b8c8aa8294bac4f2c540246d2
-7be9a9a570c1140048f8781ced1111e1d930e517
-2bac3e484114c30548e286972525dd799dbd0a5b
-df529dcc65e8037c5a3a3ad74545be294a770f07
-6acd8700bc0ee1d10207a362c1e07372ba274041
-ffc6e48b2983189dc0ce7de0a038e5329bc07b1b
-252ae7111cbff09a4cbc5caee9e02b6ed3580476
-b3ecb7bab6074377d87c700bf0c5d351e5d3174f
-d9fdac130a5ed1d96fcac6bb87c10bec9d596b17
-a07e8caa5d5000286604458e6887f57fec7fdcbb
-8b262eb2d80bfa27ae8501078ce47bc1407e9c55
-5df84de583c900e00fef63bedaef32786f205a33
-4ba6da55743a55189164e29e45ac9e73a074d808
-5bea05bc1d17aa43cbdf3a3413241f8132790d93
-c17f11f7b43ad3bd9e242c67db1f3679558a0581
-5ea932a51083837cdd27715e10a3a0d5d553af24
-033c78671b91b12d589ebff6c5ede8d94d7500f8
-ef8a634358848847e006c43ce621bc17a612fd1f
-ba216b5fa63e7e6cae847d1e3621f5c54840f898
-26fee4f6bd9aec62c6caa60683ad66574cf16aa6
-6ab0e4cf49549640b903bf5fce0e6035b8116397
-326a5652e0d25fdb60c337ef4f1c98a63e0748f0
-424be03305143cbe5da5d5adb54d73d3dc3747b6
-38c201f47c0bc388a05cdb35d6137150fa90193e
-12ed800ab870e0fc527a84d6e4584b10c8d239f5
-aeed345c9bade5d52a3fbf0a943203f6c82e6344
-c6223b3daab0328ca742b1cc3c15e89e698630bb
-877678710800a4d78afc12519424f232f1a583d3
-6c4fecfaf7beefad0d1c3f8520bf50bb515a0716
-98212745c8acb5cc4e688bbb3979bfd46b25f98a
-b9bceaf1c081a84d9fcc680372614e797b168a9e
-1afc22a7667a7a5c66b4b5d7f50832356dd5ec12
-3255d6347b1f9eccbec3d6d93d4a424087a3b35b
-ec20f01ba0945a3113797ac98a6b3500e24603d4
-75b5643c47c3b382ed97a9f5e2bdc883a0f98709
-fee0d803fb55c8d85b5cd1ff69d799c5ad522e18
-565494619d809655fa94d274bb2202d25553e485
-ad6fce67b9bb6eee864c8431ad3291aebaa2e5d2
-99c7db8731cc77f143b52f544b3fdd93033ed20d
-b4d03be3cac04da8b5d5fa17e29c5220b75d970b
-ef37f2033c4ae104585cd980141262f95d33166e
-5cfdda2503c995cdd563b1a2a29162ac298d173d
-c5904e871479514b2e2e18b4fdbbe468c4e5ec8e
-10b22e3141a603ec891d2cfc7100c29c7409aabe
-afd2fca911c4a5e3a4d1f0993a226d40f250aff4
-505955052e60e0681865f3064e005ca0d3aa90bf
-8fdd23a224ba236874ef662c4ca311b002dbcab3
-1c011ff430106b5f727f2eaa0f7f4883cd2122a3
-ec8a50b8d786a8cd1192e692ab19b46979add582
-f90603ac6d24f5263649675d51233f1fce8b2ecd
-b7d6623c76e1468f2a93db5a3120580e2784d74a
-66270a416edb1610f276124483feceef9cba93ff
-e4fcbf797ed3b472d352ac3794ec82f581209c50
-479afa0f8486146a35f1fb96be1826061ecbcf23
-2a09a3891fde052a585dc019eea9fba26d42445d
-90a002ea647dcea57a2ed4294eab77897168ba1d
-30c21306c17165c3925fea4ac9d1a4763c6d2a99
-b3eb0d6485510f2bdf36d256ab60ce29b8213744
-efbcf2b1d5ff4ee7132eae9c9e203d2b875c545b
-b33ca14f594e2cf2a16ef27778169deb7cc9f4dc
-d636f3943d39ec893dab2d2546f77f3f2607769d
-cafe24f039e117d53288387c2720f44f27deecd0
-de8db47b7ff351f3287c5efb85102ba8836058d6
-d76e84a21416ef77e78138e326d4d249454e79dc
-7a74f88a26cf251ba36b26f604f1ac9940fd9c92
-1ad3d4e1261f4a444d982a1470c257c78233bda3
-8d9f45ea6a5e4220e44d34139438eea75a07530b
-c98ebf1bfb29a8203b5090412afeb333384213cd
-f18bb49547095020a30e81b648075bc7e707515c
-76f268b9bd1b69eb7784c5324abbb67f3e395b97
-e801084decf4542d57cf5ddb95820643766a172a
-be3e042c20e2f3449b7b55d1cab0a80b0c6f00af
-400fdd08cc95f1e85afafd07ddd9c0bed11483ea
-098b01dc58ff555c473ae58c92c34b03a77eda5f
-7cc2c670e3d7cf26454ac8547a94ec2c8ca90b34
-1088b02f0ccd7358d2b7076bb9e122d59d502d02
-f94b7d5bfa911ea7125920589723ee63a3eec9f0
-b4b057a3e0712dd16b50cbcfe7d613e4413ffa1c
-b40ceed98a112f4f0d07351ce07270d9ff2bf796
-4cb8757aae1ae31e5519d81e854f44ed062d9836
-f2f7e97e8cc24cf7a2b7954cb74ecfd0f91a95ad
-ae786098bc58b1ca92f596a698b23aeade9cd2cd
-c33652576ce21694b33a94832378f737dd6959fb
-e317c0d19201ff75fa7afedf93a9d1cd2c560af2
-bee35299716cc72cb7d5bd4daa9fddca05c58378
-318ea50a1c2f612e750a93e36620dd0c4531e9cf
-b6ee855b411ee9bc39f935d0da3298a773a2ed37
-daf3e7def7b9e5db7a32f5a20b5c4e09e3f0dd18
-bc64b5aa0fc543fe8fd3dbaec275f89df44dc409
-3f57c55dba6ef1fda2bdf6fd9abd8ca7eb6828e4
-431a548faaf51c7a5fc89b6e479187a1c0e29805
-e4bbd3d230f22401ba0a0a72c8ed41ee1bd098a0
-c45da32047cac54afc99cf9b8a539389c577ded1
-ab1f1d32469180b3d011e9625d67c86a22b55903
-a550f6e415fd8aec8c45d4704712a408c37ecd18
-c73af5416b66f09cec0eb106f5a10f9bb6ef9cb1
-a077a90da88f12d9f10c8b85840bdb847a98b0a0
-c5e9e428a9198c8c4076f239b5eaa8dc95e7985b
-b7365f0545b1a6862e3277b2b2139ee0d5aee1cf
-4bd0e9b90a39c5c6a016b83882ae44cb4d28f1f8
-7438ceac716fdfe6621728c05e718eaa89dd89aa
-4e3efd47e0d50c6cd1dc81ccc9669a5b2658f495
diff --git a/contrib/verify-commits/allow-unclean-merge-commits b/contrib/verify-commits/allow-unclean-merge-commits
index 7aab274b9a..e69de29bb2 100644
--- a/contrib/verify-commits/allow-unclean-merge-commits
+++ b/contrib/verify-commits/allow-unclean-merge-commits
@@ -1,4 +0,0 @@
-6052d509105790a26b3ad5df43dd61e7f1b24a12
-3798e5de334c3deb5f71302b782f6b8fbd5087f1
-326ffed09bfcc209a2efd6a2ebc69edf6bd200b5
-97d83739db0631be5d4ba86af3616014652c00ec
diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh
index db5bfce208..cfd68e45b8 100755
--- a/contrib/verify-commits/gpg.sh
+++ b/contrib/verify-commits/gpg.sh
@@ -5,12 +5,9 @@
export LC_ALL=C
INPUT=$(cat /dev/stdin)
-VALID=false
-REVSIG=false
-IFS='
-'
if [ "$BITCOIN_VERIFY_COMMITS_ALLOW_SHA1" = 1 ]; then
- GPG_RES="$(printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)"
+ printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
+ exit $?
else
# Note how we've disabled SHA1 with the --weak-digest option, disabling
# signatures - including selfsigs - that use SHA1. While you might think that
@@ -20,12 +17,12 @@ else
# an attacker could construct a pull-req that results in a commit object that
# they've created a collision for. Not the most likely attack, but preventing
# it is pretty easy so we do so as a "belt-and-suspenders" measure.
- GPG_RES=""
for LINE in $(gpg --version); do
case "$LINE" in
"gpg (GnuPG) 1.4.1"*|"gpg (GnuPG) 2.0."*)
echo "Please upgrade to at least gpg 2.1.10 to check for weak signatures" > /dev/stderr
- GPG_RES="$(printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)"
+ printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
+ exit $?
;;
# We assume if you're running 2.1+, you're probably running 2.1.10+
# gpg will fail otherwise
@@ -33,33 +30,6 @@ else
# gpg will fail otherwise
esac
done
- [ "$GPG_RES" = "" ] && GPG_RES="$(printf '%s\n' "$INPUT" | gpg --trust-model always --weak-digest sha1 "$@" 2>/dev/null)"
-fi
-for LINE in $GPG_RES; do
- case "$LINE" in
- "[GNUPG:] VALIDSIG "*)
- while read KEY; do
- [ "${LINE#?GNUPG:? VALIDSIG * * * * * * * * * }" = "$KEY" ] && VALID=true
- done < ./contrib/verify-commits/trusted-keys
- ;;
- "[GNUPG:] REVKEYSIG "*)
- [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1
- REVSIG=true
- GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}"
- ;;
- "[GNUPG:] EXPKEYSIG "*)
- [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1
- REVSIG=true
- GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}"
- ;;
- esac
-done
-if ! $VALID; then
- exit 1
-fi
-if $VALID && $REVSIG; then
- printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null | grep "^\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)"
- echo "$GOODREVSIG"
-else
- printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
+ printf '%s\n' "$INPUT" | gpg --trust-model always --weak-digest sha1 "$@" 2>/dev/null
+ exit $?
fi
diff --git a/contrib/verify-commits/trusted-git-root b/contrib/verify-commits/trusted-git-root
index 1c42195961..7ec318e1ea 100644
--- a/contrib/verify-commits/trusted-git-root
+++ b/contrib/verify-commits/trusted-git-root
@@ -1 +1 @@
-577bd51a4b8de066466a445192c1c653872657e2
+437dfe1c26e752c280014a30f809e62c684ad99e
diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys
index 5ca65e7b0d..94daf28b15 100644
--- a/contrib/verify-commits/trusted-keys
+++ b/contrib/verify-commits/trusted-keys
@@ -1,5 +1,3 @@
-71A3B16735405025D447E8F274810B012346C9A6
-B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B
E777299FC265DD04793070EB944D35F9AC3DB76A
D1DBF2C4B96F2DEBF4C16654410108112E7EA81F
152812300785C96444D3334D17565732E08E5E41
diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py
index 2ff14c1f86..f301964280 100755
--- a/contrib/verify-commits/verify-commits.py
+++ b/contrib/verify-commits/verify-commits.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Verify commits against a trusted keys list."""
@@ -92,8 +92,10 @@ def main():
unclean_merge_allowed = f.read().splitlines()
with open(dirname + "/allow-incorrect-sha512-commits", "r", encoding="utf8") as f:
incorrect_sha512_allowed = f.read().splitlines()
+ with open(dirname + "/trusted-keys", "r", encoding="utf8") as f:
+ trusted_keys = f.read().splitlines()
- # Set commit and branch and set variables
+ # Set commit and variables
current_commit = args.commit
if ' ' in current_commit:
print("Commit must not contain spaces", file=sys.stderr)
@@ -102,7 +104,6 @@ def main():
no_sha1 = True
prev_commit = ""
initial_commit = current_commit
- branch = subprocess.check_output([GIT, 'show', '-s', '--format=%H', initial_commit]).decode('utf8').splitlines()[0]
# Iterate through commits
while True:
@@ -113,17 +114,41 @@ def main():
if current_commit == verified_root:
print('There is a valid path from "{}" to {} where all commits are signed!'.format(initial_commit, verified_root))
sys.exit(0)
- if current_commit == verified_sha512_root:
- if verify_tree:
+ else:
+ # Make sure this commit isn't older than trusted roots
+ check_root_older_res = subprocess.run([GIT, "merge-base", "--is-ancestor", verified_root, current_commit])
+ if check_root_older_res.returncode != 0:
+ print(f"\"{current_commit}\" predates the trusted root, stopping!")
+ sys.exit(0)
+
+ if verify_tree:
+ if current_commit == verified_sha512_root:
print("All Tree-SHA512s matched up to {}".format(verified_sha512_root), file=sys.stderr)
- verify_tree = False
- no_sha1 = False
+ verify_tree = False
+ no_sha1 = False
+ else:
+ # Skip the tree check if we are older than the trusted root
+ check_root_older_res = subprocess.run([GIT, "merge-base", "--is-ancestor", verified_sha512_root, current_commit])
+ if check_root_older_res.returncode != 0:
+ print(f"\"{current_commit}\" predates the trusted SHA512 root, disabling tree verification.")
+ verify_tree = False
+ no_sha1 = False
+
os.environ['BITCOIN_VERIFY_COMMITS_ALLOW_SHA1'] = "0" if no_sha1 else "1"
- os.environ['BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG'] = "1" if current_commit in revsig_allowed else "0"
+ allow_revsig = current_commit in revsig_allowed
# Check that the commit (and parents) was signed with a trusted key
- if subprocess.call([GIT, '-c', 'gpg.program={}/gpg.sh'.format(dirname), 'verify-commit', current_commit], stdout=subprocess.DEVNULL):
+ valid_sig = False
+ verify_res = subprocess.run([GIT, '-c', 'gpg.program={}/gpg.sh'.format(dirname), 'verify-commit', "--raw", current_commit], capture_output=True)
+ for line in verify_res.stderr.decode().splitlines():
+ if line.startswith("[GNUPG:] VALIDSIG "):
+ key = line.split(" ")[-1]
+ valid_sig = key in trusted_keys
+ elif (line.startswith("[GNUPG:] REVKEYSIG ") or line.startswith("[GNUPG:] EXPKEYSIG ")) and not allow_revsig:
+ valid_sig = False
+ break
+ if not valid_sig:
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)
@@ -153,15 +178,11 @@ def main():
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]).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']).decode('utf8').splitlines()[0]
+ recreated_tree = subprocess.check_output([GIT, "merge-tree", parents[0], parents[1]]).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])
- subprocess.call([GIT, 'checkout', '--force', '--quiet', branch])
+ subprocess.call([GIT, 'diff', recreated_tree, current_tree])
sys.exit(1)
- subprocess.call([GIT, 'checkout', '--force', '--quiet', branch])
prev_commit = current_commit
current_commit = parents[0]
diff --git a/contrib/verifybinaries/README.md b/contrib/verifybinaries/README.md
index c50d4bef71..ab831eea28 100644
--- a/contrib/verifybinaries/README.md
+++ b/contrib/verifybinaries/README.md
@@ -1,16 +1,5 @@
### Verify Binaries
-#### Preparation:
-
-Make sure you obtain the proper release signing key and verify the fingerprint with several independent sources.
-
-```sh
-$ gpg --fingerprint "Bitcoin Core binary release signing key"
-pub 4096R/36C2E964 2015-06-24 [expires: YYYY-MM-DD]
- Key fingerprint = 01EA 5486 DE18 A882 D4C2 6845 90C8 019E 36C2 E964
-uid Wladimir J. van der Laan (Bitcoin Core binary release signing key) <laanwj@gmail.com>
-```
-
#### Usage:
This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org.
diff --git a/depends/Makefile b/depends/Makefile
index 11fdd6dd53..27bf804c6b 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -32,6 +32,8 @@ SOURCES_PATH ?= $(BASEDIR)/sources
WORK_PATH = $(BASEDIR)/work
BASE_CACHE ?= $(BASEDIR)/built
SDK_PATH ?= $(BASEDIR)/SDKs
+NO_BOOST ?=
+NO_LIBEVENT ?=
NO_QT ?=
NO_QR ?=
NO_BDB ?=
@@ -147,6 +149,10 @@ include packages/packages.mk
build_id:=$(shell env CC='$(build_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(build_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(build_AR)' RANLIB='$(build_RANLIB)' STRIP='$(build_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' ./gen_id '$(BUILD_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))')
$(host_arch)_$(host_os)_id:=$(shell env CC='$(host_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(host_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(host_AR)' RANLIB='$(host_RANLIB)' STRIP='$(host_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' ./gen_id '$(HOST_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))')
+boost_packages_$(NO_BOOST) = $(boost_packages)
+
+libevent_packages_$(NO_LIBEVENT) = $(libevent_packages)
+
qrencode_packages_$(NO_QR) = $(qrencode_$(host_os)_packages)
qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages) $(qrencode_packages_)
@@ -162,7 +168,7 @@ zmq_packages_$(NO_ZMQ) = $(zmq_packages)
multiprocess_packages_$(MULTIPROCESS) = $(multiprocess_packages)
usdt_packages_$(NO_USDT) = $(usdt_$(host_os)_packages)
-packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) $(natpmp_packages_) $(usdt_packages_)
+packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(boost_packages_) $(libevent_packages_) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) $(natpmp_packages_) $(usdt_packages_)
native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages)
ifneq ($(zmq_packages_),)
diff --git a/depends/README.md b/depends/README.md
index 66e1ddc4eb..11abbbd90d 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -62,7 +62,7 @@ For more information, see [SDK Extraction](../contrib/macdeploy/README.md#sdk-ex
Common linux dependencies:
- sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 patch bison
+ sudo apt-get install make automake cmake curl g++-multilib libtool binutils bsdmainutils pkg-config python3 patch bison
For linux ARM cross compilation:
@@ -98,6 +98,8 @@ The following can be set when running make: `make FOO=bar`
- `FALLBACK_DOWNLOAD_PATH`: If a source file can't be fetched, try here before giving up
- `C_STANDARD`: Set the C standard version used. Defaults to `c11`.
- `CXX_STANDARD`: Set the C++ standard version used. Defaults to `c++17`.
+- `NO_BOOST`: Don't download/build/cache Boost
+- `NO_LIBEVENT`: Don't download/build/cache Libevent
- `NO_QT`: Don't download/build/cache Qt and its dependencies
- `NO_QR`: Don't download/build/cache packages needed for enabling qrencode
- `NO_ZMQ`: Don't download/build/cache packages needed for enabling ZeroMQ
diff --git a/depends/funcs.mk b/depends/funcs.mk
index a00f380236..f0bbf4a168 100644
--- a/depends/funcs.mk
+++ b/depends/funcs.mk
@@ -76,7 +76,7 @@ $(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted
$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed
$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned
$(1)_built=$$($(1)_build_dir)/.stamp_built
-$(1)_configured=$$($(1)_build_dir)/.stamp_configured
+$(1)_configured=$(host_prefix)/.$(1)_stamp_configured
$(1)_staged=$$($(1)_staging_dir)/.stamp_staged
$(1)_postprocessed=$$($(1)_staging_prefix_dir)/.stamp_postprocessed
$(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path))
@@ -87,9 +87,9 @@ $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path))
$(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash))
$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_TAR) --no-same-owner --strip-components=1 -xf $$($(1)_source)
$(1)_preprocess_cmds ?= true
-$(1)_build_cmds ?=
-$(1)_config_cmds ?=
-$(1)_stage_cmds ?=
+$(1)_build_cmds ?= true
+$(1)_config_cmds ?= true
+$(1)_stage_cmds ?= true
$(1)_set_vars ?=
@@ -137,6 +137,7 @@ $(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$(
$(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig
$(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig
+$(1)_config_env+=PKG_CONFIG_SYSROOT_DIR=/
$(1)_config_env+=CMAKE_MODULE_PATH=$($($(1)_type)_prefix)/lib/cmake
$(1)_config_env+=PATH=$(build_prefix)/bin:$(PATH)
$(1)_build_env+=PATH=$(build_prefix)/bin:$(PATH)
@@ -213,18 +214,18 @@ $($(1)_preprocessed): | $($(1)_extracted)
$($(1)_configured): | $($(1)_dependencies) $($(1)_preprocessed)
echo Configuring $(1)...
rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), $(build_TAR) --no-same-owner -xf $($(package)_cached); )
- mkdir -p $$(@D)
- +{ cd $$(@D); $($(1)_config_env) $($(1)_config_cmds); } $$($(1)_logging)
+ mkdir -p $$($(1)_build_dir)
+ +{ cd $$($(1)_build_dir); export $($(1)_config_env); $($(1)_config_cmds); } $$($(1)_logging)
touch $$@
$($(1)_built): | $($(1)_configured)
echo Building $(1)...
mkdir -p $$(@D)
- +{ cd $$(@D); $($(1)_build_env) $($(1)_build_cmds); } $$($(1)_logging)
+ +{ cd $$(@D); export $($(1)_build_env); $($(1)_build_cmds); } $$($(1)_logging)
touch $$@
$($(1)_staged): | $($(1)_built)
echo Staging $(1)...
mkdir -p $($(1)_staging_dir)/$(host_prefix)
- +{ cd $($(1)_build_dir); $($(1)_stage_env) $($(1)_stage_cmds); } $$($(1)_logging)
+ +{ cd $($(1)_build_dir); export $($(1)_stage_env); $($(1)_stage_cmds); } $$($(1)_logging)
rm -rf $($(1)_extract_dir)
touch $$@
$($(1)_postprocessed): | $($(1)_staged)
@@ -233,7 +234,9 @@ $($(1)_postprocessed): | $($(1)_staged)
touch $$@
$($(1)_cached): | $($(1)_dependencies) $($(1)_postprocessed)
echo Caching $(1)...
- cd $$($(1)_staging_dir)/$(host_prefix); find . | sort | $(build_TAR) --no-recursion -czf $$($(1)_staging_dir)/$$(@F) -T -
+ cd $$($(1)_staging_dir)/$(host_prefix); \
+ find . ! -name '.stamp_postprocessed' -print0 | TZ=UTC xargs -0r touch -h -m -t 200001011200; \
+ find . ! -name '.stamp_postprocessed' | LC_ALL=C sort | $(build_TAR) --numeric-owner --no-recursion -czf $$($(1)_staging_dir)/$$(@F) -T -
mkdir -p $$(@D)
rm -rf $$(@D) && mkdir -p $$(@D)
mv $$($(1)_staging_dir)/$$(@F) $$(@)
diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk
index 7c76331ab4..bad4568bcb 100644
--- a/depends/hosts/default.mk
+++ b/depends/hosts/default.mk
@@ -28,8 +28,13 @@ host_$1=$$($(host_arch)_$(host_os)_$1)
endef
define add_host_flags_func
+ifeq ($(filter $(origin $1),undefined default),)
+$(host_arch)_$(host_os)_$1 =
+$(host_arch)_$(host_os)_$(release_type)_$1 = $($1)
+else
$(host_arch)_$(host_os)_$1 += $($(host_os)_$1)
$(host_arch)_$(host_os)_$(release_type)_$1 += $($(host_os)_$(release_type)_$1)
+endif
host_$1 = $$($(host_arch)_$(host_os)_$1)
host_$(release_type)_$1 = $$($(host_arch)_$(host_os)_$(release_type)_$1)
endef
diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk
index 2370c5b759..d607336059 100644
--- a/depends/packages/bdb.mk
+++ b/depends/packages/bdb.mk
@@ -15,6 +15,9 @@ $(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
$(package)_config_opts_android=--with-pic
$(package)_cflags+=-Wno-error=implicit-function-declaration -Wno-error=format-security
+$(package)_cppflags_freebsd=-D_XOPEN_SOURCE=600 -D__BSD_VISIBLE=1
+$(package)_cppflags_netbsd=-D_XOPEN_SOURCE=600
+$(package)_cppflags_openbsd=-D_XOPEN_SOURCE=600
$(package)_cppflags_mingw32=-DUNICODE -D_UNICODE
endef
diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk
index e3625d97f5..ebc097d686 100644
--- a/depends/packages/boost.mk
+++ b/depends/packages/boost.mk
@@ -1,8 +1,8 @@
package=boost
-$(package)_version=1.80.0
+$(package)_version=1.81.0
$(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$($(package)_version)/source/
$(package)_file_name=boost_$(subst .,_,$($(package)_version)).tar.bz2
-$(package)_sha256_hash=1e19565d82e43bc59209a168f5ac899d3ba471d55c7610c677d4ccf2c9c500c0
+$(package)_sha256_hash=71feeed900fbccca04a3b4f2f84a7c217186f28a940ed8b7ed4725986baf99fa
define $(package)_stage_cmds
mkdir -p $($(package)_staging_prefix_dir)/include && \
diff --git a/depends/packages/capnp.mk b/depends/packages/capnp.mk
index 8a3a14810d..f4778c1ecd 100644
--- a/depends/packages/capnp.mk
+++ b/depends/packages/capnp.mk
@@ -6,8 +6,15 @@ $(package)_file_name=$(native_$(package)_file_name)
$(package)_sha256_hash=$(native_$(package)_sha256_hash)
$(package)_dependencies=native_$(package)
+define $(package)_set_vars :=
+$(package)_config_opts := --with-external-capnp
+$(package)_config_opts += CAPNP="$$(native_capnp_prefixbin)/capnp"
+$(package)_config_opts += CAPNP_CXX="$$(native_capnp_prefixbin)/capnp-c++"
+$(package)_config_opts_android := --disable-shared
+endef
+
define $(package)_config_cmds
- $($(package)_autoconf) --with-external-capnp
+ $($(package)_autoconf)
endef
define $(package)_build_cmds
diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk
index 5bd12522a7..8374f2a103 100644
--- a/depends/packages/libevent.mk
+++ b/depends/packages/libevent.mk
@@ -16,6 +16,7 @@ define $(package)_set_vars
$(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
$(package)_config_opts_android=--with-pic
+ $(package)_cppflags+=-D_FORTIFY_SOURCE=3
$(package)_cppflags_mingw32=-D_WIN32_WINNT=0x0601
endef
diff --git a/depends/packages/libmultiprocess.mk b/depends/packages/libmultiprocess.mk
index 9b66207fc5..6da5693b3f 100644
--- a/depends/packages/libmultiprocess.mk
+++ b/depends/packages/libmultiprocess.mk
@@ -24,5 +24,5 @@ define $(package)_build_cmds
endef
define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install-lib
endef
diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk
index 99f5b0a8db..7ad2529e47 100644
--- a/depends/packages/miniupnpc.mk
+++ b/depends/packages/miniupnpc.mk
@@ -3,17 +3,20 @@ $(package)_version=2.2.2
$(package)_download_path=https://miniupnp.tuxfamily.org/files/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=888fb0976ba61518276fe1eda988589c700a3f2a69d71089260d75562afd3687
-$(package)_patches=dont_leak_info.patch
+$(package)_patches=dont_leak_info.patch respect_mingw_cflags.patch
+# Next time this package is updated, ensure that _WIN32_WINNT is still properly set.
+# See discussion in https://github.com/bitcoin/bitcoin/pull/25964.
define $(package)_set_vars
$(package)_build_opts=CC="$($(package)_cc)"
$(package)_build_opts_darwin=LIBTOOL="$($(package)_libtool)"
-$(package)_build_opts_mingw32=-f Makefile.mingw
+$(package)_build_opts_mingw32=-f Makefile.mingw CFLAGS="$($(package)_cflags) -D_WIN32_WINNT=0x0601"
$(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)"
endef
define $(package)_preprocess_cmds
- patch -p1 < $($(package)_patch_dir)/dont_leak_info.patch
+ patch -p1 < $($(package)_patch_dir)/dont_leak_info.patch && \
+ patch -p1 < $($(package)_patch_dir)/respect_mingw_cflags.patch
endef
define $(package)_build_cmds
diff --git a/depends/packages/native_libmultiprocess.mk b/depends/packages/native_libmultiprocess.mk
index 6e600c5720..e647afba5f 100644
--- a/depends/packages/native_libmultiprocess.mk
+++ b/depends/packages/native_libmultiprocess.mk
@@ -1,8 +1,8 @@
package=native_libmultiprocess
-$(package)_version=d576d975debdc9090bd2582f83f49c76c0061698
+$(package)_version=1af83d15239ccfa7e47b8764029320953dd7fdf1
$(package)_download_path=https://github.com/chaincodelabs/libmultiprocess/archive
$(package)_file_name=$($(package)_version).tar.gz
-$(package)_sha256_hash=9f8b055c8bba755dc32fe799b67c20b91e7b13e67cadafbc54c0f1def057a370
+$(package)_sha256_hash=e5587d3feedc7f8473f178a89b94163a11076629825d664964799bbbd5844da5
$(package)_dependencies=native_capnp
define $(package)_config_cmds
@@ -14,5 +14,5 @@ define $(package)_build_cmds
endef
define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install-bin
endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index 998cc0221c..b3600b72d0 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -1,4 +1,8 @@
-packages:=boost libevent
+packages:=
+
+boost_packages = boost
+
+libevent_packages = libevent
qrencode_linux_packages = qrencode
qrencode_android_packages = qrencode
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index d9ae918d71..2f7ddf6a5f 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -33,6 +33,7 @@ $(package)_extra_sources = $($(package)_qttranslations_file_name)
$(package)_extra_sources += $($(package)_qttools_file_name)
define $(package)_set_vars
+$(package)_config_env = QT_MAC_SDK_NO_VERSION_CHECK=1
$(package)_config_opts_release = -release
$(package)_config_opts_release += -silent
$(package)_config_opts_debug = -debug
@@ -261,9 +262,6 @@ define $(package)_preprocess_cmds
endef
define $(package)_config_cmds
- export PKG_CONFIG_SYSROOT_DIR=/ && \
- export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
- export QT_MAC_SDK_NO_VERSION_CHECK=1 && \
cd qtbase && \
./configure -top-level $($(package)_config_opts)
endef
diff --git a/depends/packages/sqlite.mk b/depends/packages/sqlite.mk
index 820d724214..a8ec89c6c6 100644
--- a/depends/packages/sqlite.mk
+++ b/depends/packages/sqlite.mk
@@ -6,10 +6,15 @@ $(package)_sha256_hash=5af07de982ba658fd91a03170c945f99c971f6955bc79df3266544373
define $(package)_set_vars
$(package)_config_opts=--disable-shared --disable-readline --disable-dynamic-extensions --enable-option-checking
+$(package)_config_opts+= --disable-rtree --disable-fts4 --disable-fts5
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_freebsd=--with-pic
$(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
+$(package)_config_opts_debug=--enable-debug
+$(package)_cflags+=-DSQLITE_DQS=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_OMIT_DEPRECATED
+$(package)_cflags+=-DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_JSON -DSQLITE_LIKE_DOESNT_MATCH_BLOBS
+$(package)_cflags+=-DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_AUTOINIT
endef
define $(package)_preprocess_cmds
diff --git a/depends/packages/systemtap.mk b/depends/packages/systemtap.mk
index a57f1b6d36..541ebeee01 100644
--- a/depends/packages/systemtap.mk
+++ b/depends/packages/systemtap.mk
@@ -1,12 +1,13 @@
package=systemtap
-$(package)_version=4.7
-$(package)_download_path=https://sourceware.org/systemtap/ftp/releases/
+$(package)_version=4.8
+$(package)_download_path=https://sourceware.org/ftp/systemtap/releases/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=43a0a3db91aa4d41e28015b39a65e62059551f3cc7377ebf3a3a5ca7339e7b1f
-$(package)_patches=remove_SDT_ASM_SECTION_AUTOGROUP_SUPPORT_check.patch
+$(package)_sha256_hash=cbd50a4eba5b261394dc454c12448ddec73e55e6742fda7f508f9fbc1331c223
+$(package)_patches=remove_SDT_ASM_SECTION_AUTOGROUP_SUPPORT_check.patch fix_variadic_warning.patch
define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/remove_SDT_ASM_SECTION_AUTOGROUP_SUPPORT_check.patch && \
+ patch -p1 < $($(package)_patch_dir)/fix_variadic_warning.patch && \
mkdir -p $($(package)_staging_prefix_dir)/include/sys && \
cp includes/sys/sdt.h $($(package)_staging_prefix_dir)/include/sys/sdt.h
endef
diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk
index 267ed11253..d715232793 100644
--- a/depends/packages/zeromq.mk
+++ b/depends/packages/zeromq.mk
@@ -20,12 +20,12 @@ endef
define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/remove_libstd_link.patch && \
- patch -p1 < $($(package)_patch_dir)/netbsd_kevent_void.patch && \
- cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config
+ patch -p1 < $($(package)_patch_dir)/netbsd_kevent_void.patch
endef
define $(package)_config_cmds
./autogen.sh && \
+ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config && \
$($(package)_autoconf)
endef
diff --git a/depends/patches/miniupnpc/respect_mingw_cflags.patch b/depends/patches/miniupnpc/respect_mingw_cflags.patch
new file mode 100644
index 0000000000..a44580ddab
--- /dev/null
+++ b/depends/patches/miniupnpc/respect_mingw_cflags.patch
@@ -0,0 +1,23 @@
+commit fec515a7ac9991a0ee91068fda046b54b191155e
+Author: fanquake <fanquake@gmail.com>
+Date: Wed Jul 27 15:52:37 2022 +0100
+
+ build: respect CFLAGS in makefile.mingw
+
+ Similar to the other Makefile.
+
+ Cherry-pick of https://github.com/miniupnp/miniupnp/pull/619.
+
+diff --git a/Makefile.mingw b/Makefile.mingw
+index 2bff7bd..88430d2 100644
+--- a/Makefile.mingw
++++ b/Makefile.mingw
+@@ -19,7 +19,7 @@ else
+ RM = rm -f
+ endif
+ #CFLAGS = -Wall -g -DDEBUG -D_WIN32_WINNT=0X501
+-CFLAGS = -Wall -W -Wstrict-prototypes -Os -DNDEBUG -D_WIN32_WINNT=0X501
++CFLAGS ?= -Wall -W -Wstrict-prototypes -Os -DNDEBUG -D_WIN32_WINNT=0X501
+ LDLIBS = -lws2_32 -liphlpapi
+ # -lwsock32
+ # -liphlpapi is needed for GetBestRoute() and GetIpAddrTable()
diff --git a/depends/patches/systemtap/fix_variadic_warning.patch b/depends/patches/systemtap/fix_variadic_warning.patch
new file mode 100644
index 0000000000..93cc2d6081
--- /dev/null
+++ b/depends/patches/systemtap/fix_variadic_warning.patch
@@ -0,0 +1,16 @@
+Could be dropped after a migration to C++20.
+See: https://github.com/bitcoin/bitcoin/issues/26916.
+
+diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h
+index 4075a5f..7c6138c 100644
+--- a/includes/sys/sdt.h
++++ b/includes/sys/sdt.h
+@@ -276,7 +276,7 @@ __extension__ extern unsigned long long __sdt_unsp;
+ _SDT_ASM_1(.purgem _SDT_TYPE_) \
+ _SDT_ASM_1(.purgem _SDT_TYPE)
+
+-#define _SDT_ASM_BODY(provider, name, pack_args, args, ...) \
++#define _SDT_ASM_BODY(provider, name, pack_args, args) \
+ _SDT_DEF_MACROS \
+ _SDT_ASM_1(990: _SDT_NOP) \
+ _SDT_ASM_3( .pushsection .note.stapsdt,_SDT_ASM_AUTOGROUP,"note") \
diff --git a/doc/JSON-RPC-interface.md b/doc/JSON-RPC-interface.md
index 12807bfb86..ab5db58cdd 100644
--- a/doc/JSON-RPC-interface.md
+++ b/doc/JSON-RPC-interface.md
@@ -5,6 +5,28 @@ 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.
+## Parameter passing
+
+The JSON-RPC server supports both _by-position_ and _by-name_ [parameter
+structures](https://www.jsonrpc.org/specification#parameter_structures)
+described in the JSON-RPC specification. For extra convenience, to avoid the
+need to name every parameter value, all RPC methods accept a named parameter
+called `args`, which can be set to an array of initial positional values that
+are combined with named values.
+
+Examples:
+
+```sh
+# "params": ["mywallet", false, false, "", false, false, true]
+bitcoin-cli createwallet mywallet false false "" false false true
+
+# "params": {"wallet_name": "mywallet", "load_on_startup": true}
+bitcoin-cli -named createwallet wallet_name=mywallet load_on_startup=true
+
+# "params": {"args": ["mywallet"], "load_on_startup": true}
+bitcoin-cli -named createwallet mywallet load_on_startup=true
+```
+
## Versioning
The RPC interface might change from one major version of Bitcoin Core to the
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index 265b74ee9a..2d7d0e3769 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -37,8 +37,8 @@ By default, this endpoint will only search the mempool.
To query for a confirmed transaction, enable the transaction index via "txindex=1" command line / configuration option.
#### Blocks
-`GET /rest/block/<BLOCK-HASH>.<bin|hex|json>`
-`GET /rest/block/notxdetails/<BLOCK-HASH>.<bin|hex|json>`
+- `GET /rest/block/<BLOCK-HASH>.<bin|hex|json>`
+- `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.
@@ -86,12 +86,23 @@ Returns various state info regarding block chain processing.
Only supports JSON as output format.
Refer to the `getblockchaininfo` RPC help for details.
+#### Deployment info
+`GET /rest/deploymentinfo.json`
+`GET /rest/deploymentinfo/<BLOCKHASH>.json`
+
+Returns an object containing various state info regarding deployments of
+consensus changes at the current chain tip, or at <BLOCKHASH> if provided.
+Only supports JSON as output format.
+Refer to the `getdeploymentinfo` RPC help for details.
+
#### Query UTXO set
-`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>/.../<txid>-<n>.<bin|hex|json>`
+- `GET /rest/getutxos/<TXID>-<N>/<TXID>-<N>/.../<TXID>-<N>.<bin|hex|json>`
+- `GET /rest/getutxos/checkmempool/<TXID>-<N>/<TXID>-<N>/.../<TXID>-<N>.<bin|hex|json>`
-The getutxo command allows querying of the UTXO set given a set of outpoints.
-See BIP64 for input and output serialisation:
-https://github.com/bitcoin/bips/blob/master/bip-0064.mediawiki
+The getutxos endpoint allows querying the UTXO set, given a set of outpoints.
+With the `/checkmempool/` option, the mempool is also taken into account.
+See [BIP64](https://github.com/bitcoin/bips/blob/master/bip-0064.mediawiki) for
+input and output serialization (relevant for `bin` and `hex` output formats).
Example:
```
@@ -123,11 +134,15 @@ Returns various information about the transaction mempool.
Only supports JSON as output format.
Refer to the `getmempoolinfo` RPC help for details.
-`GET /rest/mempool/contents.json`
+`GET /rest/mempool/contents.json?verbose=<true|false>&mempool_sequence=<false|true>`
Returns the transactions in the mempool.
Only supports JSON as output format.
-Refer to the `getrawmempool` RPC help for details.
+Refer to the `getrawmempool` RPC help for details. Defaults to setting
+`verbose=true` and `mempool_sequence=false`.
+
+*Query parameters for `verbose` and `mempool_sequence` available in 25.0 and up.*
+
Risks
-------------
diff --git a/doc/bips.md b/doc/bips.md
index 25381818e4..1d5c91b8bd 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -28,6 +28,7 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v24.0**):
and it is disabled by default at build time since **v0.19.0** ([PR #15584](https://github.com/bitcoin/bitcoin/pull/15584)).
It has been removed as of **v0.20.0** ([PR 17165](https://github.com/bitcoin/bitcoin/pull/17165)).
* [`BIP 84`](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki): The experimental descriptor wallets introduced in **v0.21.0** by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 84. ([PR #16528](https://github.com/bitcoin/bitcoin/pull/16528))
+* [`BIP 86`](https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki): Descriptor wallets by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 86 since **v23.0** ([PR #22364](https://github.com/bitcoin/bitcoin/pull/22364)).
* [`BIP 90`](https://github.com/bitcoin/bips/blob/master/bip-0090.mediawiki): Trigger mechanism for activation of BIPs 34, 65, and 66 has been simplified to block height checks since **v0.14.0** ([PR #8391](https://github.com/bitcoin/bitcoin/pull/8391)).
* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)).
* [`BIP 112`](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki): The CHECKSEQUENCEVERIFY opcode has been implemented since **v0.12.1** ([PR #7524](https://github.com/bitcoin/bitcoin/pull/7524)), and has been *buried* since **v0.19.0** ([PR #16060](https://github.com/bitcoin/bitcoin/pull/16060)).
diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md
index a8e643a2ab..aa10e4a891 100644
--- a/doc/build-freebsd.md
+++ b/doc/build-freebsd.md
@@ -36,13 +36,30 @@ pkg install sqlite3
```
###### Legacy Wallet Support
-`db5` is only required to support legacy wallets.
-Skip if you don't intend to use legacy wallets.
+BerkeleyDB is only required if legacy wallet support is required.
+
+It is required to use Berkeley DB 4.8. You **cannot** use the BerkeleyDB library
+from ports. However, you can build DB 4.8 yourself [using depends](/depends).
-```bash
-pkg install db5
```
----
+gmake -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_NATPMP=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1
+```
+
+When the build is complete, the Berkeley DB installation location will be displayed:
+
+```
+to: /path/to/bitcoin/depends/x86_64-unknown-freebsd[release-number]
+```
+
+Finally, set `BDB_PREFIX` to this path according to your shell:
+
+```
+csh: setenv BDB_PREFIX [path displayed above]
+```
+
+```
+sh/bash: export BDB_PREFIX=[path displayed above]
+```
#### GUI Dependencies
###### Qt5
@@ -72,7 +89,7 @@ There is an included test suite that is useful for testing code changes when dev
To run the test suite (recommended), you will need to have Python 3 installed:
```bash
-pkg install python3
+pkg install python3 databases/py-sqlite3
```
---
@@ -91,12 +108,12 @@ This explicitly enables the GUI and disables legacy wallet support, assuming `sq
##### Descriptor & Legacy Wallet. No GUI:
This enables support for both wallet types and disables the GUI, assuming
-`sqlite3` and `db5` are both installed.
+`sqlite3` and `db4` are both installed.
```bash
./autogen.sh
-./configure --with-gui=no --with-incompatible-bdb \
- BDB_LIBS="-ldb_cxx-5" \
- BDB_CFLAGS="-I/usr/local/include/db5" \
+./configure --with-gui=no \
+ BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \
+ BDB_CFLAGS="-I${BDB_PREFIX}/include" \
MAKE=gmake
```
diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md
index afbb5c8e75..255995a517 100644
--- a/doc/build-openbsd.md
+++ b/doc/build-openbsd.md
@@ -41,16 +41,18 @@ pkg_add sqlite3
BerkeleyDB is only required to support legacy wallets.
It is recommended to use Berkeley DB 4.8. You cannot use the BerkeleyDB library
-from ports. However you can build it yourself, [using the installation script included in contrib/](/contrib/install_db4.sh), like so, from the root of the repository.
+from ports. However you can build it yourself, [using depends](/depends).
```bash
-./contrib/install_db4.sh `pwd`
+gmake -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_NATPMP=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1
+...
+to: /path/to/bitcoin/depends/x86_64-unknown-openbsd
```
Then set `BDB_PREFIX`:
```bash
-export BDB_PREFIX="$PWD/db4"
+export BDB_PREFIX="/path/to/bitcoin/depends/x86_64-unknown-openbsd"
```
#### GUI Dependencies
diff --git a/doc/build-unix.md b/doc/build-unix.md
index 874015707a..0960ae1577 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -72,7 +72,7 @@ executables, which are based on BerkeleyDB 4.8. If you do not care about wallet
To build Bitcoin Core without wallet, see [*Disable-wallet mode*](#disable-wallet-mode)
-Optional port mapping libraries (see: `--with-miniupnpc`, `--enable-upnp-default`, and `--with-natpmp`, `--enable-natpmp-default`):
+Optional port mapping libraries (see: `--with-miniupnpc` and `--with-natpmp`):
sudo apt install libminiupnpc-dev libnatpmp-dev
@@ -133,7 +133,7 @@ pass `--with-incompatible-bdb` to configure. Otherwise, you can build Berkeley D
To build Bitcoin Core without wallet, see [*Disable-wallet mode*](#disable-wallet-mode)
-Optional port mapping libraries (see: `--with-miniupnpc`, `--enable-upnp-default`, and `--with-natpmp`, `--enable-natpmp-default`):
+Optional port mapping libraries (see: `--with-miniupnpc` and `--with-natpmp`):
sudo dnf install miniupnpc-devel libnatpmp-devel
@@ -176,38 +176,34 @@ miniupnpc
[miniupnpc](https://miniupnp.tuxfamily.org) may be used for UPnP port mapping. It can be downloaded from [here](
https://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and
-turned off by default. See the configure options for UPnP behavior desired:
-
- --without-miniupnpc No UPnP support, miniupnp not required
- --disable-upnp-default (the default) UPnP support turned off by default at runtime
- --enable-upnp-default UPnP support turned on by default at runtime
+turned off by default.
libnatpmp
---------
[libnatpmp](https://miniupnp.tuxfamily.org/libnatpmp.html) may be used for NAT-PMP port mapping. It can be downloaded
from [here](https://miniupnp.tuxfamily.org/files/). NAT-PMP support is compiled in and
-turned off by default. See the configure options for NAT-PMP behavior desired:
-
- --without-natpmp No NAT-PMP support, libnatpmp not required
- --disable-natpmp-default (the default) NAT-PMP support turned off by default at runtime
- --enable-natpmp-default NAT-PMP support turned on by default at runtime
+turned off by default.
Berkeley DB
-----------
The legacy wallet uses Berkeley DB. To ensure backwards compatibility it is
-recommended to use Berkeley DB 4.8. If you have to build it yourself, you can
-use [the installation script included in contrib/](/contrib/install_db4.sh)
-like so:
-
-```shell
-./contrib/install_db4.sh `pwd`
+recommended to use Berkeley DB 4.8. If you have to build it yourself, and don't
+want to use any other libraries built in depends, you can do:
+```bash
+make -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_NATPMP=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1
+...
+to: /path/to/bitcoin/depends/x86_64-pc-linux-gnu
```
+and configure using the following:
+```bash
+export BDB_PREFIX="/path/to/bitcoin/depends/x86_64-pc-linux-gnu"
-from the root of the repository.
-
-Otherwise, you can build Bitcoin Core from self-compiled [depends](/depends/README.md).
+./configure \
+ BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \
+ BDB_CFLAGS="-I${BDB_PREFIX}/include"
+```
**Note**: You only need Berkeley DB if the legacy wallet is enabled (see [*Disable-wallet mode*](#disable-wallet-mode)).
diff --git a/doc/build-windows.md b/doc/build-windows.md
index e35d3bcbd0..027e8f80f5 100644
--- a/doc/build-windows.md
+++ b/doc/build-windows.md
@@ -6,8 +6,8 @@ Below are some notes on how to build Bitcoin Core for Windows.
The options known to work for building Bitcoin Core on Windows are:
* On Linux, using the [Mingw-w64](https://www.mingw-w64.org/) cross compiler tool chain.
-* On Windows, using [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/windows/wsl/about) and Mingw-w64.
-* On Windows, using [Microsoft Visual Studio](https://www.visualstudio.com). See [README.md](/build_msvc/README.md).
+* On Windows, using [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/about) and Mingw-w64.
+* On Windows, using [Microsoft Visual Studio](https://visualstudio.microsoft.com). See [README.md](/build_msvc/README.md).
Other options which may work, but which have not been extensively tested are (please contribute instructions):
@@ -16,7 +16,7 @@ Other options which may work, but which have not been extensively tested are (pl
Installing Windows Subsystem for Linux
---------------------------------------
-Follow the upstream installation instructions, available [here](https://docs.microsoft.com/windows/wsl/install-win10).
+Follow the upstream installation instructions, available [here](https://learn.microsoft.com/en-us/windows/wsl/install).
Cross-compilation for Ubuntu and Windows Subsystem for Linux
------------------------------------------------------------
@@ -66,7 +66,7 @@ Note that for WSL the Bitcoin Core source path MUST be somewhere in the default
example /usr/src/bitcoin, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail.
This means you cannot use a directory that is located directly on the host Windows file system to perform the build.
-Additional WSL Note: WSL support for [launching Win32 applications](https://docs.microsoft.com/en-us/archive/blogs/wsl/windows-and-ubuntu-interoperability#launching-win32-applications-from-within-wsl)
+Additional WSL Note: WSL support for [launching Win32 applications](https://learn.microsoft.com/en-us/archive/blogs/wsl/windows-and-ubuntu-interoperability#launching-win32-applications-from-within-wsl)
results in `Autoconf` configure scripts being able to execute Windows Portable Executable files. This can cause
unexpected behaviour during the build, such as Win32 error dialogs for missing libraries. The recommended approach
is to temporarily disable WSL support for Win32 applications.
diff --git a/doc/dependencies.md b/doc/dependencies.md
index ef8faff06c..a9ca5b3e7a 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -10,16 +10,16 @@ You can find installation instructions in the `build-*.md` file for your platfor
| [Automake](https://www.gnu.org/software/automake/) | [1.13](https://github.com/bitcoin/bitcoin/pull/18290) |
| [Clang](https://clang.llvm.org) | [8.0](https://github.com/bitcoin/bitcoin/pull/24164) |
| [GCC](https://gcc.gnu.org) | [8.1](https://github.com/bitcoin/bitcoin/pull/23060) |
-| [Python](https://www.python.org) (tests) | [3.6](https://github.com/bitcoin/bitcoin/pull/19504) |
+| [Python](https://www.python.org) (tests) | [3.7](https://github.com/bitcoin/bitcoin/pull/26226) |
| [systemtap](https://sourceware.org/systemtap/) ([tracing](tracing.md))| N/A |
## Required
| Dependency | Releases | Version used | Minimum required | Runtime |
| --- | --- | --- | --- | --- |
-| [Boost](../depends/packages/boost.mk) | [link](https://www.boost.org/users/download/) | [1.80.0](https://github.com/bitcoin/bitcoin/pull/25873) | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No |
+| [Boost](../depends/packages/boost.mk) | [link](https://www.boost.org/users/download/) | [1.81.0](https://github.com/bitcoin/bitcoin/pull/26557) | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No |
| [libevent](../depends/packages/libevent.mk) | [link](https://github.com/libevent/libevent/releases) | [2.1.12-stable](https://github.com/bitcoin/bitcoin/pull/21991) | [2.1.8](https://github.com/bitcoin/bitcoin/pull/24681) | No |
-| glibc | [link](https://www.gnu.org/software/libc/) | N/A | [2.18](https://github.com/bitcoin/bitcoin/pull/23511) | Yes |
+| glibc | [link](https://www.gnu.org/software/libc/) | N/A | [2.27](https://github.com/bitcoin/bitcoin/pull/27029) | Yes |
| Linux Kernel | [link](https://www.kernel.org/) | N/A | 3.2.0 | Yes |
## Optional
@@ -36,7 +36,7 @@ You can find installation instructions in the `build-*.md` file for your platfor
| Dependency | Releases | Version used | Minimum required | Runtime |
| --- | --- | --- | --- | --- |
| [libnatpmp](../depends/packages/libnatpmp.mk) | [link](https://github.com/miniupnp/libnatpmp/) | commit [07004b9...](https://github.com/bitcoin/bitcoin/pull/25917) | | No |
-| [MiniUPnPc](../depends/packages/miniupnpc.mk) | [link](https://miniupnp.tuxfamily.org/) | [2.2.2](https://github.com/bitcoin/bitcoin/pull/20421) | 1.9 | No |
+| [MiniUPnPc](../depends/packages/miniupnpc.mk) | [link](https://miniupnp.tuxfamily.org/) | [2.2.2](https://github.com/bitcoin/bitcoin/pull/20421) | 2.1 | No |
### Notifications
| Dependency | Releases | Version used | Minimum required | Runtime |
diff --git a/doc/descriptors.md b/doc/descriptors.md
index 69a5ee2715..1baf652f30 100644
--- a/doc/descriptors.md
+++ b/doc/descriptors.md
@@ -21,6 +21,8 @@ Supporting RPCs are:
- `importdescriptors` takes as input descriptors to import into a descriptor wallet
(since v0.21).
- `listdescriptors` outputs descriptors imported into a descriptor wallet (since v22).
+- `scanblocks` takes as input descriptors to scan for in blocks and returns the
+ relevant blockhashes (since v25).
This document describes the language. For the specifics on usage, see the RPC
documentation for the functions mentioned above.
@@ -264,6 +266,6 @@ ones. For larger numbers of errors, or other types of errors, there is a
roughly 1 in a trillion chance of not detecting the errors.
All RPCs in Bitcoin Core will include the checksum in their output. Only
-certain RPCs require checksums on input, including `deriveaddress` and
+certain RPCs require checksums on input, including `deriveaddresses` and
`importmulti`. The checksum for a descriptor without one can be computed
using the `getdescriptorinfo` RPC.
diff --git a/doc/design/assumeutxo.md b/doc/design/assumeutxo.md
index c353c78ff8..469c551536 100644
--- a/doc/design/assumeutxo.md
+++ b/doc/design/assumeutxo.md
@@ -3,9 +3,9 @@
Assumeutxo is a feature that allows fast bootstrapping of a validating bitcoind
instance with a very similar security model to assumevalid.
-The RPC commands `dumptxoutset` and `loadtxoutset` are used to respectively generate
-and load UTXO snapshots. The utility script `./contrib/devtools/utxo_snapshot.sh` may
-be of use.
+The RPC commands `dumptxoutset` and `loadtxoutset` (yet to be merged) are used to
+respectively generate and load UTXO snapshots. The utility script
+`./contrib/devtools/utxo_snapshot.sh` may be of use.
## General background
@@ -22,10 +22,6 @@ be of use.
chainstate running asynchronously in the background. We also use this flag to control
which index entries are added to setBlockIndexCandidates during LoadBlockIndex().
-- Indexing implementations via BaseIndex can no longer assume that indexation happens
- sequentially, since background validation chainstates can submit BlockConnected
- events out of order with the active chain.
-
- The concept of UTXO snapshots is treated as an implementation detail that lives
behind the ChainstateManager interface. The external presentation of the changes
required to facilitate the use of UTXO snapshots is the understanding that there are
@@ -76,8 +72,15 @@ original chainstate remains in use as active.
Once the snapshot chainstate is loaded and validated, it is promoted to active
chainstate and a sync to tip begins. A new chainstate directory is created in the
-datadir for the snapshot chainstate called
-`chainstate_[SHA256 blockhash of snapshot base block]`.
+datadir for the snapshot chainstate called `chainstate_snapshot`.
+
+When this directory is present in the datadir, the snapshot chainstate will be detected
+and loaded as active on node startup (via `DetectSnapshotChainstate()`).
+
+A special file is created within that directory, `base_blockhash`, which contains the
+serialized `uint256` of the base block of the snapshot. This is used to reinitialize
+the snapshot chainstate on subsequent inits. Otherwise, the directory is a normal
+leveldb database.
| | |
| ---------- | ----------- |
@@ -87,7 +90,7 @@ datadir for the snapshot chainstate called
The snapshot begins to sync to tip from its base block, technically in parallel with
the original chainstate, but it is given priority during block download and is
allocated most of the cache (see `MaybeRebalanceCaches()` and usages) as our chief
-consideration is getting to network tip.
+goal is getting to network tip.
**Failure consideration:** if shutdown happens at any point during this phase, both
chainstates will be detected during the next init and the process will resume.
@@ -106,33 +109,32 @@ sequentially.
### Background chainstate hits snapshot base block
Once the tip of the background chainstate hits the base block of the snapshot
-chainstate, we stop use of the background chainstate by setting `m_stop_use` (not yet
-committed - see #15606), in `CompleteSnapshotValidation()`, which is checked in
-`ActivateBestChain()`). We hash the background chainstate's UTXO set contents and
-ensure it matches the compiled value in `CMainParams::m_assumeutxo_data`.
-
-The background chainstate data lingers on disk until shutdown, when in
-`ChainstateManager::Reset()`, the background chainstate is cleaned up with
-`ValidatedSnapshotShutdownCleanup()`, which renames the `chainstate_[hash]` datadir as
-`chainstate`.
+chainstate, we stop use of the background chainstate by setting `m_disabled`, in
+`CompleteSnapshotValidation()`, which is checked in `ActivateBestChain()`). We hash the
+background chainstate's UTXO set contents and ensure it matches the compiled value in
+`CMainParams::m_assumeutxo_data`.
| | |
| ---------- | ----------- |
-| number of chainstates | 2 (ibd has `m_stop_use=true`) |
+| number of chainstates | 2 (ibd has `m_disabled=true`) |
| active chainstate | snapshot |
-**Failure consideration:** if bitcoind unexpectedly halts after `m_stop_use` is set on
-the background chainstate but before `CompleteSnapshotValidation()` can finish, the
-need to complete snapshot validation will be detected on subsequent init by
-`ChainstateManager::CheckForUncleanShutdown()`.
+The background chainstate data lingers on disk until the program is restarted.
### Bitcoind restarts sometime after snapshot validation has completed
-When bitcoind initializes again, what began as the snapshot chainstate is now
-indistinguishable from a chainstate that has been built from the traditional IBD
-process, and will be initialized as such.
+After a shutdown and subsequent restart, `LoadChainstate()` cleans up the background
+chainstate with `ValidatedSnapshotCleanup()`, which renames the `chainstate_snapshot`
+datadir as `chainstate` and removes the now unnecessary background chainstate data.
| | |
| ---------- | ----------- |
| number of chainstates | 1 |
-| active chainstate | ibd |
+| active chainstate | ibd (was snapshot, but is now fully validated) |
+
+What began as the snapshot chainstate is now indistinguishable from a chainstate that
+has been built from the traditional IBD process, and will be initialized as such.
+
+A file will be left in `chainstate/base_blockhash`, which indicates that the
+chainstate, even though now fully validated, was originally started from a snapshot
+with the corresponding base blockhash.
diff --git a/doc/design/libraries.md b/doc/design/libraries.md
index 75f8d60ba0..7cda64e713 100644
--- a/doc/design/libraries.md
+++ b/doc/design/libraries.md
@@ -35,7 +35,7 @@
```mermaid
-%%{ init : { "flowchart" : { "curve" : "linear" }}}%%
+%%{ init : { "flowchart" : { "curve" : "basis" }}}%%
graph TD;
@@ -51,18 +51,18 @@ bitcoin-qt[bitcoin-qt]-->libbitcoin_wallet;
bitcoin-wallet[bitcoin-wallet]-->libbitcoin_wallet;
bitcoin-wallet[bitcoin-wallet]-->libbitcoin_wallet_tool;
-libbitcoin_cli-->libbitcoin_common;
libbitcoin_cli-->libbitcoin_util;
+libbitcoin_cli-->libbitcoin_common;
-libbitcoin_common-->libbitcoin_util;
libbitcoin_common-->libbitcoin_consensus;
+libbitcoin_common-->libbitcoin_util;
libbitcoin_kernel-->libbitcoin_consensus;
libbitcoin_kernel-->libbitcoin_util;
-libbitcoin_node-->libbitcoin_common;
libbitcoin_node-->libbitcoin_consensus;
libbitcoin_node-->libbitcoin_kernel;
+libbitcoin_node-->libbitcoin_common;
libbitcoin_node-->libbitcoin_util;
libbitcoinqt-->libbitcoin_common;
@@ -71,8 +71,8 @@ libbitcoinqt-->libbitcoin_util;
libbitcoin_wallet-->libbitcoin_common;
libbitcoin_wallet-->libbitcoin_util;
-libbitcoin_wallet_tool-->libbitcoin_util;
libbitcoin_wallet_tool-->libbitcoin_wallet;
+libbitcoin_wallet_tool-->libbitcoin_util;
classDef bold stroke-width:2px, font-weight:bold, font-size: smaller;
class bitcoin-qt,bitcoind,bitcoin-cli,bitcoin-wallet bold
@@ -83,7 +83,7 @@ class bitcoin-qt,bitcoind,bitcoin-cli,bitcoin-wallet bold
</td></tr></table>
-- The graph shows what _linker symbols_ (functions and variables) from each library other libraries can call and reference directly, but it is not a call graph. For example, there is no arrow connecting *libbitcoin_wallet* and *libbitcoin_node* libraries, because these libraries are intended to be modular and not depend on each other's internal implementation details. But wallet code still is still able to call node code indirectly through the `interfaces::Chain` abstract class in [`interfaces/chain.h`](../../src/interfaces/chain.h) and node code calls wallet code through the `interfaces::ChainClient` and `interfaces::Chain::Notifications` abstract classes in the same file. In general, defining abstract classes in [`src/interfaces/`](../../src/interfaces/) can be a convenient way of avoiding unwanted direct dependencies or circular dependencies between libraries.
+- The graph shows what _linker symbols_ (functions and variables) from each library other libraries can call and reference directly, but it is not a call graph. For example, there is no arrow connecting *libbitcoin_wallet* and *libbitcoin_node* libraries, because these libraries are intended to be modular and not depend on each other's internal implementation details. But wallet code is still able to call node code indirectly through the `interfaces::Chain` abstract class in [`interfaces/chain.h`](../../src/interfaces/chain.h) and node code calls wallet code through the `interfaces::ChainClient` and `interfaces::Chain::Notifications` abstract classes in the same file. In general, defining abstract classes in [`src/interfaces/`](../../src/interfaces/) can be a convenient way of avoiding unwanted direct dependencies or circular dependencies between libraries.
- *libbitcoin_consensus* should be a standalone dependency that any library can depend on, and it should not depend on any other libraries itself.
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 00c68911ef..ceaba8cb99 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -109,6 +109,10 @@ code.
- `++i` is preferred over `i++`.
- `nullptr` is preferred over `NULL` or `(void*)0`.
- `static_assert` is preferred over `assert` where possible. Generally; compile-time checking is preferred over run-time checking.
+ - Use a named cast or functional cast, not a C-Style cast. When casting
+ between integer types, use functional casts such as `int(x)` or `int{x}`
+ instead of `(int) x`. When casting between more complex types, use static_cast.
+ Use reinterpret_cast and const_cast as appropriate.
For function calls a namespace should be specified explicitly, unless such functions have been declared within it.
Otherwise, [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl), also known as ADL, could be
@@ -213,11 +217,14 @@ apt install clang-tidy bear clang
Then, pass clang as compiler to configure, and use bear to produce the `compile_commands.json`:
```sh
-./autogen.sh && ./configure CC=clang CXX=clang++
-make clean && bear make -j $(nproc) # For bear 2.x
-make clean && bear -- make -j $(nproc) # For bear 3.x
+./autogen.sh && ./configure CC=clang CXX=clang++ --enable-suppress-external-warnings
+make clean && bear --config src/.bear-tidy-config -- make -j $(nproc)
```
+The output is denoised of errors from external dependencies and includes with
+`--enable-suppress-external-warnings` and `--config src/.bear-tidy-config`. Both
+options may be omitted to view the full list of errors.
+
To run clang-tidy on all source files:
```sh
@@ -556,8 +563,19 @@ address sanitizer, libtsan for the thread sanitizer, and libubsan for the
undefined sanitizer. If you are missing required libraries, the configure script
will fail with a linker error when testing the sanitizer flags.
-The test suite should pass cleanly with the `thread` and `undefined` sanitizers,
-but there are a number of known problems when using the `address` sanitizer. The
+The test suite should pass cleanly with the `thread` and `undefined` sanitizers. You
+may need to use a suppressions file, see `test/sanitizer_suppressions`. They may be
+used as follows:
+```bash
+export LSAN_OPTIONS="suppressions=$(pwd)/test/sanitizer_suppressions/lsan"
+export TSAN_OPTIONS="suppressions=$(pwd)/test/sanitizer_suppressions/tsan:halt_on_error=1:second_deadlock_stack=1"
+export UBSAN_OPTIONS="suppressions=$(pwd)/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1"
+```
+
+See the CI config for more examples, and upstream documentation for more information
+about any additional options.
+
+There are a number of known problems when using the `address` sanitizer. The
address sanitizer is known to fail in
[sha256_sse4::Transform](/src/crypto/sha256_sse4.cpp) which makes it unusable
unless you also use `--disable-asm` when running configure. We would like to fix
@@ -842,12 +860,12 @@ Strings and formatting
buffer overflows, and surprises with `\0` characters. Also, some C string manipulations
tend to act differently depending on platform, or even the user locale.
-- Use `ParseInt32`, `ParseInt64`, `ParseUInt32`, `ParseUInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing.
+- Use `ToIntegral` from [`strencodings.h`](/src/util/strencodings.h) for number parsing. In legacy code you might also find `ParseInt*` family of functions, `ParseDouble` or `LocaleIndependentAtoi`.
- *Rationale*: These functions do overflow checking and avoid pesky locale issues.
- Avoid using locale dependent functions if possible. You can use the provided
- [`lint-locale-dependence.sh`](/test/lint/lint-locale-dependence.sh)
+ [`lint-locale-dependence.py`](/test/lint/lint-locale-dependence.py)
to check for accidental use of locale dependent functions.
- *Rationale*: Unnecessary locale dependence can cause bugs that are very tricky to isolate and fix.
diff --git a/doc/fuzzing.md b/doc/fuzzing.md
index 9abfbc9213..84ebb0986d 100644
--- a/doc/fuzzing.md
+++ b/doc/fuzzing.md
@@ -136,10 +136,10 @@ You may also need to take care of giving the correct path for `clang` and
`clang++`, like `CC=/path/to/clang CXX=/path/to/clang++` if the non-systems
`clang` does not come first in your path.
-Full configure that was tested on macOS Catalina with `brew` installed `llvm`:
+Full configure that was tested on macOS with `brew` installed `llvm`:
```sh
-./configure --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=/usr/local/opt/llvm/bin/clang CXX=/usr/local/opt/llvm/bin/clang++ --disable-asm
+./configure --enable-fuzz --with-sanitizers=fuzzer,address,undefined --disable-asm CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++
```
Read the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html) for more information. This [libFuzzer tutorial](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md) might also be of interest.
@@ -283,8 +283,8 @@ $ sudo apt-get install libtool libtool-bin wget automake autoconf bison gdb
```
At this point, you must install the .NET core. The process differs, depending on your Linux distribution.
-See [this link](https://docs.microsoft.com/en-us/dotnet/core/install/linux) for details.
-On ubuntu 20.04, the following should work:
+See [this link](https://learn.microsoft.com/en-us/dotnet/core/install/linux) for details.
+On Ubuntu 20.04, the following should work:
```sh
$ wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb
diff --git a/doc/i2p.md b/doc/i2p.md
index 1599c2fe0f..0432136554 100644
--- a/doc/i2p.md
+++ b/doc/i2p.md
@@ -16,8 +16,7 @@ enabled is required. Options include:
Java
- [i2pd (I2P Daemon)](https://github.com/PurpleI2P/i2pd)
([documentation](https://i2pd.readthedocs.io/en/latest)), a lighter
- alternative in C++ (successfully tested with version 2.23 and up; version 2.36
- or later recommended)
+ alternative in C++
- [i2p-zero](https://github.com/i2p-zero/i2p-zero)
- [other alternatives](https://en.wikipedia.org/wiki/I2P#Routers)
@@ -33,12 +32,10 @@ Core configuration options:
none)
-i2pacceptincoming
- If set and -i2psam is also set then incoming I2P connections are
- accepted via the SAM proxy. If this is not set but -i2psam is set
- then only outgoing connections will be made to the I2P network.
- Ignored if -i2psam is not set. Listening for incoming I2P
- connections is done through the SAM proxy, not by binding to a
- local address and port (default: 1)
+ Whether to accept inbound I2P connections (default: 1). Ignored if
+ -i2psam is not set. Listening for inbound I2P connections is
+ done through the SAM proxy, not by binding to a local address and
+ port.
```
In a typical situation, this suffices:
@@ -47,27 +44,6 @@ In a typical situation, this suffices:
bitcoind -i2psam=127.0.0.1:7656
```
-The first time Bitcoin Core connects to the I2P router, if
-`-i2pacceptincoming=1`, then it will automatically generate a persistent I2P
-address and its corresponding private key. The private key will be saved in a
-file named `i2p_private_key` in the Bitcoin Core data directory. The persistent
-I2P address is used for accepting incoming connections and for making outgoing
-connections if `-i2pacceptincoming=1`. If `-i2pacceptincoming=0` then only
-outbound I2P connections are made and a different transient I2P address is used
-for each connection to improve privacy.
-
-## Persistent vs transient I2P addresses
-
-In I2P connections, the connection receiver sees the I2P address of the
-connection initiator. This is unlike the Tor network where the recipient does
-not know who is connecting to them and can't tell if two connections are from
-the same peer or not.
-
-If an I2P node is not accepting incoming connections, then Bitcoin Core uses
-random, one-time, transient I2P addresses for itself for outbound connections
-to make it harder to discriminate, fingerprint or analyze it based on its I2P
-address.
-
## Additional configuration options related to I2P
```
@@ -100,7 +76,29 @@ In general, a node can be run with both onion and I2P hidden services (or
any/all of IPv4/IPv6/onion/I2P/CJDNS), which can provide a potential fallback if
one of the networks has issues.
-## I2P-related information in Bitcoin Core
+## Persistent vs transient I2P addresses
+
+The first time Bitcoin Core connects to the I2P router, it automatically
+generates a persistent I2P address and its corresponding private key by default
+or if `-i2pacceptincoming=1` is set. The private key is saved in a file named
+`i2p_private_key` in the Bitcoin Core data directory. The persistent I2P
+address is used for making outbound connections and accepting inbound
+connections.
+
+In the I2P network, the receiver of an inbound connection sees the address of
+the initiator. This is unlike the Tor network, where the recipient does not
+know who is connecting to it.
+
+If your node is configured by setting `-i2pacceptincoming=0` to not accept
+inbound I2P connections, then it will use a random transient I2P address for
+itself on each outbound connection to make it harder to discriminate,
+fingerprint or analyze it based on its I2P address.
+
+I2P addresses are designed to be long-lived. Waiting for tunnels to be built
+for every peer connection adds delay to connection setup time. Therefore, I2P
+listening should only be turned off if really needed.
+
+## Fetching I2P-related information from Bitcoin Core
There are several ways to see your I2P address in Bitcoin Core if accepting
incoming I2P connections (`-i2pacceptincoming`):
@@ -133,3 +131,40 @@ listening port to 0 when listening for incoming I2P connections and advertises
its own I2P address with port 0. Furthermore, it will not attempt to connect to
I2P addresses with a non-zero port number because with SAM v3.1 the destination
port (`TO_PORT`) is always set to 0 and is not in the control of Bitcoin Core.
+
+## Bandwidth
+
+By default, your node shares bandwidth and transit tunnels with the I2P network
+in order to increase your anonymity with cover traffic, help the I2P router used
+by your node integrate optimally with the network, and give back to the network.
+It's important that the nodes of a popular application like Bitcoin contribute
+as much to the I2P network as they consume.
+
+It is possible, though strongly discouraged, to change your I2P router
+configuration to limit the amount of I2P traffic relayed by your node.
+
+With `i2pd`, this can be done by adjusting the `bandwidth`, `share` and
+`transittunnels` options in your `i2pd.conf` file. For example, to limit total
+I2P traffic to 256KB/s and share 50% of this limit for a maximum of 20 transit
+tunnels:
+
+```
+bandwidth = 256
+share = 50
+
+[limits]
+transittunnels = 20
+```
+
+Similar bandwidth configuration options for the Java I2P router can be found in
+`http://127.0.0.1:7657/config` under the "Bandwidth" tab.
+
+Before doing this, please see the "Participating Traffic Considerations" section
+in [Embedding I2P in your Application](https://geti2p.net/en/docs/applications/embedding).
+
+In most cases, the default router settings should work fine.
+
+## Bundling I2P in a Bitcoin application
+
+Please see the "General Guidance for Developers" section in https://geti2p.net/en/docs/api/samv3
+if you are developing a downstream application that may be bundling I2P with Bitcoin.
diff --git a/doc/init.md b/doc/init.md
index 399b819bf4..7f79027718 100644
--- a/doc/init.md
+++ b/doc/init.md
@@ -70,7 +70,7 @@ 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
+bitcoin group to do so. This does not allow
for the listing of files under the directory.
NOTE: It is not currently possible to override `datadir` in
diff --git a/doc/managing-wallets.md b/doc/managing-wallets.md
index 366d7ec54b..22e006c963 100644
--- a/doc/managing-wallets.md
+++ b/doc/managing-wallets.md
@@ -88,7 +88,7 @@ In the RPC, the destination parameter must include the name of the file. Otherwi
$ bitcoin-cli -rpcwallet="wallet-01" backupwallet /home/node01/Backups/backup-01.dat
```
-In the GUI, the wallet is selected in the `Wallet` drop-down list in the upper right corner. If this list is not present, the wallet can be loaded in `File` ->`Open wallet` if necessary. Then, the backup can be done in `File` -> `Backup Wallet...`.
+In the GUI, the wallet is selected in the `Wallet` drop-down list in the upper right corner. If this list is not present, the wallet can be loaded in `File` ->`Open Wallet` if necessary. Then, the backup can be done in `File` -> `Backup Wallet…`.
This backup file can be stored on one or multiple offline devices, which must be reliable enough to work in an emergency and be malware free. Backup files can be regularly tested to avoid problems in the future.
@@ -108,7 +108,7 @@ Wallets created before version 0.13 are not HD and must be backed up every 100 k
### 1.6 Restoring the Wallet From a Backup
-To restore a wallet, the `restorewallet` RPC must be used.
+To restore a wallet, the `restorewallet` RPC or the `Restore Wallet` GUI menu item (`File` -> `Restore Wallet…`) must be used.
```
$ bitcoin-cli restorewallet "restored-wallet" /home/node01/Backups/backup-01.dat
@@ -144,5 +144,5 @@ unforeseen configurations which result in some scripts being excluded. If a migr
unexpectedly or otherwise misses any scripts, please create an issue on GitHub. A backup of the
original wallet can be found in the wallet directory with the name `<name>-<timestamp>.legacy.bak`.
-The backup can be restored using the `restorewallet` command as discussed in the
-[Restoring the Wallet From a Backup](#16-restoring-the-wallet-from-a-backup) section
+The backup can be restored using the methods discussed in the
+[Restoring the Wallet From a Backup](#16-restoring-the-wallet-from-a-backup) section.
diff --git a/doc/reduce-memory.md b/doc/reduce-memory.md
index 296b172bde..25205258b8 100644
--- a/doc/reduce-memory.md
+++ b/doc/reduce-memory.md
@@ -16,11 +16,11 @@ The size of some in-memory caches can be reduced. As caches trade off memory usa
- The minimum value for `-maxmempool` is 5.
- A lower maximum mempool size means that transactions will be evicted sooner. This will affect any uses of `bitcoind` that process unconfirmed transactions.
-- To completely disable mempool functionality there is the option `-blocksonly`. This will make the client opt out of receiving (and thus relaying) transactions completely, except as part of blocks.
+- Since `0.14.0`, unused memory allocated to the mempool (default: 300MB) is shared with the UTXO cache, so when trying to reduce memory usage you should limit the mempool, with the `-maxmempool` command line argument.
- - Do not use this when using the client to broadcast transactions as any transaction sent will stick out like a sore thumb, affecting privacy. When used with the wallet it should be combined with `-walletbroadcast=0` and `-spendzeroconfchange=0`. Another mechanism for broadcasting outgoing transactions (if any) should be used.
+- To disable most of the mempool functionality there is the `-blocksonly` option. This will reduce the default memory usage to 5MB and make the client opt out of receiving (and thus relaying) transactions, except from peers who have the `relay` permission set (e.g. whitelisted peers), and as part of blocks.
-- Since `0.14.0`, unused memory allocated to the mempool (default: 300MB) is shared with the UTXO cache, so when trying to reduce memory usage you should limit the mempool, with the `-maxmempool` command line argument.
+ - Do not use this when using the client to broadcast transactions as any transaction sent will stick out like a sore thumb, affecting privacy. When used with the wallet it should be combined with `-walletbroadcast=0` and `-spendzeroconfchange=0`. Another mechanism for broadcasting outgoing transactions (if any) should be used.
## Number of peers
diff --git a/doc/release-note-26194.md b/doc/release-note-26194.md
new file mode 100644
index 0000000000..b72dbf9a23
--- /dev/null
+++ b/doc/release-note-26194.md
@@ -0,0 +1,4 @@
+Add `next_index` in `listdescriptors` RPC
+-----------------
+
+- Added a new `next_index` field in the response in `listdescriptors` to have the same format as `importdescriptors`
diff --git a/doc/release-notes-19762.md b/doc/release-notes-19762.md
new file mode 100644
index 0000000000..4dc45fb2c8
--- /dev/null
+++ b/doc/release-notes-19762.md
@@ -0,0 +1,19 @@
+JSON-RPC
+---
+
+All JSON-RPC methods accept a new [named
+parameter](JSON-RPC-interface.md#parameter-passing) called `args` that can
+contain positional parameter values. This is a convenience to allow some
+parameter values to be passed by name without having to name every value. The
+python test framework and `bitcoin-cli` tool both take advantage of this, so
+for example:
+
+```sh
+bitcoin-cli -named createwallet wallet_name=mywallet load_on_startup=1
+```
+
+Can now be shortened to:
+
+```sh
+bitcoin-cli -named createwallet mywallet load_on_startup=1
+```
diff --git a/doc/release-notes-22087.md b/doc/release-notes-22087.md
new file mode 100644
index 0000000000..8d7fd242b2
--- /dev/null
+++ b/doc/release-notes-22087.md
@@ -0,0 +1,4 @@
+Updated settings
+----------------
+
+- Ports specified in `-port` and `-rpcport` options are now validated at startup. Values that previously worked and were considered valid can now result in errors. (#22087)
diff --git a/doc/release-notes-23395.md b/doc/release-notes-23395.md
new file mode 100644
index 0000000000..b9d7d9409c
--- /dev/null
+++ b/doc/release-notes-23395.md
@@ -0,0 +1,8 @@
+Notable changes
+===============
+
+New settings
+------------
+
+- The `shutdownnotify` option is used to specify a command to execute synchronously
+before Bitcoin Core has begun its shutdown sequence. (#23395)
diff --git a/doc/release-notes-25375.md b/doc/release-notes-25375.md
new file mode 100644
index 0000000000..504a2644f4
--- /dev/null
+++ b/doc/release-notes-25375.md
@@ -0,0 +1,11 @@
+Updated RPCs
+--------
+
+The `minconf` option, which allows a user to specify the minimum number
+of confirmations a UTXO being spent has, and the `maxconf` option,
+which allows specifying the maximum number of confirmations, have been
+added to the following RPCs:
+- `fundrawtransaction`
+- `send`
+- `walletcreatefundedpsbt`
+- `sendall`
diff --git a/doc/release-notes-25412.md b/doc/release-notes-25412.md
new file mode 100644
index 0000000000..b11fe73d45
--- /dev/null
+++ b/doc/release-notes-25412.md
@@ -0,0 +1,5 @@
+New REST endpoint
+-----------------
+
+- A new `/rest/deploymentinfo` endpoint has been added for fetching various
+ state info regarding deployments of consensus changes. (#25412)
diff --git a/doc/release-notes-25574.md b/doc/release-notes-25574.md
new file mode 100644
index 0000000000..312a99d95b
--- /dev/null
+++ b/doc/release-notes-25574.md
@@ -0,0 +1,13 @@
+Updated settings
+----------------
+
+If the `-checkblocks` or `-checklevel` options are explicitly provided by the
+user, but the verification checks cannot be completed due to an insufficient
+dbcache, Bitcoin Core will now return an error at startup. (#25574)
+
+RPC
+---
+The `-verifychain` RPC will now return `false` if the checks didn't fail,
+but couldn't be completed at the desired depth and level. This could be due
+to missing data while pruning, due to an insufficient dbcache or due to
+the node being shutdown before the call could finish. (#25574)
diff --git a/doc/release-notes-25730.md b/doc/release-notes-25730.md
new file mode 100644
index 0000000000..33393cf314
--- /dev/null
+++ b/doc/release-notes-25730.md
@@ -0,0 +1,6 @@
+RPC Wallet
+----------
+
+- RPC `listunspent` now has a new argument `include_immature_coinbase`
+ to include coinbase UTXOs that don't meet the minimum spendability
+ depth requirement (which before were silently skipped). (#25730) \ No newline at end of file
diff --git a/doc/release-notes-25934.md b/doc/release-notes-25934.md
new file mode 100644
index 0000000000..b4f1ae0d3c
--- /dev/null
+++ b/doc/release-notes-25934.md
@@ -0,0 +1,8 @@
+Low-level changes
+=================
+
+RPC
+---
+
+- RPC `listsinceblock` now accepts an optional `label` argument
+ to fetch incoming transactions having the specified label. (#25934) \ No newline at end of file
diff --git a/doc/release-notes-25943.md b/doc/release-notes-25943.md
new file mode 100644
index 0000000000..81b0a48b5d
--- /dev/null
+++ b/doc/release-notes-25943.md
@@ -0,0 +1,4 @@
+New RPC Argument
+--------
+- `sendrawtransaction` has a new, optional argument, `maxburnamount` with a default value of `0`. Any transaction containing an unspendable output with a value greater than `maxburnamount` will not be submitted. At present, the outputs deemed unspendable are those with scripts that begin with an `OP_RETURN` code (known as 'datacarriers'), scripts that exceed the maximum script size, and scripts that contain invalid opcodes.
+
diff --git a/doc/release-notes-25957.md b/doc/release-notes-25957.md
new file mode 100644
index 0000000000..c71afa2c2e
--- /dev/null
+++ b/doc/release-notes-25957.md
@@ -0,0 +1,9 @@
+Wallet
+------
+
+- Rescans for descriptor wallets are now significantly faster if compact
+ block filters (BIP158) are available. Since those are not constructed
+ by default, the configuration option "-blockfilterindex=1" has to be
+ provided to take advantage of the optimization. This improves the
+ performance of the RPC calls `rescanblockchain`, `importdescriptors`
+ and `restorewallet`. (#25957)
diff --git a/doc/release-notes-26213.md b/doc/release-notes-26213.md
new file mode 100644
index 0000000000..e78d718ca9
--- /dev/null
+++ b/doc/release-notes-26213.md
@@ -0,0 +1,8 @@
+Low-level changes
+=================
+
+- Previously `setban`, `addpeeraddress`, `walletcreatefundedpsbt`, methods
+ allowed non-boolean and non-null values to be passed as boolean parameters.
+ Any string, number, array, or object value that was passed would be treated
+ as false. After this change, passing any value except `true`, `false`, or
+ `null` now triggers a JSON value is not of expected type error. (#26213)
diff --git a/doc/release-notes-26265.md b/doc/release-notes-26265.md
new file mode 100644
index 0000000000..ca2313d956
--- /dev/null
+++ b/doc/release-notes-26265.md
@@ -0,0 +1,6 @@
+P2P and network changes
+---------
+
+- Transactions of non-witness size 65 and above are now allowed by mempool
+ and relay policy. This is to better reflect the actual afforded protections
+ against CVE-2017-12842 and open up additional use-cases of smaller transaction sizes. (#26265)
diff --git a/doc/release-notes-26471.md b/doc/release-notes-26471.md
new file mode 100644
index 0000000000..2cb74804ca
--- /dev/null
+++ b/doc/release-notes-26471.md
@@ -0,0 +1,13 @@
+Updated settings
+----------------
+
+- Setting `-blocksonly` will now reduce the maximum mempool memory
+ to 5MB (users may still use `-maxmempool` to override). Previously,
+ the default 300MB would be used, leading to unexpected memory usage
+ for users running with `-blocksonly` expecting it to eliminate
+ mempool memory usage.
+
+ As unused mempool memory is shared with dbcache, this also reduces
+ the dbcache size for users running with `-blocksonly`, potentially
+ impacting performance.
+
diff --git a/doc/release-notes-26618.md b/doc/release-notes-26618.md
new file mode 100644
index 0000000000..9d1ef3bd2e
--- /dev/null
+++ b/doc/release-notes-26618.md
@@ -0,0 +1,4 @@
+RPC Wallet
+----------
+
+- RPC `unloadwallet` now fails if a rescan is in progress. (#26618)
diff --git a/doc/release-notes-26628.md b/doc/release-notes-26628.md
new file mode 100644
index 0000000000..48a07c1e81
--- /dev/null
+++ b/doc/release-notes-26628.md
@@ -0,0 +1,4 @@
+JSON-RPC
+---
+
+The JSON-RPC server now rejects requests where a parameter is specified multiple times with the same name, instead of silently overwriting earlier parameter values with later ones. (#26628)
diff --git a/doc/release-notes-26646.md b/doc/release-notes-26646.md
new file mode 100644
index 0000000000..7f94505a01
--- /dev/null
+++ b/doc/release-notes-26646.md
@@ -0,0 +1,8 @@
+JSON-RPC
+--------
+
+The `testmempoolaccept` RPC now returns 2 additional results within the "fees" result:
+"effective-feerate" is the feerate including fees and sizes of transactions validated together if
+package validation was used, and also includes any modified fees from prioritisetransaction. The
+"effective-includes" result lists the wtxids of transactions whose modified fees and sizes were used
+in the effective-feerate (#26646).
diff --git a/doc/release-notes-26896.md b/doc/release-notes-26896.md
new file mode 100644
index 0000000000..ff4ab44e27
--- /dev/null
+++ b/doc/release-notes-26896.md
@@ -0,0 +1,7 @@
+Build System
+------------
+
+The --enable-upnp-default and --enable-natpmp-default options
+have been removed. If you want to use port mapping, you can
+configure it using a .conf file, or by passing the relevant
+options at runtime. \ No newline at end of file
diff --git a/doc/release-notes-27037.md b/doc/release-notes-27037.md
new file mode 100644
index 0000000000..ee30e64010
--- /dev/null
+++ b/doc/release-notes-27037.md
@@ -0,0 +1,5 @@
+RPC
+---
+
+- `decodescript` may now infer a Miniscript descriptor under P2WSH context if it is not lacking
+ information.
diff --git a/doc/release-notes-27068.md b/doc/release-notes-27068.md
new file mode 100644
index 0000000000..3f5c5dba37
--- /dev/null
+++ b/doc/release-notes-27068.md
@@ -0,0 +1,6 @@
+Wallet
+------
+
+- Wallet passphrases may now contain null characters.
+ Prior to this change, only characters up to the first
+ null character were recognized and accepted. (#27068) \ No newline at end of file
diff --git a/doc/release-notes-empty-template.md b/doc/release-notes-empty-template.md
index 8462714898..4cd2314308 100644
--- a/doc/release-notes-empty-template.md
+++ b/doc/release-notes-empty-template.md
@@ -25,7 +25,7 @@ How to Upgrade
If you are running an older version, shut it down. Wait until it has completely
shut down (which might take a few minutes in some cases), then run the
-installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
or `bitcoind`/`bitcoin-qt` (on Linux).
Upgrading directly from a version of Bitcoin Core that has reached its EOL is
diff --git a/doc/release-notes/release-notes-22.1.md b/doc/release-notes/release-notes-22.1.md
new file mode 100644
index 0000000000..d304b7e57a
--- /dev/null
+++ b/doc/release-notes/release-notes-22.1.md
@@ -0,0 +1,128 @@
+22.1 Release Notes
+==================
+
+Bitcoin Core version 22.1 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-22.1/>
+
+This release includes new features, various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.14+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+From Bitcoin Core 22.0 onwards, macOS versions earlier than 10.14 are no longer supported.
+
+Notable changes
+===============
+
+Updated settings
+----------------
+
+- In previous releases, the meaning of the command line option
+ `-persistmempool` (without a value provided) incorrectly disabled mempool
+ persistence. `-persistmempool` is now treated like other boolean options to
+ mean `-persistmempool=1`. Passing `-persistmempool=0`, `-persistmempool=1`
+ and `-nopersistmempool` is unaffected. (#23061)
+
+### P2P
+
+### RPC and other APIs
+
+- #25237 rpc: Capture UniValue by ref for rpcdoccheck
+- #25983 Prevent data race for pathHandlers
+- #26275 Fix crash on deriveaddresses when index is 2147483647 (2^31-1)
+
+### Wallet
+
+- #22781 wallet: fix the behavior of IsHDEnabled
+- #22949 fee: Round up fee calculation to avoid a lower than expected feerate
+- #23333 wallet: fix segfault by avoiding invalid default-ctored external_spk_managers entry
+
+### Build system
+
+- #22820 build, qt: Fix typo in QtInputSupport check
+- #23045 build: Restrict check for CRC32C intrinsic to aarch64
+- #23148 build: Fix guix linker-loader path and add check_ELF_interpreter
+- #23314 build: explicitly disable libsecp256k1 openssl based tests
+- #23580 build: patch qt to explicitly define previously implicit header include
+- #24215 guix: ignore additional failing certvalidator test
+- #24256 build: Bump depends packages (zmq, libXau)
+- #25201 windeploy: Renewed windows code signing certificate
+- #25985 Revert "build: Use Homebrew's sqlite package if it is available"
+- #26633 depends: update qt 5.12 url to archive location
+
+### GUI
+
+- #gui631 Disallow encryption of watchonly wallets
+- #gui680 Fixes MacOS 13 segfault by preventing certain notifications
+- #24498 qt: Avoid crash on startup if int specified in settings.json
+
+### Tests
+
+- #23716 test: replace hashlib.ripemd160 with an own implementation
+- #24239 test: fix ceildiv division by using integers
+
+### Utilities
+
+- #22390 system: skip trying to set the locale on NetBSD
+- #22895 don't call GetBlockPos in ReadBlockFromDisk without cs_main lock
+- #24104 fs: Make compatible with boost 1.78
+
+### Miscellaneous
+
+- #23335 refactor: include a missing <limits> header in fs.cpp
+- #23504 ci: Replace soon EOL hirsute with jammy
+- #26321 Adjust .tx/config for new Transifex CLI
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Andrew Chow
+- BlackcoinDev
+- Carl Dong
+- Hennadii Stepanov
+- Joan Karadimov
+- John Moffett
+- Jon Atack
+- Kittywhiskers Van Gogh
+- Marco Falke
+- Martin Zumsande
+- Michael Ford
+- muxator
+- Pieter Wuille
+- Ryan Ofsky
+- Saibato
+- Sebastian Falbesoner
+- W. J. van der Laan
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/doc/release-notes/release-notes-23.1.md b/doc/release-notes/release-notes-23.1.md
new file mode 100644
index 0000000000..31d9b7f068
--- /dev/null
+++ b/doc/release-notes/release-notes-23.1.md
@@ -0,0 +1,90 @@
+23.1 Release Notes
+==================
+
+Bitcoin Core version 23.1 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-23.1/>
+
+This release includes new features, various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+### P2P
+
+- #25314 p2p: always set nTime for self-advertisements
+
+### RPC and other APIs
+
+- #25220 rpc: fix incorrect warning for address type p2sh-segwit in createmultisig
+- #25237 rpc: Capture UniValue by ref for rpcdoccheck
+- #25983 Prevent data race for pathHandlers
+- #26275 Fix crash on deriveaddresses when index is 2147483647 (2^31-1)
+
+### Build system
+
+- #25201 windeploy: Renewed windows code signing certificate
+- #25788 guix: patch NSIS to remove .reloc sections from installer stubs
+- #25861 guix: use --build={arch}-guix-linux-gnu in cross toolchain
+- #25985 Revert "build: Use Homebrew's sqlite package if it is available"
+
+### GUI
+
+- #24668 build, qt: bump Qt5 version to 5.15.3
+- gui#631 Disallow encryption of watchonly wallets
+- gui#680 Fixes MacOS 13 segfault by preventing certain notifications
+
+### Tests
+
+- #24454 tests: Fix calculation of external input weights
+
+### Miscellaneous
+
+- #26321 Adjust .tx/config for new Transifex CLI
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Andrew Chow
+- brunoerg
+- Hennadii Stepanov
+- John Moffett
+- MacroFake
+- Martin Zumsande
+- Michael Ford
+- muxator
+- Pavol Rusnak
+- Sebastian Falbesoner
+- W. J. van der Laan
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/doc/release-notes/release-notes-24.0.1.md b/doc/release-notes/release-notes-24.0.1.md
new file mode 100644
index 0000000000..24920ba450
--- /dev/null
+++ b/doc/release-notes/release-notes-24.0.1.md
@@ -0,0 +1,391 @@
+24.0.1 Release Notes
+====================
+
+Due to last-minute issues (#26616), 24.0, although tagged, was never fully
+announced or released.
+
+Bitcoin Core version 24.0.1 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-24.0.1/>
+
+This release includes new features, various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+Notice of new option for transaction replacement policies
+=========================================================
+
+This version of Bitcoin Core adds a new `mempoolfullrbf` configuration
+option which allows users to change the policy their individual node
+will use for relaying and mining unconfirmed transactions. The option
+defaults to the same policy that was used in previous releases and no
+changes to node policy will occur if everyone uses the default.
+
+Some Bitcoin services today expect that the first version of an
+unconfirmed transaction that they see will be the version of the
+transaction that ultimately gets confirmed---a transaction acceptance
+policy sometimes called "first-seen".
+
+The Bitcoin Protocol does not, and cannot, provide any assurance that
+the first version of an unconfirmed transaction seen by a particular
+node will be the version that gets confirmed. If there are multiple
+versions of the same unconfirmed transaction available, only the miner
+who includes one of those transactions in a block gets to decide which
+version of the transaction gets confirmed.
+
+Despite this lack of assurance, multiple merchants and services today
+still make this assumption.
+
+There are several benefits to users from removing this *first-seen*
+simplification. One key benefit, the ability for the sender of a
+transaction to replace it with an alternative version paying higher
+fees, was realized in [Bitcoin Core 0.12.0][] (February 2016) with the
+introduction of [BIP125][] opt-in Replace By Fee (RBF).
+
+Since then, there has been discussion about completely removing the
+first-seen simplification and allowing users to replace any of their
+older unconfirmed transactions with newer transactions, a feature called
+*full-RBF*. This release includes a `mempoolfullrbf` configuration
+option that allows enabling full-RBF, although it defaults to off
+(allowing only opt-in RBF).
+
+Several alternative node implementations have already enabled full-RBF by
+default for years, and several contributors to Bitcoin Core are
+advocating for enabling full-RBF by default in a future version of
+Bitcoin Core.
+
+As more nodes that participate in relay and mining begin enabling
+full-RBF, replacement of unconfirmed transactions by ones offering higher
+fees may rapidly become more reliable.
+
+Contributors to this project strongly recommend that merchants and services
+not accept unconfirmed transactions as final, and if they insist on doing so,
+to take the appropriate steps to ensure they have some recourse or plan for
+when their assumptions do not hold.
+
+[Bitcoin Core 0.12.0]: https://bitcoincore.org/en/releases/0.12.0/#opt-in-replace-by-fee-transactions
+[bip125]: https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki
+
+Notable changes
+===============
+
+P2P and network changes
+-----------------------
+
+- To address a potential denial-of-service, the logic to download headers from peers
+ has been reworked. This is particularly relevant for nodes starting up for the
+ first time (or for nodes which are starting up after being offline for a long time).
+
+ Whenever headers are received from a peer that have a total chainwork that is either
+ less than the node's `-minimumchainwork` value or is sufficiently below the work at
+ the node's tip, a "presync" phase will begin, in which the node will download the
+ peer's headers and verify the cumulative work on the peer's chain, prior to storing
+ those headers permanently. Once that cumulative work is verified to be sufficiently high,
+ the headers will be redownloaded from that peer and fully validated and stored.
+
+ This may result in initial headers sync taking longer for new nodes starting up for
+ the first time, both because the headers will be downloaded twice, and because the effect
+ of a peer disconnecting during the presync phase (or while the node's best headers chain has less
+ than `-minimumchainwork`), will result in the node needing to use the headers presync mechanism
+ with the next peer as well (downloading the headers twice, again). (#25717)
+
+- With I2P connections, a new, transient address is used for each outbound
+ connection if `-i2pacceptincoming=0`. (#25355)
+
+Updated RPCs
+------------
+
+- The `-deprecatedrpc=softforks` configuration option has been removed. The
+ RPC `getblockchaininfo` no longer returns the `softforks` field, which was
+ previously deprecated in 23.0. (#23508) Information on soft fork status is
+ now only available via the `getdeploymentinfo` RPC.
+
+- The `deprecatedrpc=exclude_coinbase` configuration option has been removed.
+ The `receivedby` RPCs (`listreceivedbyaddress`, `listreceivedbylabel`,
+ `getreceivedbyaddress` and `getreceivedbylabel`) now always return results
+ accounting for received coins from coinbase outputs, without an option to
+ change that behaviour. Excluding coinbases was previously deprecated in 23.0.
+ (#25171)
+
+- The `deprecatedrpc=fees` configuration option has been removed. The top-level
+ fee fields `fee`, `modifiedfee`, `ancestorfees` and `descendantfees` are no
+ longer returned by RPCs `getmempoolentry`, `getrawmempool(verbose=true)`,
+ `getmempoolancestors(verbose=true)` and `getmempooldescendants(verbose=true)`.
+ The same fee fields can be accessed through the `fees` object in the result.
+ The top-level fee fields were previously deprecated in 23.0. (#25204)
+
+- The `getpeerinfo` RPC has been updated with a new `presynced_headers` field,
+ indicating the progress on the presync phase mentioned in the
+ "P2P and network changes" section above.
+
+Changes to wallet related RPCs can be found in the Wallet section below.
+
+New RPCs
+--------
+
+- The `sendall` RPC spends specific UTXOs to one or more recipients
+ without creating change. By default, the `sendall` RPC will spend
+ every UTXO in the wallet. `sendall` is useful to empty wallets or to
+ create a changeless payment from select UTXOs. When creating a payment
+ from a specific amount for which the recipient incurs the transaction
+ fee, continue to use the `subtractfeefromamount` option via the
+ `send`, `sendtoaddress`, or `sendmany` RPCs. (#24118)
+
+- A new `gettxspendingprevout` RPC has been added, which scans the mempool to find
+ transactions spending any of the given outpoints. (#24408)
+
+- The `simulaterawtransaction` RPC iterates over the inputs and outputs of the given
+ transactions, and tallies up the balance change for the given wallet. This can be
+ useful e.g. when verifying that a coin join like transaction doesn't contain unexpected
+ inputs that the wallet will then sign for unintentionally. (#22751)
+
+Updated REST APIs
+-----------------
+
+- The `/headers/` and `/blockfilterheaders/` endpoints have been updated to use
+ a query parameter instead of path parameter to specify the result count. The
+ count parameter is now optional, and defaults to 5 for both endpoints. The old
+ endpoints are still functional, and have no documented behaviour change.
+
+ For `/headers`, use
+ `GET /rest/headers/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>`
+ instead of
+ `GET /rest/headers/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated)
+
+ For `/blockfilterheaders/`, use
+ `GET /rest/blockfilterheaders/<FILTERTYPE>/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>`
+ instead of
+ `GET /rest/blockfilterheaders/<FILTERTYPE>/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated)
+
+ (#24098)
+
+Build System
+------------
+
+- Guix builds are now reproducible across architectures (x86_64 & aarch64). (#21194)
+
+New settings
+------------
+
+- A new `mempoolfullrbf` option has been added, which enables the mempool to
+ accept transaction replacement without enforcing BIP125 replaceability
+ signaling. (#25353)
+
+Wallet
+------
+
+- The `-walletrbf` startup option will now default to `true`. The
+ wallet will now default to opt-in RBF on transactions that it creates. (#25610)
+
+- The `replaceable` option for the `createrawtransaction` and
+ `createpsbt` RPCs will now default to `true`. Transactions created
+ with these RPCs will default to having opt-in RBF enabled. (#25610)
+
+- The `wsh()` output descriptor was extended with Miniscript support. You can import Miniscript
+ descriptors for P2WSH in a watchonly wallet to track coins, but you can't spend from them using
+ the Bitcoin Core wallet yet.
+ You can find more about Miniscript on the [reference website](https://bitcoin.sipa.be/miniscript/). (#24148)
+
+- The `tr()` output descriptor now supports multisig scripts through the `multi_a()` and
+ `sortedmulti_a()` functions. (#24043)
+
+- To help prevent fingerprinting transactions created by the Bitcoin Core wallet, change output
+ amounts are now randomized. (#24494)
+
+- The `listtransactions`, `gettransaction`, and `listsinceblock`
+ RPC methods now include a wtxid field (hash of serialized transaction,
+ including witness data) for each transaction. (#24198)
+
+- The `listsinceblock`, `listtransactions` and `gettransaction` output now contain a new
+ `parent_descs` field for every "receive" entry. (#25504)
+
+- A new optional `include_change` parameter was added to the `listsinceblock` command.
+
+- RPC `getreceivedbylabel` now returns an error, "Label not found
+ in wallet" (-4), if the label is not in the address book. (#25122)
+
+Migrating Legacy Wallets to Descriptor Wallets
+---------------------------------------------
+
+An experimental RPC `migratewallet` has been added to migrate Legacy (non-descriptor) wallets to
+Descriptor wallets. More information about the migration process is available in the
+[documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/managing-wallets.md#migrating-legacy-wallets-to-descriptor-wallets).
+
+GUI changes
+-----------
+
+- A new menu item to restore a wallet from a backup file has been added (gui#471).
+
+- Configuration changes made in the bitcoin GUI (such as the pruning setting,
+proxy settings, UPNP preferences) are now saved to `<datadir>/settings.json`
+file rather than to the Qt settings backend (windows registry or unix desktop
+config files), so these settings will now apply to bitcoind, instead of being
+ignored. (#15936, gui#602)
+
+- Also, the interaction between GUI settings and `bitcoin.conf` settings is
+simplified. Settings from `bitcoin.conf` are now displayed normally in the GUI
+settings dialog, instead of in a separate warning message ("Options set in this
+dialog are overridden by the configuration file: -setting=value"). And these
+settings can now be edited because `settings.json` values take precedence over
+`bitcoin.conf` values. (#15936)
+
+Low-level changes
+=================
+
+RPC
+---
+
+- The `deriveaddresses`, `getdescriptorinfo`, `importdescriptors` and `scantxoutset` commands now
+ accept Miniscript expression within a `wsh()` descriptor. (#24148)
+
+- The `getaddressinfo`, `decodescript`, `listdescriptors` and `listunspent` commands may now output
+ a Miniscript descriptor inside a `wsh()` where a `wsh(raw())` descriptor was previously returned. (#24148)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- /dev/fd0
+- 0xb10c
+- Adam Jonas
+- akankshakashyap
+- Ali Sherief
+- amadeuszpawlik
+- Andreas Kouloumos
+- Andrew Chow
+- Anthony Towns
+- Antoine Poinsot
+- Antoine Riard
+- Aurèle Oulès
+- avirgovi
+- Ayush Sharma
+- Baas
+- Ben Woosley
+- BrokenProgrammer
+- brunoerg
+- brydinh
+- Bushstar
+- Calvin Kim
+- CAnon
+- Carl Dong
+- chinggg
+- Cory Fields
+- Daniel Kraft
+- Daniela Brozzoni
+- darosior
+- Dave Scotese
+- David Bakin
+- dergoegge
+- dhruv
+- Dimitri
+- dontbyte
+- Duncan Dean
+- eugene
+- Eunoia
+- Fabian Jahr
+- furszy
+- Gleb Naumenko
+- glozow
+- Greg Weber
+- Gregory Sanders
+- gruve-p
+- Hennadii Stepanov
+- hiago
+- Igor Bubelov
+- ishaanam
+- Jacob P.
+- Jadi
+- James O'Beirne
+- Janna
+- Jarol Rodriguez
+- Jeremy Rand
+- Jeremy Rubin
+- jessebarton
+- João Barbosa
+- John Newbery
+- Jon Atack
+- Josiah Baker
+- Karl-Johan Alm
+- KevinMusgrave
+- Kiminuo
+- klementtan
+- Kolby Moroz
+- kouloumos
+- Kristaps Kaupe
+- Larry Ruane
+- Luke Dashjr
+- MarcoFalke
+- Marnix
+- Martin Leitner-Ankerl
+- Martin Zumsande
+- Michael Dietz
+- Michael Folkson
+- Michael Ford
+- Murch
+- mutatrum
+- muxator
+- Oskar Mendel
+- Pablo Greco
+- pasta
+- Patrick Strateman
+- Pavol Rusnak
+- Peter Bushnell
+- phyBrackets
+- Pieter Wuille
+- practicalswift
+- randymcmillan
+- Robert Spigler
+- Russell Yanofsky
+- S3RK
+- Samer Afach
+- Sebastian Falbesoner
+- Seibart Nedor
+- Shashwat
+- Sjors Provoost
+- Smlep
+- sogoagain
+- Stacie
+- Stéphan Vuylsteke
+- Suhail Saqan
+- Suhas Daftuar
+- t-bast
+- TakeshiMusgrave
+- Vasil Dimov
+- W. J. van der Laan
+- w0xlt
+- whiteh0rse
+- willcl-ark
+- William Casarin
+- Yancy Ribbens
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/doc/release-notes/release-notes-24.0.md b/doc/release-notes/release-notes-24.0.md
new file mode 100644
index 0000000000..a0227aa17f
--- /dev/null
+++ b/doc/release-notes/release-notes-24.0.md
@@ -0,0 +1,4 @@
+Due to last-minute issues (#26616), 24.0, although tagged, was never fully
+announced or released.
+
+See the release notes for 24.0.1 instead.
diff --git a/doc/release-process.md b/doc/release-process.md
index 17a03f7dcd..f1fd72f8ac 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -46,10 +46,10 @@ Release Process
- Clear the release notes and move them to the wiki (see "Write the release notes" below).
- Translations on Transifex:
- Pull translations from Transifex into the master branch.
- - Create [a new resource](https://www.transifex.com/bitcoin/bitcoin/content/) named after the major version with the slug `[bitcoin.qt-translation-<RRR>x]`, where `RRR` is the major branch number padded with zeros. Use `src/qt/locale/bitcoin_en.xlf` to create it.
- - In the project workflow settings, ensure that [Translation Memory Fill-up](https://docs.transifex.com/translation-memory/enabling-autofill) is enabled and that [Translation Memory Context Matching](https://docs.transifex.com/translation-memory/translation-memory-with-context) is disabled.
+ - Create [a new resource](https://www.transifex.com/bitcoin/bitcoin/content/) named after the major version with the slug `qt-translation-<RRR>x`, where `RRR` is the major branch number padded with zeros. Use `src/qt/locale/bitcoin_en.xlf` to create it.
+ - In the project workflow settings, ensure that [Translation Memory Fill-up](https://help.transifex.com/en/articles/6224817-setting-up-translation-memory-fill-up) is enabled and that [Translation Memory Context Matching](https://help.transifex.com/en/articles/6224753-translation-memory-with-context) is disabled.
- Update the Transifex slug in [`.tx/config`](/.tx/config) to the slug of the resource created in the first step. This identifies which resource the translations will be synchronized from.
- - Make an announcement that translators can start translating for the new version. You can use one of the [previous announcements](https://www.transifex.com/bitcoin/bitcoin/announcements/) as a template.
+ - Make an announcement that translators can start translating for the new version. You can use one of the [previous announcements](https://www.transifex.com/bitcoin/communication/) as a template.
- Change the auto-update URL for the resource to `master`, e.g. `https://raw.githubusercontent.com/bitcoin/bitcoin/master/src/qt/locale/bitcoin_en.xlf`. (Do this only after the previous steps, to prevent an auto-update from interfering.)
#### After branch-off (on the major release branch)
@@ -134,7 +134,6 @@ Follow the relevant Guix README.md sections:
### Verify other builders' signatures to your own (optional)
-- [Add other builders keys to your gpg keyring, and/or refresh keys](/contrib/builder-keys/README.md)
- [Verifying build output attestations](/contrib/guix/README.md#verifying-build-output-attestations)
### Commit your non codesigned signature to guix.sigs
@@ -193,7 +192,6 @@ popd
### Verify other builders' signatures to your own (optional)
-- [Add other builders keys to your gpg keyring, and/or refresh keys](/contrib/builder-keys/README.md)
- [Verifying build output attestations](/contrib/guix/README.md#verifying-build-output-attestations)
### Commit your codesigned signature to guix.sigs (for the signed macOS/Windows binaries)
diff --git a/doc/tracing.md b/doc/tracing.md
index b6e3b9263a..6e60901496 100644
--- a/doc/tracing.md
+++ b/doc/tracing.md
@@ -76,7 +76,7 @@ the passed message.
#### Tracepoint `net:outbound_message`
-Is called when a message is send to a peer over the P2P network. Passes
+Is called when a message is sent to a peer over the P2P network. Passes
information about our peer, the connection and the message as arguments.
Arguments passed:
@@ -116,7 +116,7 @@ added to and removed (spent) from the cache when we connect a new block.
(`chainstate.CoinsTip()`). For example, the RPCs `generateblock` and
`getblocktemplate` call `TestBlockValidity()`, which applies the UTXO set
changes to a temporary cache. Similarly, mempool consistency checks, which are
-frequent on regtest, also apply the the UTXO set changes to a temporary cache.
+frequent on regtest, also apply the UTXO set changes to a temporary cache.
Changes to the _main_ UTXO cache and to temporary caches trigger the tracepoints.
We can't tell if a temporary cache or the _main_ cache was changed.
@@ -253,8 +253,8 @@ TRACE6(net, inbound_message,
### Guidelines and best practices
-#### Clear motivation and use-case
-Tracepoints need a clear motivation and use-case. The motivation should
+#### Clear motivation and use case
+Tracepoints need a clear motivation and use case. The motivation should
outweigh the impact on, for example, code readability. There is no point in
adding tracepoints that don't end up being used.
diff --git a/share/rpcauth/rpcauth.py b/share/rpcauth/rpcauth.py
index d441d5f21d..cc7bba1f8b 100755
--- a/share/rpcauth/rpcauth.py
+++ b/share/rpcauth/rpcauth.py
@@ -4,22 +4,20 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from argparse import ArgumentParser
-from base64 import urlsafe_b64encode
from getpass import getpass
-from os import urandom
-
+from secrets import token_hex, token_urlsafe
import hmac
def generate_salt(size):
"""Create size byte hex salt"""
- return urandom(size).hex()
+ return token_hex(size)
def generate_password():
"""Create 32 byte b64 password"""
- return urlsafe_b64encode(urandom(32)).decode('utf-8')
+ return token_urlsafe(32)
def password_to_hmac(salt, password):
- m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), 'SHA256')
+ m = hmac.new(salt.encode('utf-8'), password.encode('utf-8'), 'SHA256')
return m.hexdigest()
def main():
@@ -38,8 +36,8 @@ def main():
password_hmac = password_to_hmac(salt, args.password)
print('String to be appended to bitcoin.conf:')
- print('rpcauth={0}:{1}${2}'.format(args.username, salt, password_hmac))
- print('Your password:\n{0}'.format(args.password))
+ print(f'rpcauth={args.username}:{salt}${password_hmac}')
+ print(f'Your password:\n{args.password}')
if __name__ == '__main__':
main()
diff --git a/src/.clang-tidy b/src/.clang-tidy
index 9d78ccc959..b2c1b49588 100644
--- a/src/.clang-tidy
+++ b/src/.clang-tidy
@@ -7,22 +7,14 @@ modernize-use-default-member-init,
modernize-use-nullptr,
performance-for-range-copy,
performance-move-const-arg,
+performance-no-automatic-move,
performance-unnecessary-copy-initialization,
+readability-const-return-type,
readability-redundant-declaration,
readability-redundant-string-init,
'
-WarningsAsErrors: '
-bugprone-argument-comment,
-bugprone-use-after-move,
-misc-unused-using-decls,
-modernize-use-default-member-init,
-modernize-use-nullptr,
-performance-for-range-copy,
-performance-move-const-arg,
-performance-unnecessary-copy-initialization,
-readability-redundant-declaration,
-readability-redundant-string-init,
-'
+WarningsAsErrors: '*'
CheckOptions:
- key: performance-move-const-arg.CheckTriviallyCopyableMove
value: false
+HeaderFilterRegex: '.'
diff --git a/src/Makefile.am b/src/Makefile.am
index bc1c6a0d0f..53c809c901 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,7 @@ noinst_LTLIBRARIES =
bin_PROGRAMS =
noinst_PROGRAMS =
+check_PROGRAMS =
TESTS =
BENCHMARKS =
@@ -133,6 +134,9 @@ BITCOIN_CORE_H = \
clientversion.h \
coins.h \
common/bloom.h \
+ common/init.h \
+ common/run_command.h \
+ common/url.h \
compat/assumptions.h \
compat/byteswap.h \
compat/compat.h \
@@ -170,11 +174,15 @@ BITCOIN_CORE_H = \
interfaces/ipc.h \
interfaces/node.h \
interfaces/wallet.h \
+ kernel/blockmanager_opts.h \
kernel/chain.h \
+ kernel/chainparams.h \
kernel/chainstatemanager_opts.h \
kernel/checks.h \
kernel/coinstats.h \
kernel/context.h \
+ kernel/cs_main.h \
+ kernel/mempool_entry.h \
kernel/mempool_limits.h \
kernel/mempool_options.h \
kernel/mempool_persist.h \
@@ -194,12 +202,16 @@ BITCOIN_CORE_H = \
netbase.h \
netgroup.h \
netmessagemaker.h \
+ node/blockmanager_args.h \
node/blockstorage.h \
node/caches.h \
node/chainstate.h \
+ node/chainstatemanager_args.h \
node/coin.h \
+ node/coins_view_args.h \
node/connection_types.h \
node/context.h \
+ node/database_args.h \
node/eviction.h \
node/interface_ui.h \
node/mempool_args.h \
@@ -208,6 +220,7 @@ BITCOIN_CORE_H = \
node/minisketchwrapper.h \
node/psbt.h \
node/transaction.h \
+ node/txreconciliation.h \
node/utxo_snapshot.h \
node/validation_cache_args.h \
noui.h \
@@ -254,7 +267,6 @@ BITCOIN_CORE_H = \
support/events.h \
support/lockedpool.h \
sync.h \
- threadinterrupt.h \
threadsafety.h \
timedata.h \
torcontrol.h \
@@ -270,6 +282,7 @@ BITCOIN_CORE_H = \
util/check.h \
util/epochguard.h \
util/error.h \
+ util/exception.h \
util/fastrange.h \
util/fees.h \
util/getuniquepath.h \
@@ -293,6 +306,7 @@ BITCOIN_CORE_H = \
util/syserror.h \
util/system.h \
util/thread.h \
+ util/threadinterrupt.h \
util/threadnames.h \
util/time.h \
util/tokenpipe.h \
@@ -300,7 +314,6 @@ BITCOIN_CORE_H = \
util/translation.h \
util/types.h \
util/ui_change_type.h \
- util/url.h \
util/vector.h \
validation.h \
validationinterface.h \
@@ -344,11 +357,7 @@ obj/build.h: FORCE
"$(abs_top_srcdir)"
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
-
-# server: shared between bitcoind and bitcoin-qt
-# Contains code accessing mempool and chain state that is meant to be separated
-# from wallet and gui code (see node/README.md). Shared code should go in
-# libbitcoin_common or libbitcoin_util libraries, instead.
+# node #
libbitcoin_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_node_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_node_a_SOURCES = \
@@ -375,17 +384,22 @@ libbitcoin_node_a_SOURCES = \
kernel/checks.cpp \
kernel/coinstats.cpp \
kernel/context.cpp \
+ kernel/cs_main.cpp \
kernel/mempool_persist.cpp \
mapport.cpp \
net.cpp \
net_processing.cpp \
netgroup.cpp \
+ node/blockmanager_args.cpp \
node/blockstorage.cpp \
node/caches.cpp \
node/chainstate.cpp \
+ node/chainstatemanager_args.cpp \
node/coin.cpp \
+ node/coins_view_args.cpp \
node/connection_types.cpp \
node/context.cpp \
+ node/database_args.cpp \
node/eviction.cpp \
node/interface_ui.cpp \
node/interfaces.cpp \
@@ -395,6 +409,8 @@ libbitcoin_node_a_SOURCES = \
node/minisketchwrapper.cpp \
node/psbt.cpp \
node/transaction.cpp \
+ node/txreconciliation.cpp \
+ node/utxo_snapshot.cpp \
node/validation_cache_args.cpp \
noui.cpp \
policy/fees.cpp \
@@ -437,7 +453,9 @@ endif
if !ENABLE_WALLET
libbitcoin_node_a_SOURCES += dummywallet.cpp
endif
+#
+# zmq #
if ENABLE_ZMQ
libbitcoin_zmq_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
@@ -448,10 +466,9 @@ libbitcoin_zmq_a_SOURCES = \
zmq/zmqrpc.cpp \
zmq/zmqutil.cpp
endif
+#
-
-# wallet: shared between bitcoind and bitcoin-qt, but only linked
-# when wallet enabled
+# wallet #
libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(BDB_CPPFLAGS) $(SQLITE_CFLAGS)
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_a_SOURCES = \
@@ -490,14 +507,17 @@ endif
if USE_BDB
libbitcoin_wallet_a_SOURCES += wallet/bdb.cpp wallet/salvage.cpp
endif
+#
+# wallet tool #
libbitcoin_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libbitcoin_wallet_tool_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_tool_a_SOURCES = \
wallet/wallettool.cpp \
$(BITCOIN_CORE_H)
+#
-# crypto primitives library
+# crypto #
crypto_libbitcoin_crypto_base_la_CPPFLAGS = $(AM_CPPFLAGS)
# Specify -static in both CXXFLAGS and LDFLAGS so libtool will only build a
@@ -577,8 +597,9 @@ crypto_libbitcoin_crypto_arm_shani_la_CPPFLAGS = $(AM_CPPFLAGS)
crypto_libbitcoin_crypto_arm_shani_la_CXXFLAGS += $(ARM_SHANI_CXXFLAGS)
crypto_libbitcoin_crypto_arm_shani_la_CPPFLAGS += -DENABLE_ARM_SHANI
crypto_libbitcoin_crypto_arm_shani_la_SOURCES = crypto/sha256_arm_shani.cpp
+#
-# consensus: shared between all executables that validate any consensus rules.
+# consensus #
libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_consensus_a_SOURCES = \
@@ -614,9 +635,10 @@ libbitcoin_consensus_a_SOURCES = \
util/strencodings.cpp \
util/strencodings.h \
version.h
+#
-# common: shared between bitcoind, and bitcoin-qt and non-server tools
-libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+# common #
+libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \
base58.cpp \
@@ -624,12 +646,16 @@ libbitcoin_common_a_SOURCES = \
chainparams.cpp \
coins.cpp \
common/bloom.cpp \
+ common/init.cpp \
+ common/interfaces.cpp \
+ common/run_command.cpp \
compressor.cpp \
core_read.cpp \
core_write.cpp \
deploymentinfo.cpp \
external_signer.cpp \
init/common.cpp \
+ kernel/chainparams.cpp \
key.cpp \
key_io.cpp \
merkleblock.cpp \
@@ -642,8 +668,9 @@ libbitcoin_common_a_SOURCES = \
policy/policy.cpp \
protocol.cpp \
psbt.cpp \
- rpc/rawtransaction_util.cpp \
rpc/external_signer.cpp \
+ rpc/rawtransaction_util.cpp \
+ rpc/request.cpp \
rpc/util.cpp \
scheduler.cpp \
script/descriptor.cpp \
@@ -654,29 +681,31 @@ libbitcoin_common_a_SOURCES = \
warnings.cpp \
$(BITCOIN_CORE_H)
-# util: shared between all executables.
-libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
+if USE_LIBEVENT
+libbitcoin_common_a_CPPFLAGS += $(EVENT_CFLAGS)
+libbitcoin_common_a_SOURCES += common/url.cpp
+endif
+#
+
+# util #
+libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_util_a_SOURCES = \
support/lockedpool.cpp \
chainparamsbase.cpp \
clientversion.cpp \
fs.cpp \
- interfaces/echo.cpp \
- interfaces/handler.cpp \
- interfaces/init.cpp \
logging.cpp \
random.cpp \
randomenv.cpp \
- rpc/request.cpp \
support/cleanse.cpp \
sync.cpp \
- threadinterrupt.cpp \
util/asmap.cpp \
util/bip32.cpp \
util/bytevectorhash.cpp \
util/check.cpp \
util/error.cpp \
+ util/exception.cpp \
util/fees.cpp \
util/getuniquepath.cpp \
util/hasher.cpp \
@@ -689,6 +718,7 @@ libbitcoin_util_a_SOURCES = \
util/readwritefile.cpp \
util/settings.cpp \
util/thread.cpp \
+ util/threadinterrupt.cpp \
util/threadnames.cpp \
util/serfloat.cpp \
util/spanparsing.cpp \
@@ -698,12 +728,9 @@ libbitcoin_util_a_SOURCES = \
util/time.cpp \
util/tokenpipe.cpp \
$(BITCOIN_CORE_H)
+#
-if USE_LIBEVENT
-libbitcoin_util_a_SOURCES += util/url.cpp
-endif
-
-# cli: shared between bitcoin-cli and bitcoin-qt
+# cli #
libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_cli_a_SOURCES = \
@@ -764,6 +791,7 @@ endif
bitcoin_cli_LDADD = \
$(LIBBITCOIN_CLI) \
$(LIBUNIVALUE) \
+ $(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO)
@@ -836,11 +864,12 @@ bitcoin_chainstate_SOURCES = bitcoin-chainstate.cpp
bitcoin_chainstate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
bitcoin_chainstate_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-# $(LIBTOOL_APP_LDFLAGS) deliberately omitted here so that we can test linking
-# bitcoin-chainstate against libbitcoinkernel as a shared or static library by
-# setting --{en,dis}able-shared.
-bitcoin_chainstate_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(PTHREAD_FLAGS)
+bitcoin_chainstate_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(PTHREAD_FLAGS) $(LIBTOOL_APP_LDFLAGS) -static
bitcoin_chainstate_LDADD = $(LIBBITCOINKERNEL)
+
+# libtool is unable to calculate this indirect dependency, presumably because it's a subproject.
+# libsecp256k1 only needs to be linked in when libbitcoinkernel is static.
+bitcoin_chainstate_LDADD += $(LIBSECP256K1)
#
# bitcoinkernel library #
@@ -859,15 +888,6 @@ libbitcoinkernel_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp
# to export from the library.
libbitcoinkernel_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -fvisibility=default
-# TODO: For now, Specify -static in both CXXFLAGS and LDFLAGS when building for
-# windows targets so libtool will only build a static version of this
-# library. There are unresolved problems when building dll's for mingw-w64
-# and attempting to statically embed libstdc++, libpthread, etc.
-if TARGET_WINDOWS
-libbitcoinkernel_la_LDFLAGS += -static
-libbitcoinkernel_la_CXXFLAGS += -static
-endif
-
# TODO: libbitcoinkernel is a work in progress consensus engine library, as more
# and more modules are decoupled from the consensus engine, this list will
# shrink to only those which are absolutely necessary.
@@ -892,14 +912,17 @@ libbitcoinkernel_la_SOURCES = \
hash.cpp \
kernel/chain.cpp \
kernel/checks.cpp \
+ kernel/chainparams.cpp \
kernel/coinstats.cpp \
kernel/context.cpp \
+ kernel/cs_main.cpp \
kernel/mempool_persist.cpp \
key.cpp \
logging.cpp \
node/blockstorage.cpp \
node/chainstate.cpp \
node/interface_ui.cpp \
+ node/utxo_snapshot.cpp \
policy/feerate.cpp \
policy/fees.cpp \
policy/packages.cpp \
@@ -923,11 +946,11 @@ libbitcoinkernel_la_SOURCES = \
support/cleanse.cpp \
support/lockedpool.cpp \
sync.cpp \
- threadinterrupt.cpp \
txdb.cpp \
txmempool.cpp \
uint256.cpp \
util/check.cpp \
+ util/exception.cpp \
util/getuniquepath.cpp \
util/hasher.cpp \
util/moneystr.cpp \
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index e1e2066877..f1e4e706a1 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -32,6 +32,7 @@ bench_bench_bitcoin_SOURCES = \
bench/examples.cpp \
bench/gcs_filter.cpp \
bench/hashpadding.cpp \
+ bench/load_external.cpp \
bench/lockedpool.cpp \
bench/logging.cpp \
bench/mempool_eviction.cpp \
@@ -79,6 +80,7 @@ if ENABLE_WALLET
bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp
bench_bench_bitcoin_SOURCES += bench/wallet_loading.cpp
+bench_bench_bitcoin_SOURCES += bench/wallet_create_tx.cpp
bench_bench_bitcoin_LDADD += $(BDB_LIBS) $(SQLITE_LIBS)
endif
diff --git a/src/Makefile.minisketch.include b/src/Makefile.minisketch.include
index b337f48349..1363bec34e 100644
--- a/src/Makefile.minisketch.include
+++ b/src/Makefile.minisketch.include
@@ -31,7 +31,7 @@ if ENABLE_TESTS
if !ENABLE_FUZZ
MINISKETCH_TEST = minisketch/test
TESTS += $(MINISKETCH_TEST)
-noinst_PROGRAMS += $(MINISKETCH_TEST)
+check_PROGRAMS += $(MINISKETCH_TEST)
minisketch_test_SOURCES = $(MINISKETCH_TEST_SOURCES_INT)
minisketch_test_CPPFLAGS = $(AM_CPPFLAGS) $(LIBMINISKETCH_CPPFLAGS)
diff --git a/src/Makefile.qt_locale.include b/src/Makefile.qt_locale.include
index 8638bd024c..c44cf61a1a 100644
--- a/src/Makefile.qt_locale.include
+++ b/src/Makefile.qt_locale.include
@@ -31,6 +31,7 @@ QT_TS = \
qt/locale/bitcoin_gl.ts \
qt/locale/bitcoin_gl_ES.ts \
qt/locale/bitcoin_gu.ts \
+ qt/locale/bitcoin_ha.ts \
qt/locale/bitcoin_he.ts \
qt/locale/bitcoin_hr.ts \
qt/locale/bitcoin_hu.ts \
@@ -43,6 +44,7 @@ QT_TS = \
qt/locale/bitcoin_kl.ts \
qt/locale/bitcoin_km.ts \
qt/locale/bitcoin_ko.ts \
+ qt/locale/bitcoin_ku.ts \
qt/locale/bitcoin_ku_IQ.ts \
qt/locale/bitcoin_ky.ts \
qt/locale/bitcoin_la.ts \
@@ -58,6 +60,7 @@ QT_TS = \
qt/locale/bitcoin_ne.ts \
qt/locale/bitcoin_nl.ts \
qt/locale/bitcoin_no.ts \
+ qt/locale/bitcoin_pa.ts \
qt/locale/bitcoin_pam.ts \
qt/locale/bitcoin_pl.ts \
qt/locale/bitcoin_pt.ts \
@@ -78,10 +81,13 @@ QT_TS = \
qt/locale/bitcoin_ta.ts \
qt/locale/bitcoin_te.ts \
qt/locale/bitcoin_th.ts \
+ qt/locale/bitcoin_tk.ts \
+ qt/locale/bitcoin_tl.ts \
qt/locale/bitcoin_tr.ts \
qt/locale/bitcoin_ug.ts \
qt/locale/bitcoin_uk.ts \
qt/locale/bitcoin_ur.ts \
+ qt/locale/bitcoin_uz.ts \
qt/locale/bitcoin_uz@Cyrl.ts \
qt/locale/bitcoin_uz@Latn.ts \
qt/locale/bitcoin_vi.ts \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 253f64d2c3..a39b0abd9d 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -66,6 +66,7 @@ BITCOIN_TESTS =\
test/addrman_tests.cpp \
test/allocator_tests.cpp \
test/amount_tests.cpp \
+ test/argsman_tests.cpp \
test/arith_uint256_tests.cpp \
test/banman_tests.cpp \
test/base32_tests.cpp \
@@ -77,6 +78,7 @@ BITCOIN_TESTS =\
test/blockencodings_tests.cpp \
test/blockfilter_index_tests.cpp \
test/blockfilter_tests.cpp \
+ test/blockmanager_tests.cpp \
test/bloom_tests.cpp \
test/bswap_tests.cpp \
test/checkqueue_tests.cpp \
@@ -145,8 +147,10 @@ BITCOIN_TESTS =\
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
+ test/translation_tests.cpp \
test/txindex_tests.cpp \
test/txpackage_tests.cpp \
+ test/txreconciliation_tests.cpp \
test/txrequest_tests.cpp \
test/txvalidation_tests.cpp \
test/txvalidationcache_tests.cpp \
@@ -159,7 +163,8 @@ BITCOIN_TESTS =\
test/validation_flush_tests.cpp \
test/validation_tests.cpp \
test/validationinterface_tests.cpp \
- test/versionbits_tests.cpp
+ test/versionbits_tests.cpp \
+ test/xoroshiro128plusplus_tests.cpp
if ENABLE_WALLET
BITCOIN_TESTS += \
@@ -171,12 +176,12 @@ BITCOIN_TESTS += \
wallet/test/wallet_crypto_tests.cpp \
wallet/test/wallet_transaction_tests.cpp \
wallet/test/coinselector_tests.cpp \
- wallet/test/availablecoins_tests.cpp \
wallet/test/init_tests.cpp \
wallet/test/ismine_tests.cpp \
wallet/test/rpc_util_tests.cpp \
wallet/test/scriptpubkeyman_tests.cpp \
- wallet/test/walletload_tests.cpp
+ wallet/test/walletload_tests.cpp \
+ wallet/test/group_outputs_tests.cpp
FUZZ_SUITE_LD_COMMON +=\
$(SQLITE_LIBS) \
@@ -196,8 +201,6 @@ FUZZ_WALLET_SRC += \
endif # USE_SQLITE
BITCOIN_TEST_SUITE += \
- wallet/test/util.cpp \
- wallet/test/util.h \
wallet/test/wallet_test_fixture.cpp \
wallet/test/wallet_test_fixture.h \
wallet/test/init_test_fixture.cpp \
@@ -248,6 +251,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/chain.cpp \
test/fuzz/checkqueue.cpp \
test/fuzz/coins_view.cpp \
+ test/fuzz/coinscache_sim.cpp \
test/fuzz/connman.cpp \
test/fuzz/crypto.cpp \
test/fuzz/crypto_aes256.cpp \
@@ -293,6 +297,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/parse_numbers.cpp \
test/fuzz/parse_script.cpp \
test/fuzz/parse_univalue.cpp \
+ test/fuzz/partially_downloaded_block.cpp \
test/fuzz/policy_estimator.cpp \
test/fuzz/policy_estimator_io.cpp \
test/fuzz/pow.cpp \
@@ -374,8 +379,8 @@ endif
if TARGET_WINDOWS
else
if ENABLE_BENCH
- @echo "Running bench/bench_bitcoin (one iteration sanity check)..."
- $(BENCH_BINARY) --sanity-check > /dev/null
+ @echo "Running bench/bench_bitcoin (one iteration sanity check, only high priority)..."
+ $(BENCH_BINARY) -sanity-check -priority-level=high
endif
endif
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include
index b35d713d57..aa9c052750 100644
--- a/src/Makefile.test_fuzz.include
+++ b/src/Makefile.test_fuzz.include
@@ -11,7 +11,8 @@ TEST_FUZZ_H = \
test/fuzz/fuzz.h \
test/fuzz/FuzzedDataProvider.h \
test/fuzz/util.h \
- test/fuzz/util/mempool.h
+ test/fuzz/util/mempool.h \
+ test/fuzz/util/net.h
libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
@@ -19,4 +20,5 @@ libtest_fuzz_a_SOURCES = \
test/fuzz/fuzz.cpp \
test/fuzz/util.cpp \
test/fuzz/util/mempool.cpp \
+ test/fuzz/util/net.cpp \
$(TEST_FUZZ_H)
diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include
index ada789f1b0..aefefe789a 100644
--- a/src/Makefile.test_util.include
+++ b/src/Makefile.test_util.include
@@ -5,25 +5,35 @@
LIBTEST_UTIL=libtest_util.a
EXTRA_LIBRARIES += \
- $(LIBTEST_UTIL)
+ $(LIBTEST_UTIL)
TEST_UTIL_H = \
- test/util/blockfilter.h \
- test/util/chainstate.h \
- test/util/logging.h \
- test/util/mining.h \
- test/util/net.h \
- test/util/script.h \
- test/util/setup_common.h \
- test/util/str.h \
- test/util/transaction_utils.h \
- test/util/validation.h \
- test/util/wallet.h
+ test/util/blockfilter.h \
+ test/util/chainstate.h \
+ test/util/coins.h \
+ test/util/json.h \
+ test/util/logging.h \
+ test/util/mining.h \
+ test/util/net.h \
+ test/util/random.h \
+ test/util/script.h \
+ test/util/setup_common.h \
+ test/util/str.h \
+ test/util/transaction_utils.h \
+ test/util/txmempool.h \
+ test/util/validation.h \
+ test/util/xoroshiro128plusplus.h
+
+if ENABLE_WALLET
+TEST_UTIL_H += wallet/test/util.h
+endif # ENABLE_WALLET
libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libtest_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libtest_util_a_SOURCES = \
test/util/blockfilter.cpp \
+ test/util/coins.cpp \
+ test/util/json.cpp \
test/util/logging.cpp \
test/util/mining.cpp \
test/util/net.cpp \
@@ -31,6 +41,11 @@ libtest_util_a_SOURCES = \
test/util/setup_common.cpp \
test/util/str.cpp \
test/util/transaction_utils.cpp \
- test/util/validation.cpp \
- test/util/wallet.cpp \
- $(TEST_UTIL_H)
+ test/util/txmempool.cpp \
+ test/util/validation.cpp
+
+if ENABLE_WALLET
+libtest_util_a_SOURCES += wallet/test/util.cpp
+endif # ENABLE_WALLET
+
+libtest_util_a_SOURCES += $(TEST_UTIL_H)
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 7106d819b0..9ae8244d1c 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@
#include <cstdint>
#include <fs.h>
#include <hash.h>
+#include <logging.h>
#include <logging/timer.h>
#include <netbase.h>
#include <netgroup.h>
@@ -34,10 +35,9 @@ bool SerializeDB(Stream& stream, const Data& data)
{
// Write and commit header, data
try {
- CHashWriter hasher(stream.GetType(), stream.GetVersion());
- stream << Params().MessageStart() << data;
- hasher << Params().MessageStart() << data;
- stream << hasher.GetHash();
+ HashedSourceWriter hashwriter{stream};
+ hashwriter << Params().MessageStart() << data;
+ stream << hashwriter.GetHash();
} catch (const std::exception& e) {
return error("%s: Serialize or I/O error - %s", __func__, e.what());
}
@@ -191,7 +191,7 @@ std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, con
const auto path_addr{args.GetDataDirNet() / "peers.dat"};
try {
DeserializeFileDB(path_addr, *addrman, CLIENT_VERSION);
- LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
+ LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} catch (const DbNotFoundError&) {
// Addrman can be in an inconsistent state after failure, reset it
addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
diff --git a/src/addrman.cpp b/src/addrman.cpp
index f16ff2230b..f5ca9a5c34 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2012 Pieter Wuille
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -291,6 +291,7 @@ void AddrManImpl::Unserialize(Stream& s_)
mapAddr[info] = n;
info.nRandomPos = vRandom.size();
vRandom.push_back(n);
+ m_network_counts[info.GetNetwork()].n_new++;
}
nIdCount = nNew;
@@ -310,6 +311,7 @@ void AddrManImpl::Unserialize(Stream& s_)
mapAddr[info] = nIdCount;
vvTried[nKBucket][nKBucketPos] = nIdCount;
nIdCount++;
+ m_network_counts[info.GetNetwork()].n_tried++;
} else {
nLost++;
}
@@ -425,6 +427,8 @@ AddrInfo* AddrManImpl::Create(const CAddress& addr, const CNetAddr& addrSource,
mapAddr[addr] = nId;
mapInfo[nId].nRandomPos = vRandom.size();
vRandom.push_back(nId);
+ nNew++;
+ m_network_counts[addr.GetNetwork()].n_new++;
if (pnId)
*pnId = nId;
return &mapInfo[nId];
@@ -464,6 +468,7 @@ void AddrManImpl::Delete(int nId)
assert(info.nRefCount == 0);
SwapRandom(info.nRandomPos, vRandom.size() - 1);
+ m_network_counts[info.GetNetwork()].n_new--;
vRandom.pop_back();
mapAddr.erase(info);
mapInfo.erase(nId);
@@ -481,7 +486,7 @@ void AddrManImpl::ClearNew(int nUBucket, int nUBucketPos)
assert(infoDelete.nRefCount > 0);
infoDelete.nRefCount--;
vvNew[nUBucket][nUBucketPos] = -1;
- LogPrint(BCLog::ADDRMAN, "Removed %s from new[%i][%i]\n", infoDelete.ToString(), nUBucket, nUBucketPos);
+ LogPrint(BCLog::ADDRMAN, "Removed %s from new[%i][%i]\n", infoDelete.ToStringAddrPort(), nUBucket, nUBucketPos);
if (infoDelete.nRefCount == 0) {
Delete(nIdDelete);
}
@@ -504,6 +509,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
}
}
nNew--;
+ m_network_counts[info.GetNetwork()].n_new--;
assert(info.nRefCount == 0);
@@ -522,6 +528,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
infoOld.fInTried = false;
vvTried[nKBucket][nKBucketPos] = -1;
nTried--;
+ m_network_counts[infoOld.GetNetwork()].n_tried--;
// find which new bucket it belongs to
int nUBucket = infoOld.GetNewBucket(nKey, m_netgroupman);
@@ -533,14 +540,16 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
infoOld.nRefCount = 1;
vvNew[nUBucket][nUBucketPos] = nIdEvict;
nNew++;
+ m_network_counts[infoOld.GetNetwork()].n_new++;
LogPrint(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n",
- infoOld.ToString(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
+ infoOld.ToStringAddrPort(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
}
assert(vvTried[nKBucket][nKBucketPos] == -1);
vvTried[nKBucket][nKBucketPos] = nId;
nTried++;
info.fInTried = true;
+ m_network_counts[info.GetNetwork()].n_tried++;
}
bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty)
@@ -591,7 +600,6 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::c
} else {
pinfo = Create(addr, source, &nId);
pinfo->nTime = std::max(NodeSeconds{0s}, pinfo->nTime - time_penalty);
- nNew++;
}
int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman);
@@ -610,7 +618,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::c
pinfo->nRefCount++;
vvNew[nUBucket][nUBucketPos] = nId;
LogPrint(BCLog::ADDRMAN, "Added %s mapped to AS%i to new[%i][%i]\n",
- addr.ToString(), m_netgroupman.GetMappedAS(addr), nUBucket, nUBucketPos);
+ addr.ToStringAddrPort(), m_netgroupman.GetMappedAS(addr), nUBucket, nUBucketPos);
} else {
if (pinfo->nRefCount == 0) {
Delete(nId);
@@ -661,15 +669,15 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, NodeSecond
// Output the entry we'd be colliding with, for debugging purposes
auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
LogPrint(BCLog::ADDRMAN, "Collision with %s while attempting to move %s to tried table. Collisions=%d\n",
- colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "",
- addr.ToString(),
+ colliding_entry != mapInfo.end() ? colliding_entry->second.ToStringAddrPort() : "",
+ addr.ToStringAddrPort(),
m_tried_collisions.size());
return false;
} else {
// move nId to the tried tables
MakeTried(info, nId);
LogPrint(BCLog::ADDRMAN, "Moved %s mapped to AS%i to tried[%i][%i]\n",
- addr.ToString(), m_netgroupman.GetMappedAS(addr), tried_bucket, tried_bucket_pos);
+ addr.ToStringAddrPort(), m_netgroupman.GetMappedAS(addr), tried_bucket, tried_bucket_pos);
return true;
}
}
@@ -681,7 +689,7 @@ bool AddrManImpl::Add_(const std::vector<CAddress>& vAddr, const CNetAddr& sourc
added += AddSingle(*it, source, time_penalty) ? 1 : 0;
}
if (added > 0) {
- LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToString(), nTried, nNew);
+ LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToStringAddr(), nTried, nNew);
}
return added > 0;
}
@@ -738,7 +746,7 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool newOnly) const
const AddrInfo& info{it_found->second};
// With probability GetChance() * fChanceFactor, return the entry.
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
- LogPrint(BCLog::ADDRMAN, "Selected %s from tried\n", info.ToString());
+ LogPrint(BCLog::ADDRMAN, "Selected %s from tried\n", info.ToStringAddrPort());
return {info, info.m_last_try};
}
// Otherwise start over with a (likely) different bucket, and increased chance factor.
@@ -766,7 +774,7 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool newOnly) const
const AddrInfo& info{it_found->second};
// With probability GetChance() * fChanceFactor, return the entry.
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
- LogPrint(BCLog::ADDRMAN, "Selected %s from new\n", info.ToString());
+ LogPrint(BCLog::ADDRMAN, "Selected %s from new\n", info.ToStringAddrPort());
return {info, info.m_last_try};
}
// Otherwise start over with a (likely) different bucket, and increased chance factor.
@@ -883,7 +891,7 @@ void AddrManImpl::ResolveCollisions_()
// Give address at least 60 seconds to successfully connect
if (current_time - info_old.m_last_try > 60s) {
- LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
+ LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort());
// Replaces an existing address already in the tried table with the new address
Good_(info_new, false, current_time);
@@ -893,7 +901,7 @@ void AddrManImpl::ResolveCollisions_()
// If the collision hasn't resolved in some reasonable amount of time,
// just evict the old entry -- we must not be able to
// connect to it for some reason.
- LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
+ LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort());
Good_(info_new, false, current_time);
erase_collision = true;
}
@@ -962,6 +970,28 @@ std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& ad
}
}
+size_t AddrManImpl::Size_(std::optional<Network> net, std::optional<bool> in_new) const
+{
+ AssertLockHeld(cs);
+
+ if (!net.has_value()) {
+ if (in_new.has_value()) {
+ return *in_new ? nNew : nTried;
+ } else {
+ return vRandom.size();
+ }
+ }
+ if (auto it = m_network_counts.find(*net); it != m_network_counts.end()) {
+ auto net_count = it->second;
+ if (in_new.has_value()) {
+ return *in_new ? net_count.n_new : net_count.n_tried;
+ } else {
+ return net_count.n_new + net_count.n_tried;
+ }
+ }
+ return 0;
+}
+
void AddrManImpl::Check() const
{
AssertLockHeld(cs);
@@ -986,6 +1016,7 @@ int AddrManImpl::CheckAddrman() const
std::unordered_set<int> setTried;
std::unordered_map<int, int> mapNew;
+ std::unordered_map<Network, NewTriedCount> local_counts;
if (vRandom.size() != (size_t)(nTried + nNew))
return -7;
@@ -1000,12 +1031,14 @@ int AddrManImpl::CheckAddrman() const
if (info.nRefCount)
return -2;
setTried.insert(n);
+ local_counts[info.GetNetwork()].n_tried++;
} else {
if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
return -3;
if (!info.nRefCount)
return -4;
mapNew[n] = info.nRefCount;
+ local_counts[info.GetNetwork()].n_new++;
}
const auto it{mapAddr.find(info)};
if (it == mapAddr.end() || it->second != n) {
@@ -1065,13 +1098,27 @@ int AddrManImpl::CheckAddrman() const
if (nKey.IsNull())
return -16;
+ // It's possible that m_network_counts may have all-zero entries that local_counts
+ // doesn't have if addrs from a network were being added and then removed again in the past.
+ if (m_network_counts.size() < local_counts.size()) {
+ return -20;
+ }
+ for (const auto& [net, count] : m_network_counts) {
+ if (local_counts[net].n_new != count.n_new || local_counts[net].n_tried != count.n_tried) {
+ return -21;
+ }
+ }
+
return 0;
}
-size_t AddrManImpl::size() const
+size_t AddrManImpl::Size(std::optional<Network> net, std::optional<bool> in_new) const
{
- LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
- return vRandom.size();
+ LOCK(cs);
+ Check();
+ auto ret = Size_(net, in_new);
+ Check();
+ return ret;
}
bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
@@ -1112,7 +1159,7 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision()
{
LOCK(cs);
Check();
- const auto ret = SelectTriedCollision_();
+ auto ret = SelectTriedCollision_();
Check();
return ret;
}
@@ -1121,7 +1168,7 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool newOnly) const
{
LOCK(cs);
Check();
- const auto addrRet = Select_(newOnly);
+ auto addrRet = Select_(newOnly);
Check();
return addrRet;
}
@@ -1130,7 +1177,7 @@ std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct,
{
LOCK(cs);
Check();
- const auto addresses = GetAddr_(max_addresses, max_pct, network);
+ auto addresses = GetAddr_(max_addresses, max_pct, network);
Check();
return addresses;
}
@@ -1178,17 +1225,16 @@ void AddrMan::Unserialize(Stream& s_)
}
// explicit instantiation
-template void AddrMan::Serialize(CHashWriter& s) const;
-template void AddrMan::Serialize(CAutoFile& s) const;
+template void AddrMan::Serialize(HashedSourceWriter<CAutoFile>& s) const;
template void AddrMan::Serialize(CDataStream& s) const;
template void AddrMan::Unserialize(CAutoFile& s);
template void AddrMan::Unserialize(CHashVerifier<CAutoFile>& s);
template void AddrMan::Unserialize(CDataStream& s);
template void AddrMan::Unserialize(CHashVerifier<CDataStream>& s);
-size_t AddrMan::size() const
+size_t AddrMan::Size(std::optional<Network> net, std::optional<bool> in_new) const
{
- return m_impl->size();
+ return m_impl->Size(net, in_new);
}
bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
diff --git a/src/addrman.h b/src/addrman.h
index 5099c8c7a3..4985fc764c 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -1,5 +1,5 @@
// Copyright (c) 2012 Pieter Wuille
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -99,8 +99,14 @@ public:
template <typename Stream>
void Unserialize(Stream& s_);
- //! Return the number of (unique) addresses in all tables.
- size_t size() const;
+ /**
+ * Return size information about addrman.
+ *
+ * @param[in] net Select addresses only from specified network (nullopt = all)
+ * @param[in] in_new Select addresses only from one table (true = new, false = tried, nullopt = both)
+ * @return Number of unique addresses that match specified options.
+ */
+ size_t Size(std::optional<Network> net = std::nullopt, std::optional<bool> in_new = std::nullopt) const;
/**
* Attempt to add one or more addresses to addrman's new table.
diff --git a/src/addrman_impl.h b/src/addrman_impl.h
index 376e79f49f..94fe81aca9 100644
--- a/src/addrman_impl.h
+++ b/src/addrman_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -112,7 +112,7 @@ public:
template <typename Stream>
void Unserialize(Stream& s_) EXCLUSIVE_LOCKS_REQUIRED(!cs);
- size_t size() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
+ size_t Size(std::optional<Network> net, std::optional<bool> in_new) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
@@ -215,6 +215,14 @@ private:
/** Reference to the netgroup manager. netgroupman must be constructed before addrman and destructed after. */
const NetGroupManager& m_netgroupman;
+ struct NewTriedCount {
+ size_t n_new;
+ size_t n_tried;
+ };
+
+ /** Number of entries in addrman per network and new/tried table. */
+ std::unordered_map<Network, NewTriedCount> m_network_counts GUARDED_BY(cs);
+
//! Find an entry.
AddrInfo* Find(const CService& addr, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
@@ -257,6 +265,8 @@ private:
std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ size_t Size_(std::optional<Network> net, std::optional<bool> in_new) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+
//! Consistency check, taking into account m_consistency_check_ratio.
//! Will std::abort if an inconsistency is detected.
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs);
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index e614102de3..3776cfb6de 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index b7b3b3a285..c710fe9471 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -58,7 +58,7 @@ public:
explicit base_uint(const std::string& str);
- const base_uint operator~() const
+ base_uint operator~() const
{
base_uint ret;
for (int i = 0; i < WIDTH; i++)
@@ -66,7 +66,7 @@ public:
return ret;
}
- const base_uint operator-() const
+ base_uint operator-() const
{
base_uint ret;
for (int i = 0; i < WIDTH; i++)
@@ -171,7 +171,7 @@ public:
return *this;
}
- const base_uint operator++(int)
+ base_uint operator++(int)
{
// postfix operator
const base_uint ret = *this;
@@ -188,7 +188,7 @@ public:
return *this;
}
- const base_uint operator--(int)
+ base_uint operator--(int)
{
// postfix operator
const base_uint ret = *this;
@@ -199,16 +199,16 @@ public:
int CompareTo(const base_uint& b) const;
bool EqualTo(uint64_t b) const;
- friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; }
- friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; }
- friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; }
- friend inline const base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; }
- friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; }
- friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; }
- friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; }
- friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; }
- friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; }
- friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; }
+ friend inline base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; }
+ friend inline base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; }
+ friend inline base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; }
+ friend inline base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; }
+ friend inline base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; }
+ friend inline base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; }
+ friend inline base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; }
+ friend inline base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; }
+ friend inline base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; }
+ friend inline base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; }
friend inline bool operator==(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) == 0; }
friend inline bool operator!=(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) != 0; }
friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; }
diff --git a/src/banman.cpp b/src/banman.cpp
index 3cd646c148..ece949d997 100644
--- a/src/banman.cpp
+++ b/src/banman.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/banman.h b/src/banman.h
index 77b043f081..241f01dd2e 100644
--- a/src/banman.h
+++ b/src/banman.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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
diff --git a/src/base58.cpp b/src/base58.cpp
index 11c1ce7397..cf5d62f164 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2021 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/base58.h b/src/base58.h
index d2a8d5e3bc..2f4d0b74b1 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bech32.cpp b/src/bech32.cpp
index 8e0025b8f4..ba3c419d8b 100644
--- a/src/bech32.cpp
+++ b/src/bech32.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2017, 2021 Pieter Wuille
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp
index f14d1f89b6..d6b52eb587 100644
--- a/src/bench/addrman.cpp
+++ b/src/bench/addrman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -133,7 +133,7 @@ static void AddrManAddThenGood(benchmark::Bench& bench)
});
}
-BENCHMARK(AddrManAdd);
-BENCHMARK(AddrManSelect);
-BENCHMARK(AddrManGetAddr);
-BENCHMARK(AddrManAddThenGood);
+BENCHMARK(AddrManAdd, benchmark::PriorityLevel::HIGH);
+BENCHMARK(AddrManSelect, benchmark::PriorityLevel::HIGH);
+BENCHMARK(AddrManGetAddr, benchmark::PriorityLevel::HIGH);
+BENCHMARK(AddrManAddThenGood, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 6f6b4e3bfa..78748bc5bd 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2020 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -50,6 +50,6 @@ static void Base58Decode(benchmark::Bench& bench)
}
-BENCHMARK(Base58Encode);
-BENCHMARK(Base58CheckEncode);
-BENCHMARK(Base58Decode);
+BENCHMARK(Base58Encode, benchmark::PriorityLevel::HIGH);
+BENCHMARK(Base58CheckEncode, benchmark::PriorityLevel::HIGH);
+BENCHMARK(Base58Decode, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/bech32.cpp b/src/bench/bech32.cpp
index 0f89a8e2b5..9922653766 100644
--- a/src/bench/bech32.cpp
+++ b/src/bench/bech32.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -32,5 +32,5 @@ static void Bech32Decode(benchmark::Bench& bench)
}
-BENCHMARK(Bech32Encode);
-BENCHMARK(Bech32Decode);
+BENCHMARK(Bech32Encode, benchmark::PriorityLevel::HIGH);
+BENCHMARK(Bech32Decode, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 26975bb59d..4374a63250 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,6 +6,7 @@
#include <fs.h>
#include <test/util/setup_common.h>
+#include <util/string.h>
#include <chrono>
#include <fstream>
@@ -41,42 +42,73 @@ void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& bench
} // namespace
-benchmark::BenchRunner::BenchmarkMap& benchmark::BenchRunner::benchmarks()
+namespace benchmark {
+
+// map a label to one or multiple priority levels
+std::map<std::string, uint8_t> map_label_priority = {
+ {"high", PriorityLevel::HIGH},
+ {"low", PriorityLevel::LOW},
+ {"all", 0xff}
+};
+
+std::string ListPriorities()
{
- static std::map<std::string, BenchFunction> benchmarks_map;
+ using item_t = std::pair<std::string, uint8_t>;
+ auto sort_by_priority = [](item_t a, item_t b){ return a.second < b.second; };
+ std::set<item_t, decltype(sort_by_priority)> sorted_priorities(map_label_priority.begin(), map_label_priority.end(), sort_by_priority);
+ return Join(sorted_priorities, ',', [](const auto& entry){ return entry.first; });
+}
+
+uint8_t StringToPriority(const std::string& str)
+{
+ auto it = map_label_priority.find(str);
+ if (it == map_label_priority.end()) throw std::runtime_error(strprintf("Unknown priority level %s", str));
+ return it->second;
+}
+
+BenchRunner::BenchmarkMap& BenchRunner::benchmarks()
+{
+ static BenchmarkMap benchmarks_map;
return benchmarks_map;
}
-benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
+BenchRunner::BenchRunner(std::string name, BenchFunction func, PriorityLevel level)
{
- benchmarks().insert(std::make_pair(name, func));
+ benchmarks().insert(std::make_pair(name, std::make_pair(func, level)));
}
-void benchmark::BenchRunner::RunAll(const Args& args)
+void BenchRunner::RunAll(const Args& args)
{
std::regex reFilter(args.regex_filter);
std::smatch baseMatch;
if (args.sanity_check) {
- std::cout << "Running with --sanity-check option, benchmark results will be useless." << std::endl;
+ std::cout << "Running with -sanity-check option, output is being suppressed as benchmark results will be useless." << std::endl;
}
std::vector<ankerl::nanobench::Result> benchmarkResults;
- for (const auto& p : benchmarks()) {
- if (!std::regex_match(p.first, baseMatch, reFilter)) {
+ for (const auto& [name, bench_func] : benchmarks()) {
+ const auto& [func, priority_level] = bench_func;
+
+ if (!(priority_level & args.priority)) {
+ continue;
+ }
+
+ if (!std::regex_match(name, baseMatch, reFilter)) {
continue;
}
if (args.is_list_only) {
- std::cout << p.first << std::endl;
+ std::cout << name << std::endl;
continue;
}
Bench bench;
if (args.sanity_check) {
bench.epochs(1).epochIterations(1);
+ bench.output(nullptr);
}
- bench.name(p.first);
+ bench.name(name);
if (args.min_time > 0ms) {
// convert to nanos before dividing to reduce rounding errors
std::chrono::nanoseconds min_time_ns = args.min_time;
@@ -84,11 +116,11 @@ void benchmark::BenchRunner::RunAll(const Args& args)
}
if (args.asymptote.empty()) {
- p.second(bench);
+ func(bench);
} else {
for (auto n : args.asymptote) {
bench.complexityN(n);
- p.second(bench);
+ func(bench);
}
std::cout << bench.complexityBigO() << std::endl;
}
@@ -103,3 +135,5 @@ void benchmark::BenchRunner::RunAll(const Args& args)
"{{/result}}");
GenerateTemplateResults(benchmarkResults, args.output_json, ankerl::nanobench::templates::json());
}
+
+} // namespace benchmark
diff --git a/src/bench/bench.h b/src/bench/bench.h
index 17535e4e81..22c63a797b 100644
--- a/src/bench/bench.h
+++ b/src/bench/bench.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -41,6 +41,16 @@ using ankerl::nanobench::Bench;
typedef std::function<void(Bench&)> BenchFunction;
+enum PriorityLevel : uint8_t
+{
+ LOW = 1 << 0,
+ HIGH = 1 << 2,
+};
+
+// List priority labels, comma-separated and sorted by increasing priority
+std::string ListPriorities();
+uint8_t StringToPriority(const std::string& str);
+
struct Args {
bool is_list_only;
bool sanity_check;
@@ -49,22 +59,24 @@ struct Args {
fs::path output_csv;
fs::path output_json;
std::string regex_filter;
+ uint8_t priority;
};
class BenchRunner
{
- typedef std::map<std::string, BenchFunction> BenchmarkMap;
+ // maps from "name" -> (function, priority_level)
+ typedef std::map<std::string, std::pair<BenchFunction, PriorityLevel>> BenchmarkMap;
static BenchmarkMap& benchmarks();
public:
- BenchRunner(std::string name, BenchFunction func);
+ BenchRunner(std::string name, BenchFunction func, PriorityLevel level);
static void RunAll(const Args& args);
};
} // namespace benchmark
-// BENCHMARK(foo) expands to: benchmark::BenchRunner bench_11foo("foo", foo);
-#define BENCHMARK(n) \
- benchmark::BenchRunner PASTE2(bench_, PASTE2(__LINE__, n))(STRINGIZE(n), n);
+// BENCHMARK(foo) expands to: benchmark::BenchRunner bench_11foo("foo", foo, priority_level);
+#define BENCHMARK(n, priority_level) \
+ benchmark::BenchRunner PASTE2(bench_, PASTE2(__LINE__, n))(STRINGIZE(n), n, priority_level);
#endif // BITCOIN_BENCH_BENCH_H
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 1bb4d34db9..06e32f684f 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,6 +18,8 @@
static const char* DEFAULT_BENCH_FILTER = ".*";
static constexpr int64_t DEFAULT_MIN_TIME_MS{10};
+/** Priority level default value, run "all" priority levels */
+static const std::string DEFAULT_PRIORITY{"all"};
static void SetupBenchArgs(ArgsManager& argsman)
{
@@ -29,7 +31,9 @@ static void SetupBenchArgs(ArgsManager& argsman)
argsman.AddArg("-min-time=<milliseconds>", strprintf("Minimum runtime per benchmark, in milliseconds (default: %d)", DEFAULT_MIN_TIME_MS), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
argsman.AddArg("-output-csv=<output.csv>", "Generate CSV file with the most important benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-output-json=<output.json>", "Generate JSON file with all benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-sanity-check", "Run benchmarks for only one iteration", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-sanity-check", "Run benchmarks for only one iteration with no output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-priority-level=<l1,l2,l3>", strprintf("Run benchmarks of one or multiple priority level(s) (%s), default: '%s'",
+ benchmark::ListPriorities(), DEFAULT_PRIORITY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
}
// parses a comma separated list like "10,20,30,50"
@@ -45,6 +49,14 @@ static std::vector<double> parseAsymptote(const std::string& str) {
return numbers;
}
+static uint8_t parsePriorityLevel(const std::string& str) {
+ uint8_t levels{0};
+ for (const auto& level: SplitString(str, ',')) {
+ levels |= benchmark::StringToPriority(level);
+ }
+ return levels;
+}
+
int main(int argc, char** argv)
{
ArgsManager argsman;
@@ -106,16 +118,22 @@ int main(int argc, char** argv)
return EXIT_SUCCESS;
}
- benchmark::Args args;
- args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", ""));
- args.is_list_only = argsman.GetBoolArg("-list", false);
- args.min_time = std::chrono::milliseconds(argsman.GetIntArg("-min-time", DEFAULT_MIN_TIME_MS));
- args.output_csv = argsman.GetPathArg("-output-csv");
- args.output_json = argsman.GetPathArg("-output-json");
- args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER);
- args.sanity_check = argsman.GetBoolArg("-sanity-check", false);
+ try {
+ benchmark::Args args;
+ args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", ""));
+ args.is_list_only = argsman.GetBoolArg("-list", false);
+ args.min_time = std::chrono::milliseconds(argsman.GetIntArg("-min-time", DEFAULT_MIN_TIME_MS));
+ args.output_csv = argsman.GetPathArg("-output-csv");
+ args.output_json = argsman.GetPathArg("-output-json");
+ args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER);
+ args.sanity_check = argsman.GetBoolArg("-sanity-check", false);
+ args.priority = parsePriorityLevel(argsman.GetArg("-priority-level", DEFAULT_PRIORITY));
- benchmark::BenchRunner::RunAll(args);
+ benchmark::BenchRunner::RunAll(args);
- return EXIT_SUCCESS;
+ return EXIT_SUCCESS;
+ } catch (const std::exception& e) {
+ tfm::format(std::cerr, "Error: %s\n", e.what());
+ return EXIT_FAILURE;
+ }
}
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index 4ed5397330..8dd4117a3e 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -1,14 +1,14 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
+#include <node/miner.h>
#include <test/util/mining.h>
#include <test/util/script.h>
#include <test/util/setup_common.h>
-#include <test/util/wallet.h>
#include <txmempool.h>
#include <validation.h>
@@ -46,5 +46,18 @@ static void AssembleBlock(benchmark::Bench& bench)
PrepareBlock(test_setup->m_node, P2WSH_OP_TRUE);
});
}
+static void BlockAssemblerAddPackageTxns(benchmark::Bench& bench)
+{
+ FastRandomContext det_rand{true};
+ auto testing_setup{MakeNoLogFileContext<TestChain100Setup>()};
+ testing_setup->PopulateMempool(det_rand, /*num_transactions=*/1000, /*submit=*/true);
+ node::BlockAssembler::Options assembler_options;
+ assembler_options.test_block_validity = false;
+
+ bench.run([&] {
+ PrepareBlock(testing_setup->m_node, P2WSH_OP_TRUE, assembler_options);
+ });
+}
-BENCHMARK(AssembleBlock);
+BENCHMARK(AssembleBlock, benchmark::PriorityLevel::HIGH);
+BENCHMARK(BlockAssemblerAddPackageTxns, benchmark::PriorityLevel::LOW);
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
index 22dfb7aa5b..4a3ec67c2b 100644
--- a/src/bench/ccoins_caching.cpp
+++ b/src/bench/ccoins_caching.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,7 +18,6 @@
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
static void CCoinsCaching(benchmark::Bench& bench)
{
- const ECCVerifyHandle verify_handle;
ECC_Start();
FillableSigningProvider keystore;
@@ -51,4 +50,4 @@ static void CCoinsCaching(benchmark::Bench& bench)
ECC_Stop();
}
-BENCHMARK(CCoinsCaching);
+BENCHMARK(CCoinsCaching, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp
index a6f4eec4ca..115cd064bd 100644
--- a/src/bench/chacha20.cpp
+++ b/src/bench/chacha20.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,9 +14,9 @@ static const uint64_t BUFFER_SIZE_LARGE = 1024*1024;
static void CHACHA20(benchmark::Bench& bench, size_t buffersize)
{
std::vector<uint8_t> key(32,0);
- ChaCha20 ctx(key.data(), key.size());
+ ChaCha20 ctx(key.data());
ctx.SetIV(0);
- ctx.Seek(0);
+ ctx.Seek64(0);
std::vector<uint8_t> in(buffersize,0);
std::vector<uint8_t> out(buffersize,0);
bench.batch(in.size()).unit("byte").run([&] {
@@ -39,6 +39,6 @@ static void CHACHA20_1MB(benchmark::Bench& bench)
CHACHA20(bench, BUFFER_SIZE_LARGE);
}
-BENCHMARK(CHACHA20_64BYTES);
-BENCHMARK(CHACHA20_256BYTES);
-BENCHMARK(CHACHA20_1MB);
+BENCHMARK(CHACHA20_64BYTES, benchmark::PriorityLevel::HIGH);
+BENCHMARK(CHACHA20_256BYTES, benchmark::PriorityLevel::HIGH);
+BENCHMARK(CHACHA20_1MB, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/chacha_poly_aead.cpp b/src/bench/chacha_poly_aead.cpp
index e994279a4d..db88841c32 100644
--- a/src/bench/chacha_poly_aead.cpp
+++ b/src/bench/chacha_poly_aead.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -115,12 +115,12 @@ static void HASH_1MB(benchmark::Bench& bench)
HASH(bench, BUFFER_SIZE_LARGE);
}
-BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT);
-BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT);
-BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT);
-BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT);
-BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT);
-BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT);
-BENCHMARK(HASH_64BYTES);
-BENCHMARK(HASH_256BYTES);
-BENCHMARK(HASH_1MB);
+BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT, benchmark::PriorityLevel::HIGH);
+BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT, benchmark::PriorityLevel::HIGH);
+BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT, benchmark::PriorityLevel::HIGH);
+BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT, benchmark::PriorityLevel::HIGH);
+BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT, benchmark::PriorityLevel::HIGH);
+BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT, benchmark::PriorityLevel::HIGH);
+BENCHMARK(HASH_64BYTES, benchmark::PriorityLevel::HIGH);
+BENCHMARK(HASH_256BYTES, benchmark::PriorityLevel::HIGH);
+BENCHMARK(HASH_1MB, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index 53aa470042..ee76f7b767 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2020 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -50,5 +50,5 @@ static void DeserializeAndCheckBlockTest(benchmark::Bench& bench)
});
}
-BENCHMARK(DeserializeBlockTest);
-BENCHMARK(DeserializeAndCheckBlockTest);
+BENCHMARK(DeserializeBlockTest, benchmark::PriorityLevel::HIGH);
+BENCHMARK(DeserializeAndCheckBlockTest, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index 602081fb9b..dfd7275f46 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -25,7 +25,6 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
// We shouldn't ever be running with the checkqueue on a single core machine.
if (GetNumCores() <= 1) return;
- const ECCVerifyHandle verify_handle;
ECC_Start();
struct PrevectorJob {
@@ -70,4 +69,4 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
queue.StopWorkerThreads();
ECC_Stop();
}
-BENCHMARK(CCheckQueueSpeedPrevectorJob);
+BENCHMARK(CCheckQueueSpeedPrevectorJob, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 6ada28115e..265d4bf655 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -45,7 +45,7 @@ static void CoinSelection(benchmark::Bench& bench)
{
NodeContext node;
auto chain = interfaces::MakeChain(node);
- CWallet wallet(chain.get(), "", gArgs, CreateDummyWalletDatabase());
+ CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
std::vector<std::unique_ptr<CWalletTx>> wtxs;
LOCK(wallet.cs_wallet);
@@ -75,8 +75,9 @@ static void CoinSelection(benchmark::Bench& bench)
/*tx_noinputs_size=*/ 0,
/*avoid_partial=*/ false,
};
+ auto group = wallet::GroupOutputs(wallet, available_coins, coin_selection_params, {{filter_standard}})[filter_standard];
bench.run([&] {
- auto result = AttemptSelection(wallet, 1003 * COIN, filter_standard, available_coins, coin_selection_params, /*allow_mixed_output_types=*/true);
+ auto result = AttemptSelection(1003 * COIN, group, coin_selection_params, /*allow_mixed_output_types=*/true);
assert(result);
assert(result->GetSelectedValue() == 1003 * COIN);
assert(result->GetInputSet().size() == 2);
@@ -91,7 +92,7 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup>
tx.vout[nInput].nValue = nValue;
COutput output(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 0, /*input_bytes=*/ -1, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ true, /*fees=*/ 0);
set.emplace_back();
- set.back().Insert(output, /*ancestors=*/ 0, /*descendants=*/ 0, /*positive_only=*/ false);
+ set.back().Insert(std::make_shared<COutput>(output), /*ancestors=*/ 0, /*descendants=*/ 0);
}
// Copied from src/wallet/test/coinselector_tests.cpp
static CAmount make_hard_case(int utxos, std::vector<OutputGroup>& utxo_pool)
@@ -99,9 +100,9 @@ static CAmount make_hard_case(int utxos, std::vector<OutputGroup>& utxo_pool)
utxo_pool.clear();
CAmount target = 0;
for (int i = 0; i < utxos; ++i) {
- target += (CAmount)1 << (utxos+i);
- add_coin((CAmount)1 << (utxos+i), 2*i, utxo_pool);
- add_coin(((CAmount)1 << (utxos+i)) + ((CAmount)1 << (utxos-1-i)), 2*i + 1, utxo_pool);
+ target += CAmount{1} << (utxos+i);
+ add_coin(CAmount{1} << (utxos+i), 2*i, utxo_pool);
+ add_coin((CAmount{1} << (utxos+i)) + (CAmount{1} << (utxos-1-i)), 2*i + 1, utxo_pool);
}
return target;
}
@@ -121,5 +122,5 @@ static void BnBExhaustion(benchmark::Bench& bench)
});
}
-BENCHMARK(CoinSelection);
-BENCHMARK(BnBExhaustion);
+BENCHMARK(CoinSelection, benchmark::PriorityLevel::HIGH);
+BENCHMARK(BnBExhaustion, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index d17ec503e7..cf8d807d7b 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,7 +18,7 @@
/* Number of bytes to hash per iteration */
static const uint64_t BUFFER_SIZE = 1000*1000;
-static void RIPEMD160(benchmark::Bench& bench)
+static void BenchRIPEMD160(benchmark::Bench& bench)
{
uint8_t hash[CRIPEMD160::OUTPUT_SIZE];
std::vector<uint8_t> in(BUFFER_SIZE,0);
@@ -150,19 +150,19 @@ static void MuHashPrecompute(benchmark::Bench& bench)
});
}
-BENCHMARK(RIPEMD160);
-BENCHMARK(SHA1);
-BENCHMARK(SHA256);
-BENCHMARK(SHA512);
-BENCHMARK(SHA3_256_1M);
-
-BENCHMARK(SHA256_32b);
-BENCHMARK(SipHash_32b);
-BENCHMARK(SHA256D64_1024);
-BENCHMARK(FastRandom_32bit);
-BENCHMARK(FastRandom_1bit);
-
-BENCHMARK(MuHash);
-BENCHMARK(MuHashMul);
-BENCHMARK(MuHashDiv);
-BENCHMARK(MuHashPrecompute);
+BENCHMARK(BenchRIPEMD160, benchmark::PriorityLevel::HIGH);
+BENCHMARK(SHA1, benchmark::PriorityLevel::HIGH);
+BENCHMARK(SHA256, benchmark::PriorityLevel::HIGH);
+BENCHMARK(SHA512, benchmark::PriorityLevel::HIGH);
+BENCHMARK(SHA3_256_1M, benchmark::PriorityLevel::HIGH);
+
+BENCHMARK(SHA256_32b, benchmark::PriorityLevel::HIGH);
+BENCHMARK(SipHash_32b, benchmark::PriorityLevel::HIGH);
+BENCHMARK(SHA256D64_1024, benchmark::PriorityLevel::HIGH);
+BENCHMARK(FastRandom_32bit, benchmark::PriorityLevel::HIGH);
+BENCHMARK(FastRandom_1bit, benchmark::PriorityLevel::HIGH);
+
+BENCHMARK(MuHash, benchmark::PriorityLevel::HIGH);
+BENCHMARK(MuHashMul, benchmark::PriorityLevel::HIGH);
+BENCHMARK(MuHashDiv, benchmark::PriorityLevel::HIGH);
+BENCHMARK(MuHashPrecompute, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/descriptors.cpp b/src/bench/descriptors.cpp
index 5c868a8573..5d28d26909 100644
--- a/src/bench/descriptors.cpp
+++ b/src/bench/descriptors.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
#include <key.h>
+#include <pubkey.h>
#include <script/descriptor.h>
#include <script/standard.h>
@@ -12,6 +13,8 @@
static void ExpandDescriptor(benchmark::Bench& bench)
{
+ ECC_Start();
+
const auto desc_str = "sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))";
const std::pair<int64_t, int64_t> range = {0, 1000};
FlatSigningProvider provider;
@@ -25,6 +28,8 @@ static void ExpandDescriptor(benchmark::Bench& bench)
assert(success);
}
});
+
+ ECC_Stop();
}
-BENCHMARK(ExpandDescriptor);
+BENCHMARK(ExpandDescriptor, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp
index 02a2e689b1..b3799ad1b7 100644
--- a/src/bench/duplicate_inputs.cpp
+++ b/src/bench/duplicate_inputs.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -62,4 +62,4 @@ static void DuplicateInputs(benchmark::Bench& bench)
});
}
-BENCHMARK(DuplicateInputs);
+BENCHMARK(DuplicateInputs, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/examples.cpp b/src/bench/examples.cpp
index 72a9922e94..671902ef2f 100644
--- a/src/bench/examples.cpp
+++ b/src/bench/examples.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,4 +18,4 @@ static void Trig(benchmark::Bench& bench)
});
}
-BENCHMARK(Trig);
+BENCHMARK(Trig, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/gcs_filter.cpp b/src/bench/gcs_filter.cpp
index 80babb213b..0af4ee98fe 100644
--- a/src/bench/gcs_filter.cpp
+++ b/src/bench/gcs_filter.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
#include <blockfilter.h>
-static const GCSFilter::ElementSet GenerateGCSTestElements()
+static GCSFilter::ElementSet GenerateGCSTestElements()
{
GCSFilter::ElementSet elements;
@@ -81,8 +81,8 @@ static void GCSFilterMatch(benchmark::Bench& bench)
filter.Match(GCSFilter::Element());
});
}
-BENCHMARK(GCSBlockFilterGetHash);
-BENCHMARK(GCSFilterConstruct);
-BENCHMARK(GCSFilterDecode);
-BENCHMARK(GCSFilterDecodeSkipCheck);
-BENCHMARK(GCSFilterMatch);
+BENCHMARK(GCSBlockFilterGetHash, benchmark::PriorityLevel::HIGH);
+BENCHMARK(GCSFilterConstruct, benchmark::PriorityLevel::HIGH);
+BENCHMARK(GCSFilterDecode, benchmark::PriorityLevel::HIGH);
+BENCHMARK(GCSFilterDecodeSkipCheck, benchmark::PriorityLevel::HIGH);
+BENCHMARK(GCSFilterMatch, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/hashpadding.cpp b/src/bench/hashpadding.cpp
index 753c8c2881..e9d2c25fe3 100644
--- a/src/bench/hashpadding.cpp
+++ b/src/bench/hashpadding.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -26,7 +26,7 @@ static void PrePadded(benchmark::Bench& bench)
});
}
-BENCHMARK(PrePadded);
+BENCHMARK(PrePadded, benchmark::PriorityLevel::HIGH);
static void RegularPadded(benchmark::Bench& bench)
{
@@ -44,4 +44,4 @@ static void RegularPadded(benchmark::Bench& bench)
});
}
-BENCHMARK(RegularPadded);
+BENCHMARK(RegularPadded, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/load_external.cpp b/src/bench/load_external.cpp
new file mode 100644
index 0000000000..0fd842c7c3
--- /dev/null
+++ b/src/bench/load_external.cpp
@@ -0,0 +1,63 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or https://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+#include <bench/data.h>
+#include <chainparams.h>
+#include <test/util/setup_common.h>
+#include <validation.h>
+
+/**
+ * The LoadExternalBlockFile() function is used during -reindex and -loadblock.
+ *
+ * Create a test file that's similar to a datadir/blocks/blk?????.dat file,
+ * It contains around 134 copies of the same block (typical size of real block files).
+ * For each block in the file, LoadExternalBlockFile() won't find its parent,
+ * and so will skip the block. (In the real system, it will re-read the block
+ * from disk later when it encounters its parent.)
+ *
+ * This benchmark measures the performance of deserializing the block (or just
+ * its header, beginning with PR 16981).
+ */
+static void LoadExternalBlockFile(benchmark::Bench& bench)
+{
+ const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN)};
+
+ // Create a single block as in the blocks files (magic bytes, block size,
+ // block data) as a stream object.
+ const fs::path blkfile{testing_setup.get()->m_path_root / "blk.dat"};
+ DataStream ss{};
+ auto params{testing_setup->m_node.chainman->GetParams()};
+ ss << params.MessageStart();
+ ss << static_cast<uint32_t>(benchmark::data::block413567.size());
+ // We can't use the streaming serialization (ss << benchmark::data::block413567)
+ // because that first writes a compact size.
+ ss.write(MakeByteSpan(benchmark::data::block413567));
+
+ // Create the test file.
+ {
+ // "wb+" is "binary, O_RDWR | O_CREAT | O_TRUNC".
+ FILE* file{fsbridge::fopen(blkfile, "wb+")};
+ // Make the test block file about 128 MB in length.
+ for (size_t i = 0; i < node::MAX_BLOCKFILE_SIZE / ss.size(); ++i) {
+ if (fwrite(ss.data(), 1, ss.size(), file) != ss.size()) {
+ throw std::runtime_error("write to test file failed\n");
+ }
+ }
+ fclose(file);
+ }
+
+ Chainstate& chainstate{testing_setup->m_node.chainman->ActiveChainstate()};
+ std::multimap<uint256, FlatFilePos> blocks_with_unknown_parent;
+ FlatFilePos pos;
+ bench.run([&] {
+ // "rb" is "binary, O_RDONLY", positioned to the start of the file.
+ // The file will be closed by LoadExternalBlockFile().
+ FILE* file{fsbridge::fopen(blkfile, "rb")};
+ chainstate.LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent);
+ });
+ fs::remove(blkfile);
+}
+
+BENCHMARK(LoadExternalBlockFile, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp
index b6d8824aba..161f9af621 100644
--- a/src/bench/lockedpool.cpp
+++ b/src/bench/lockedpool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2020 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -39,4 +39,4 @@ static void BenchLockedPool(benchmark::Bench& bench)
addr.clear();
}
-BENCHMARK(BenchLockedPool);
+BENCHMARK(BenchLockedPool, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/logging.cpp b/src/bench/logging.cpp
index d28777df9e..c38552f0b8 100644
--- a/src/bench/logging.cpp
+++ b/src/bench/logging.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -41,8 +41,8 @@ static void LoggingNoFile(benchmark::Bench& bench)
});
}
-BENCHMARK(LoggingYoThreadNames);
-BENCHMARK(LoggingNoThreadNames);
-BENCHMARK(LoggingYoCategory);
-BENCHMARK(LoggingNoCategory);
-BENCHMARK(LoggingNoFile);
+BENCHMARK(LoggingYoThreadNames, benchmark::PriorityLevel::HIGH);
+BENCHMARK(LoggingNoThreadNames, benchmark::PriorityLevel::HIGH);
+BENCHMARK(LoggingYoCategory, benchmark::PriorityLevel::HIGH);
+BENCHMARK(LoggingNoCategory, benchmark::PriorityLevel::HIGH);
+BENCHMARK(LoggingNoFile, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
index 60d991fab9..735dc92dfb 100644
--- a/src/bench/mempool_eviction.cpp
+++ b/src/bench/mempool_eviction.cpp
@@ -1,8 +1,9 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
+#include <kernel/mempool_entry.h>
#include <policy/policy.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
@@ -132,4 +133,4 @@ static void MempoolEviction(benchmark::Bench& bench)
});
}
-BENCHMARK(MempoolEviction);
+BENCHMARK(MempoolEviction, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp
index 725a6f8f5b..80c959cdfb 100644
--- a/src/bench/mempool_stress.cpp
+++ b/src/bench/mempool_stress.cpp
@@ -1,8 +1,9 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
+#include <kernel/mempool_entry.h>
#include <policy/policy.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
@@ -114,5 +115,5 @@ static void MempoolCheck(benchmark::Bench& bench)
});
}
-BENCHMARK(ComplexMemPool);
-BENCHMARK(MempoolCheck);
+BENCHMARK(ComplexMemPool, benchmark::PriorityLevel::HIGH);
+BENCHMARK(MempoolCheck, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/merkle_root.cpp b/src/bench/merkle_root.cpp
index ba6629b9f0..55409335bd 100644
--- a/src/bench/merkle_root.cpp
+++ b/src/bench/merkle_root.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2020 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -23,4 +23,4 @@ static void MerkleRoot(benchmark::Bench& bench)
});
}
-BENCHMARK(MerkleRoot);
+BENCHMARK(MerkleRoot, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/nanobench.h b/src/bench/nanobench.h
index 916a7d61ef..8b3dc6c71c 100644
--- a/src/bench/nanobench.h
+++ b/src/bench/nanobench.h
@@ -7,7 +7,7 @@
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
-// Copyright (c) 2019-2021 Martin Ankerl <martin.ankerl@gmail.com>
+// Copyright (c) 2019-2023 Martin Leitner-Ankerl <martin.ankerl@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -31,19 +31,20 @@
#define ANKERL_NANOBENCH_H_INCLUDED
// see https://semver.org/
-#define ANKERL_NANOBENCH_VERSION_MAJOR 4 // incompatible API changes
-#define ANKERL_NANOBENCH_VERSION_MINOR 3 // backwards-compatible changes
-#define ANKERL_NANOBENCH_VERSION_PATCH 6 // backwards-compatible bug fixes
+#define ANKERL_NANOBENCH_VERSION_MAJOR 4 // incompatible API changes
+#define ANKERL_NANOBENCH_VERSION_MINOR 3 // backwards-compatible changes
+#define ANKERL_NANOBENCH_VERSION_PATCH 10 // backwards-compatible bug fixes
///////////////////////////////////////////////////////////////////////////////////////////////////
// public facing api - as minimal as possible
///////////////////////////////////////////////////////////////////////////////////////////////////
-#include <chrono> // high_resolution_clock
-#include <cstring> // memcpy
-#include <iosfwd> // for std::ostream* custom output target in Config
-#include <string> // all names
-#include <vector> // holds all results
+#include <chrono> // high_resolution_clock
+#include <cstring> // memcpy
+#include <iosfwd> // for std::ostream* custom output target in Config
+#include <string> // all names
+#include <unordered_map> // holds context information of results
+#include <vector> // holds all results
#define ANKERL_NANOBENCH(x) ANKERL_NANOBENCH_PRIVATE_##x()
@@ -91,7 +92,7 @@
#define ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS() 0
#if defined(__linux__) && !defined(ANKERL_NANOBENCH_DISABLE_PERF_COUNTERS)
# include <linux/version.h>
-# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
// PERF_COUNT_HW_REF_CPU_CYCLES only available since kernel 3.3
// PERF_FLAG_FD_CLOEXEC since kernel 3.14
# undef ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS
@@ -144,43 +145,45 @@ class BigO;
* * `{{#result}}` Marks the begin of the result layer. Whatever comes after this will be instantiated as often as
* a benchmark result is available. Within it, you can use these tags:
*
- * * `{{title}}` See Bench::title().
+ * * `{{title}}` See Bench::title.
*
- * * `{{name}}` Benchmark name, usually directly provided with Bench::run(), but can also be set with Bench::name().
+ * * `{{name}}` Benchmark name, usually directly provided with Bench::run, but can also be set with Bench::name.
*
- * * `{{unit}}` Unit, e.g. `byte`. Defaults to `op`, see Bench::title().
+ * * `{{unit}}` Unit, e.g. `byte`. Defaults to `op`, see Bench::unit.
*
- * * `{{batch}}` Batch size, see Bench::batch().
+ * * `{{batch}}` Batch size, see Bench::batch.
*
- * * `{{complexityN}}` Value used for asymptotic complexity calculation. See Bench::complexityN().
+ * * `{{complexityN}}` Value used for asymptotic complexity calculation. See Bench::complexityN.
*
- * * `{{epochs}}` Number of epochs, see Bench::epochs().
+ * * `{{epochs}}` Number of epochs, see Bench::epochs.
*
* * `{{clockResolution}}` Accuracy of the clock, i.e. what's the smallest time possible to measure with the clock.
* For modern systems, this can be around 20 ns. This value is automatically determined by nanobench at the first
* benchmark that is run, and used as a static variable throughout the application's runtime.
*
- * * `{{clockResolutionMultiple}}` Configuration multiplier for `clockResolution`. See Bench::clockResolutionMultiple().
+ * * `{{clockResolutionMultiple}}` Configuration multiplier for `clockResolution`. See Bench::clockResolutionMultiple.
* This is the target runtime for each measurement (epoch). That means the more accurate your clock is, the faster
* will be the benchmark. Basing the measurement's runtime on the clock resolution is the main reason why nanobench is so fast.
*
* * `{{maxEpochTime}}` Configuration for a maximum time each measurement (epoch) is allowed to take. Note that at least
- * a single iteration will be performed, even when that takes longer than maxEpochTime. See Bench::maxEpochTime().
+ * a single iteration will be performed, even when that takes longer than maxEpochTime. See Bench::maxEpochTime.
*
- * * `{{minEpochTime}}` Minimum epoch time, usually not set. See Bench::minEpochTime().
+ * * `{{minEpochTime}}` Minimum epoch time, defaults to 1ms. See Bench::minEpochTime.
*
- * * `{{minEpochIterations}}` See Bench::minEpochIterations().
+ * * `{{minEpochIterations}}` See Bench::minEpochIterations.
*
- * * `{{epochIterations}}` See Bench::epochIterations().
+ * * `{{epochIterations}}` See Bench::epochIterations.
*
- * * `{{warmup}}` Number of iterations used before measuring starts. See Bench::warmup().
+ * * `{{warmup}}` Number of iterations used before measuring starts. See Bench::warmup.
*
- * * `{{relative}}` True or false, depending on the setting you have used. See Bench::relative().
+ * * `{{relative}}` True or false, depending on the setting you have used. See Bench::relative.
+ *
+ * * `{{context(variableName)}}` See Bench::context.
*
* Apart from these tags, it is also possible to use some mathematical operations on the measurement data. The operations
* are of the form `{{command(name)}}`. Currently `name` can be one of `elapsed`, `iterations`. If performance counters
* are available (currently only on current Linux systems), you also have `pagefaults`, `cpucycles`,
- * `contextswitches`, `instructions`, `branchinstructions`, and `branchmisses`. All the measuers (except `iterations`) are
+ * `contextswitches`, `instructions`, `branchinstructions`, and `branchmisses`. All the measures (except `iterations`) are
* provided for a single iteration (so `elapsed` is the time a single iteration took). The following tags are available:
*
* * `{{median(<name>)}}` Calculate median of a measurement data set, e.g. `{{median(elapsed)}}`.
@@ -201,7 +204,7 @@ class BigO;
* This measurement is a bit hard to interpret, but it is very robust against outliers. E.g. a value of 5% means that half of the
* measurements deviate less than 5% from the median, and the other deviate more than 5% from the median.
*
- * * `{{sum(<name>)}}` Sums of all the measurements. E.g. `{{sum(iterations)}}` will give you the total number of iterations
+ * * `{{sum(<name>)}}` Sum of all the measurements. E.g. `{{sum(iterations)}}` will give you the total number of iterations
* measured in this benchmark.
*
* * `{{minimum(<name>)}}` Minimum of all measurements.
@@ -244,21 +247,21 @@ class BigO;
* For the layer tags *result* and *measurement* you additionally can use these special markers:
*
* * ``{{#-first}}`` - Begin marker of a template that will be instantiated *only for the first* entry in the layer. Use is only
- * allowed between the begin and end marker of the layer allowed. So between ``{{#result}}`` and ``{{/result}}``, or between
+ * allowed between the begin and end marker of the layer. So between ``{{#result}}`` and ``{{/result}}``, or between
* ``{{#measurement}}`` and ``{{/measurement}}``. Finish the template with ``{{/-first}}``.
*
* * ``{{^-first}}`` - Begin marker of a template that will be instantiated *for each except the first* entry in the layer. This,
- * this is basically the inversion of ``{{#-first}}``. Use is only allowed between the begin and end marker of the layer allowed.
+ * this is basically the inversion of ``{{#-first}}``. Use is only allowed between the begin and end marker of the layer.
* So between ``{{#result}}`` and ``{{/result}}``, or between ``{{#measurement}}`` and ``{{/measurement}}``.
*
* * ``{{/-first}}`` - End marker for either ``{{#-first}}`` or ``{{^-first}}``.
*
* * ``{{#-last}}`` - Begin marker of a template that will be instantiated *only for the last* entry in the layer. Use is only
- * allowed between the begin and end marker of the layer allowed. So between ``{{#result}}`` and ``{{/result}}``, or between
+ * allowed between the begin and end marker of the layer. So between ``{{#result}}`` and ``{{/result}}``, or between
* ``{{#measurement}}`` and ``{{/measurement}}``. Finish the template with ``{{/-last}}``.
*
* * ``{{^-last}}`` - Begin marker of a template that will be instantiated *for each except the last* entry in the layer. This,
- * this is basically the inversion of ``{{#-last}}``. Use is only allowed between the begin and end marker of the layer allowed.
+ * this is basically the inversion of ``{{#-last}}``. Use is only allowed between the begin and end marker of the layer.
* So between ``{{#result}}`` and ``{{/result}}``, or between ``{{#measurement}}`` and ``{{/measurement}}``.
*
* * ``{{/-last}}`` - End marker for either ``{{#-last}}`` or ``{{^-last}}``.
@@ -316,12 +319,12 @@ char const* csv() noexcept;
See the tutorial at :ref:`tutorial-template-html` for an example.
@endverbatim
- @see ankerl::nanobench::render()
+ @see also ankerl::nanobench::render()
*/
char const* htmlBoxplot() noexcept;
/*!
- @brief Output in pyperf compatible JSON format, which can be used for more analyzations.
+ @brief Output in pyperf compatible JSON format, which can be used for more analyzation.
@verbatim embed:rst
See the tutorial at :ref:`tutorial-template-pyperf` for an example how to further analyze the output.
@endverbatim
@@ -378,30 +381,32 @@ struct PerfCountSet {
ANKERL_NANOBENCH(IGNORE_PADDED_PUSH)
struct Config {
// actual benchmark config
- std::string mBenchmarkTitle = "benchmark";
- std::string mBenchmarkName = "noname";
- std::string mUnit = "op";
- double mBatch = 1.0;
- double mComplexityN = -1.0;
- size_t mNumEpochs = 11;
- size_t mClockResolutionMultiple = static_cast<size_t>(1000);
- std::chrono::nanoseconds mMaxEpochTime = std::chrono::milliseconds(100);
- std::chrono::nanoseconds mMinEpochTime{};
- uint64_t mMinEpochIterations{1};
- uint64_t mEpochIterations{0}; // If not 0, run *exactly* these number of iterations per epoch.
- uint64_t mWarmup = 0;
- std::ostream* mOut = nullptr;
- std::chrono::duration<double> mTimeUnit = std::chrono::nanoseconds{1};
- std::string mTimeUnitName = "ns";
- bool mShowPerformanceCounters = true;
- bool mIsRelative = false;
+ std::string mBenchmarkTitle = "benchmark"; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string mBenchmarkName = "noname"; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string mUnit = "op"; // NOLINT(misc-non-private-member-variables-in-classes)
+ double mBatch = 1.0; // NOLINT(misc-non-private-member-variables-in-classes)
+ double mComplexityN = -1.0; // NOLINT(misc-non-private-member-variables-in-classes)
+ size_t mNumEpochs = 11; // NOLINT(misc-non-private-member-variables-in-classes)
+ size_t mClockResolutionMultiple = static_cast<size_t>(1000); // NOLINT(misc-non-private-member-variables-in-classes)
+ std::chrono::nanoseconds mMaxEpochTime = std::chrono::milliseconds(100); // NOLINT(misc-non-private-member-variables-in-classes)
+ std::chrono::nanoseconds mMinEpochTime = std::chrono::milliseconds(1); // NOLINT(misc-non-private-member-variables-in-classes)
+ uint64_t mMinEpochIterations{1}; // NOLINT(misc-non-private-member-variables-in-classes)
+ // If not 0, run *exactly* these number of iterations per epoch.
+ uint64_t mEpochIterations{0}; // NOLINT(misc-non-private-member-variables-in-classes)
+ uint64_t mWarmup = 0; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::ostream* mOut = nullptr; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::chrono::duration<double> mTimeUnit = std::chrono::nanoseconds{1}; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string mTimeUnitName = "ns"; // NOLINT(misc-non-private-member-variables-in-classes)
+ bool mShowPerformanceCounters = true; // NOLINT(misc-non-private-member-variables-in-classes)
+ bool mIsRelative = false; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::unordered_map<std::string, std::string> mContext{}; // NOLINT(misc-non-private-member-variables-in-classes)
Config();
~Config();
- Config& operator=(Config const&);
- Config& operator=(Config&&);
- Config(Config const&);
- Config(Config&&) noexcept;
+ Config& operator=(Config const& other);
+ Config& operator=(Config&& other) noexcept;
+ Config(Config const& other);
+ Config(Config&& other) noexcept;
};
ANKERL_NANOBENCH(IGNORE_PADDED_POP)
@@ -421,13 +426,13 @@ public:
_size
};
- explicit Result(Config const& benchmarkConfig);
+ explicit Result(Config benchmarkConfig);
~Result();
- Result& operator=(Result const&);
- Result& operator=(Result&&);
- Result(Result const&);
- Result(Result&&) noexcept;
+ Result& operator=(Result const& other);
+ Result& operator=(Result&& other) noexcept;
+ Result(Result const& other);
+ Result(Result&& other) noexcept;
// adds new measurement results
// all values are scaled by iters (except iters...)
@@ -442,6 +447,8 @@ public:
ANKERL_NANOBENCH(NODISCARD) double sumProduct(Measure m1, Measure m2) const noexcept;
ANKERL_NANOBENCH(NODISCARD) double minimum(Measure m) const noexcept;
ANKERL_NANOBENCH(NODISCARD) double maximum(Measure m) const noexcept;
+ ANKERL_NANOBENCH(NODISCARD) std::string const& context(char const* variableName) const;
+ ANKERL_NANOBENCH(NODISCARD) std::string const& context(std::string const& variableName) const;
ANKERL_NANOBENCH(NODISCARD) bool has(Measure m) const noexcept;
ANKERL_NANOBENCH(NODISCARD) double get(size_t idx, Measure m) const;
@@ -485,9 +492,9 @@ public:
static constexpr uint64_t(max)();
/**
- * As a safety precausion, we don't allow copying. Copying a PRNG would mean you would have two random generators that produce the
+ * As a safety precaution, we don't allow copying. Copying a PRNG would mean you would have two random generators that produce the
* same sequence, which is generally not what one wants. Instead create a new rng with the default constructor Rng(), which is
- * automatically seeded from `std::random_device`. If you really need a copy, use copy().
+ * automatically seeded from `std::random_device`. If you really need a copy, use `copy()`.
*/
Rng(Rng const&) = delete;
@@ -528,7 +535,7 @@ public:
*/
explicit Rng(uint64_t seed) noexcept;
Rng(uint64_t x, uint64_t y) noexcept;
- Rng(std::vector<uint64_t> const& data);
+ explicit Rng(std::vector<uint64_t> const& data);
/**
* Creates a copy of the Rng, thus the copy provides exactly the same random sequence as the original.
@@ -620,8 +627,8 @@ public:
*/
Bench();
- Bench(Bench&& other);
- Bench& operator=(Bench&& other);
+ Bench(Bench&& other) noexcept;
+ Bench& operator=(Bench&& other) noexcept;
Bench(Bench const& other);
Bench& operator=(Bench const& other);
~Bench() noexcept;
@@ -667,6 +674,10 @@ public:
*/
Bench& title(char const* benchmarkTitle);
Bench& title(std::string const& benchmarkTitle);
+
+ /**
+ * @brief Gets the title of the benchmark
+ */
ANKERL_NANOBENCH(NODISCARD) std::string const& title() const noexcept;
/// Name of the benchmark, will be shown in the table row.
@@ -675,6 +686,31 @@ public:
ANKERL_NANOBENCH(NODISCARD) std::string const& name() const noexcept;
/**
+ * @brief Set context information.
+ *
+ * The information can be accessed using custom render templates via `{{context(variableName)}}`.
+ * Trying to render a variable that hasn't been set before raises an exception.
+ * Not included in (default) markdown table.
+ *
+ * @see clearContext, render
+ *
+ * @param variableName The name of the context variable.
+ * @param variableValue The value of the context variable.
+ */
+ Bench& context(char const* variableName, char const* variableValue);
+ Bench& context(std::string const& variableName, std::string const& variableValue);
+
+ /**
+ * @brief Reset context information.
+ *
+ * This may improve efficiency when using many context entries,
+ * or improve robustness by removing spurious context entries.
+ *
+ * @see context
+ */
+ Bench& clearContext();
+
+ /**
* @brief Sets the batch size.
*
* E.g. number of processed byte, or some other metric for the size of the processed data in each iteration. If you benchmark
@@ -754,9 +790,9 @@ public:
* representation of the benchmarked code's runtime stability.
*
* Choose the value wisely. In practice, 11 has been shown to be a reasonable choice between runtime performance and accuracy.
- * This setting goes hand in hand with minEpocIterations() (or minEpochTime()). If you are more interested in *median* runtime, you
- * might want to increase epochs(). If you are more interested in *mean* runtime, you might want to increase minEpochIterations()
- * instead.
+ * This setting goes hand in hand with minEpochIterations() (or minEpochTime()). If you are more interested in *median* runtime,
+ * you might want to increase epochs(). If you are more interested in *mean* runtime, you might want to increase
+ * minEpochIterations() instead.
*
* @param numEpochs Number of epochs.
*/
@@ -766,10 +802,10 @@ public:
/**
* @brief Upper limit for the runtime of each epoch.
*
- * As a safety precausion if the clock is not very accurate, we can set an upper limit for the maximum evaluation time per
+ * As a safety precaution if the clock is not very accurate, we can set an upper limit for the maximum evaluation time per
* epoch. Default is 100ms. At least a single evaluation of the benchmark is performed.
*
- * @see minEpochTime(), minEpochIterations()
+ * @see minEpochTime, minEpochIterations
*
* @param t Maximum target runtime for a single epoch.
*/
@@ -782,7 +818,7 @@ public:
* Default is zero, so we are fully relying on clockResolutionMultiple(). In most cases this is exactly what you want. If you see
* that the evaluation is unreliable with a high `err%`, you can increase either minEpochTime() or minEpochIterations().
*
- * @see maxEpochTime(), minEpochIterations()
+ * @see maxEpochTim), minEpochIterations
*
* @param t Minimum time each epoch should take.
*/
@@ -793,9 +829,9 @@ public:
* @brief Sets the minimum number of iterations each epoch should take.
*
* Default is 1, and we rely on clockResolutionMultiple(). If the `err%` is high and you want a more smooth result, you might want
- * to increase the minimum number or iterations, or increase the minEpochTime().
+ * to increase the minimum number of iterations, or increase the minEpochTime().
*
- * @see minEpochTime(), maxEpochTime(), minEpochIterations()
+ * @see minEpochTime, maxEpochTime, minEpochIterations
*
* @param numIters Minimum number of iterations per epoch.
*/
@@ -886,10 +922,10 @@ public:
@endverbatim
@tparam T Any type is cast to `double`.
- @param b Length of N for the next benchmark run, so it is possible to calculate `bigO`.
+ @param n Length of N for the next benchmark run, so it is possible to calculate `bigO`.
*/
template <typename T>
- Bench& complexityN(T b) noexcept;
+ Bench& complexityN(T n) noexcept;
ANKERL_NANOBENCH(NODISCARD) double complexityN() const noexcept;
/*!
@@ -993,7 +1029,7 @@ void doNotOptimizeAway(T const& val);
#else
// These assembly magic is directly from what Google Benchmark is doing. I have previously used what facebook's folly was doing, but
-// this seemd to have compilation problems in some cases. Google Benchmark seemed to be the most well tested anyways.
+// this seemed to have compilation problems in some cases. Google Benchmark seemed to be the most well tested anyways.
// see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307
template <typename T>
void doNotOptimizeAway(T const& val) {
@@ -1019,7 +1055,11 @@ void doNotOptimizeAway(T& val) {
ANKERL_NANOBENCH(IGNORE_EFFCPP_PUSH)
class IterationLogic {
public:
- explicit IterationLogic(Bench const& config) noexcept;
+ explicit IterationLogic(Bench const& bench);
+ IterationLogic(IterationLogic&&) = delete;
+ IterationLogic& operator=(IterationLogic&&) = delete;
+ IterationLogic(IterationLogic const&) = delete;
+ IterationLogic& operator=(IterationLogic const&) = delete;
~IterationLogic();
ANKERL_NANOBENCH(NODISCARD) uint64_t numIters() const noexcept;
@@ -1036,7 +1076,9 @@ ANKERL_NANOBENCH(IGNORE_PADDED_PUSH)
class PerformanceCounters {
public:
PerformanceCounters(PerformanceCounters const&) = delete;
+ PerformanceCounters(PerformanceCounters&&) = delete;
PerformanceCounters& operator=(PerformanceCounters const&) = delete;
+ PerformanceCounters& operator=(PerformanceCounters&&) = delete;
PerformanceCounters();
~PerformanceCounters();
@@ -1081,11 +1123,11 @@ public:
: BigO(bigOName, mapRangeMeasure(rangeMeasure, rangeToN)) {}
template <typename Op>
- BigO(std::string const& bigOName, RangeMeasure const& rangeMeasure, Op rangeToN)
- : BigO(bigOName, mapRangeMeasure(rangeMeasure, rangeToN)) {}
+ BigO(std::string bigOName, RangeMeasure const& rangeMeasure, Op rangeToN)
+ : BigO(std::move(bigOName), mapRangeMeasure(rangeMeasure, rangeToN)) {}
BigO(char const* bigOName, RangeMeasure const& scaledRangeMeasure);
- BigO(std::string const& bigOName, RangeMeasure const& scaledRangeMeasure);
+ BigO(std::string bigOName, RangeMeasure const& scaledRangeMeasure);
ANKERL_NANOBENCH(NODISCARD) std::string const& name() const noexcept;
ANKERL_NANOBENCH(NODISCARD) double constant() const noexcept;
ANKERL_NANOBENCH(NODISCARD) double normalizedRootMeanSquare() const noexcept;
@@ -1127,7 +1169,7 @@ uint64_t Rng::operator()() noexcept {
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined")
uint32_t Rng::bounded(uint32_t range) noexcept {
- uint64_t r32 = static_cast<uint32_t>(operator()());
+ uint64_t const r32 = static_cast<uint32_t>(operator()());
auto multiresult = r32 * range;
return static_cast<uint32_t>(multiresult >> 32U);
}
@@ -1136,18 +1178,23 @@ double Rng::uniform01() noexcept {
auto i = (UINT64_C(0x3ff) << 52U) | (operator()() >> 12U);
// can't use union in c++ here for type puning, it's undefined behavior.
// std::memcpy is optimized anyways.
- double d;
+ double d{};
std::memcpy(&d, &i, sizeof(double));
return d - 1.0;
}
template <typename Container>
void Rng::shuffle(Container& container) noexcept {
- auto size = static_cast<uint32_t>(container.size());
- for (auto i = size; i > 1U; --i) {
+ auto i = container.size();
+ while (i > 1U) {
using std::swap;
- auto p = bounded(i); // number in [0, i)
- swap(container[i - 1], container[p]);
+ auto n = operator()();
+ // using decltype(i) instead of size_t to be compatible to containers with 32bit index (see #80)
+ auto b1 = static_cast<decltype(i)>((static_cast<uint32_t>(n) * static_cast<uint64_t>(i)) >> 32U);
+ swap(container[--i], container[b1]);
+
+ auto b2 = static_cast<decltype(i)>(((n >> 32U) * static_cast<uint64_t>(i)) >> 32U);
+ swap(container[--i], container[b2]);
}
}
@@ -1165,11 +1212,11 @@ Bench& Bench::run(Op&& op) {
while (auto n = iterationLogic.numIters()) {
pc.beginMeasure();
- Clock::time_point before = Clock::now();
+ Clock::time_point const before = Clock::now();
while (n-- > 0) {
op();
}
- Clock::time_point after = Clock::now();
+ Clock::time_point const after = Clock::now();
pc.endMeasure();
pc.updateResults(iterationLogic.numIters());
iterationLogic.add(after - before, pc);
@@ -1270,7 +1317,6 @@ void doNotOptimizeAway(T const& val) {
# include <linux/perf_event.h>
# include <sys/ioctl.h>
# include <sys/syscall.h>
-# include <unistd.h>
# endif
// declarations ///////////////////////////////////////////////////////////////////////////////////
@@ -1436,31 +1482,37 @@ struct Node {
template <size_t N>
// NOLINTNEXTLINE(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
bool operator==(char const (&str)[N]) const noexcept {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
return static_cast<size_t>(std::distance(begin, end) + 1) == N && 0 == strncmp(str, begin, N - 1);
}
};
ANKERL_NANOBENCH(IGNORE_PADDED_POP)
+// NOLINTNEXTLINE(misc-no-recursion)
static std::vector<Node> parseMustacheTemplate(char const** tpl) {
std::vector<Node> nodes;
while (true) {
- auto begin = std::strstr(*tpl, "{{");
- auto end = begin;
+ auto const* begin = std::strstr(*tpl, "{{");
+ auto const* end = begin;
if (begin != nullptr) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
begin += 2;
end = std::strstr(begin, "}}");
}
if (begin == nullptr || end == nullptr) {
// nothing found, finish node
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
nodes.emplace_back(Node{*tpl, *tpl + std::strlen(*tpl), std::vector<Node>{}, Node::Type::content});
return nodes;
}
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
nodes.emplace_back(Node{*tpl, begin - 2, std::vector<Node>{}, Node::Type::content});
// we found a tag
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*tpl = end + 2;
switch (*begin) {
case '/':
@@ -1468,10 +1520,12 @@ static std::vector<Node> parseMustacheTemplate(char const** tpl) {
return nodes;
case '#':
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
nodes.emplace_back(Node{begin + 1, end, parseMustacheTemplate(tpl), Node::Type::section});
break;
case '^':
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
nodes.emplace_back(Node{begin + 1, end, parseMustacheTemplate(tpl), Node::Type::inverted_section});
break;
@@ -1484,8 +1538,8 @@ static std::vector<Node> parseMustacheTemplate(char const** tpl) {
static bool generateFirstLast(Node const& n, size_t idx, size_t size, std::ostream& out) {
ANKERL_NANOBENCH_LOG("n.type=" << static_cast<int>(n.type));
- bool matchFirst = n == "-first";
- bool matchLast = n == "-last";
+ bool const matchFirst = n == "-first";
+ bool const matchLast = n == "-last";
if (!matchFirst && !matchLast) {
return false;
}
@@ -1518,7 +1572,7 @@ static bool matchCmdArgs(std::string const& str, std::vector<std::string>& match
matchResult.emplace_back(str.substr(0, idxOpen));
// split by comma
- matchResult.emplace_back(std::string{});
+ matchResult.emplace_back();
for (size_t i = idxOpen + 1; i != idxClose; ++i) {
if (str[i] == ' ' || str[i] == '\t') {
// skip whitespace
@@ -1526,7 +1580,7 @@ static bool matchCmdArgs(std::string const& str, std::vector<std::string>& match
}
if (str[i] == ',') {
// got a comma => new string
- matchResult.emplace_back(std::string{});
+ matchResult.emplace_back();
continue;
}
// no whitespace no comma, append
@@ -1541,49 +1595,63 @@ static bool generateConfigTag(Node const& n, Config const& config, std::ostream&
if (n == "title") {
out << config.mBenchmarkTitle;
return true;
- } else if (n == "name") {
+ }
+ if (n == "name") {
out << config.mBenchmarkName;
return true;
- } else if (n == "unit") {
+ }
+ if (n == "unit") {
out << config.mUnit;
return true;
- } else if (n == "batch") {
+ }
+ if (n == "batch") {
out << config.mBatch;
return true;
- } else if (n == "complexityN") {
+ }
+ if (n == "complexityN") {
out << config.mComplexityN;
return true;
- } else if (n == "epochs") {
+ }
+ if (n == "epochs") {
out << config.mNumEpochs;
return true;
- } else if (n == "clockResolution") {
+ }
+ if (n == "clockResolution") {
out << d(detail::clockResolution());
return true;
- } else if (n == "clockResolutionMultiple") {
+ }
+ if (n == "clockResolutionMultiple") {
out << config.mClockResolutionMultiple;
return true;
- } else if (n == "maxEpochTime") {
+ }
+ if (n == "maxEpochTime") {
out << d(config.mMaxEpochTime);
return true;
- } else if (n == "minEpochTime") {
+ }
+ if (n == "minEpochTime") {
out << d(config.mMinEpochTime);
return true;
- } else if (n == "minEpochIterations") {
+ }
+ if (n == "minEpochIterations") {
out << config.mMinEpochIterations;
return true;
- } else if (n == "epochIterations") {
+ }
+ if (n == "epochIterations") {
out << config.mEpochIterations;
return true;
- } else if (n == "warmup") {
+ }
+ if (n == "warmup") {
out << config.mWarmup;
return true;
- } else if (n == "relative") {
+ }
+ if (n == "relative") {
out << config.mIsRelative;
return true;
}
return false;
}
+// NOLINTNEXTLINE(readability-function-cognitive-complexity)
static std::ostream& generateResultTag(Node const& n, Result const& r, std::ostream& out) {
if (generateConfigTag(n, r.config(), out)) {
return out;
@@ -1596,6 +1664,10 @@ static std::ostream& generateResultTag(Node const& n, Result const& r, std::ostr
std::vector<std::string> matchResult;
if (matchCmdArgs(std::string(n.begin, n.end), matchResult)) {
if (matchResult.size() == 2) {
+ if (matchResult[0] == "context") {
+ return out << r.context(matchResult[1]);
+ }
+
auto m = Result::fromString(matchResult[1]);
if (m == Result::Measure::_size) {
return out << 0.0;
@@ -1712,7 +1784,7 @@ template <typename T>
T parseFile(std::string const& filename);
void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<std::string>& recommendations);
-void printStabilityInformationOnce(std::ostream* os);
+void printStabilityInformationOnce(std::ostream* outStream);
// remembers the last table settings used. When it changes, a new table header is automatically written for the new entry.
uint64_t& singletonHeaderHash() noexcept;
@@ -1779,13 +1851,13 @@ private:
};
// helper replacement for std::to_string of signed/unsigned numbers so we are locale independent
-std::string to_s(uint64_t s);
+std::string to_s(uint64_t n);
std::ostream& operator<<(std::ostream& os, Number const& n);
class MarkDownColumn {
public:
- MarkDownColumn(int w, int prec, std::string const& tit, std::string const& suff, double val);
+ MarkDownColumn(int w, int prec, std::string tit, std::string suff, double val);
std::string title() const;
std::string separator() const;
std::string invalid() const;
@@ -1823,8 +1895,9 @@ std::ostream& operator<<(std::ostream& os, MarkDownCode const& mdCode);
namespace ankerl {
namespace nanobench {
+// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void render(char const* mustacheTemplate, std::vector<Result> const& results, std::ostream& out) {
- detail::fmt::StreamStateRestorer restorer(out);
+ detail::fmt::StreamStateRestorer const restorer(out);
out.precision(std::numeric_limits<double>::digits10);
auto nodes = templates::parseMustacheTemplate(&mustacheTemplate);
@@ -1914,7 +1987,7 @@ void doNotOptimizeAwaySink(void const*) {}
template <typename T>
T parseFile(std::string const& filename) {
- std::ifstream fin(filename);
+ std::ifstream fin(filename); // NOLINT(misc-const-correctness)
T num{};
fin >> num;
return num;
@@ -1925,20 +1998,20 @@ char const* getEnv(char const* name) {
# pragma warning(push)
# pragma warning(disable : 4996) // getenv': This function or variable may be unsafe.
# endif
- return std::getenv(name);
+ return std::getenv(name); // NOLINT(concurrency-mt-unsafe)
# if defined(_MSC_VER)
# pragma warning(pop)
# endif
}
bool isEndlessRunning(std::string const& name) {
- auto endless = getEnv("NANOBENCH_ENDLESS");
+ auto const* const endless = getEnv("NANOBENCH_ENDLESS");
return nullptr != endless && endless == name;
}
// True when environment variable NANOBENCH_SUPPRESS_WARNINGS is either not set at all, or set to "0"
bool isWarningsEnabled() {
- auto suppression = getEnv("NANOBENCH_SUPPRESS_WARNINGS");
+ auto const* const suppression = getEnv("NANOBENCH_SUPPRESS_WARNINGS");
return nullptr == suppression || suppression == std::string("0");
}
@@ -1946,11 +2019,11 @@ void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<
warnings.clear();
recommendations.clear();
- bool recommendCheckFlags = false;
-
# if defined(DEBUG)
warnings.emplace_back("DEBUG defined");
- recommendCheckFlags = true;
+ bool const recommendCheckFlags = true;
+# else
+ bool const recommendCheckFlags = false;
# endif
bool recommendPyPerf = false;
@@ -2000,7 +2073,7 @@ void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<
void printStabilityInformationOnce(std::ostream* outStream) {
static bool shouldPrint = true;
- if (shouldPrint && outStream && isWarningsEnabled()) {
+ if (shouldPrint && (nullptr != outStream) && isWarningsEnabled()) {
auto& os = *outStream;
shouldPrint = false;
std::vector<std::string> warnings;
@@ -2050,7 +2123,7 @@ Clock::duration calcClockResolution(size_t numEvaluations) noexcept {
// Calculates clock resolution once, and remembers the result
Clock::duration clockResolution() noexcept {
- static Clock::duration sResolution = calcClockResolution(20);
+ static Clock::duration const sResolution = calcClockResolution(20);
return sResolution;
}
@@ -2183,6 +2256,7 @@ struct IterationLogic::Impl {
<< ", mState=" << static_cast<int>(mState));
}
+ // NOLINTNEXTLINE(readability-function-cognitive-complexity)
void showResult(std::string const& errorMessage) const {
ANKERL_NANOBENCH_LOG(errorMessage);
@@ -2208,7 +2282,7 @@ struct IterationLogic::Impl {
rMedian / (mBench.timeUnit().count() * mBench.batch()));
columns.emplace_back(22, 2, mBench.unit() + "/s", "", rMedian <= 0.0 ? 0.0 : mBench.batch() / rMedian);
- double rErrorMedian = mResult.medianAbsolutePercentError(Result::Measure::elapsed);
+ double const rErrorMedian = mResult.medianAbsolutePercentError(Result::Measure::elapsed);
columns.emplace_back(10, 1, "err%", "%", rErrorMedian * 100.0);
double rInsMedian = -1.0;
@@ -2226,7 +2300,7 @@ struct IterationLogic::Impl {
columns.emplace_back(9, 3, "IPC", "", rCycMedian <= 0.0 ? 0.0 : rInsMedian / rCycMedian);
}
if (mBench.performanceCounters() && mResult.has(Result::Measure::branchinstructions)) {
- double rBraMedian = mResult.median(Result::Measure::branchinstructions);
+ double const rBraMedian = mResult.median(Result::Measure::branchinstructions);
columns.emplace_back(17, 2, "bra/" + mBench.unit(), "", rBraMedian / mBench.batch());
if (mResult.has(Result::Measure::branchmisses)) {
double p = 0.0;
@@ -2299,25 +2373,22 @@ struct IterationLogic::Impl {
return elapsed * 3 >= mTargetRuntimePerEpoch * 2;
}
- uint64_t mNumIters = 1;
- Bench const& mBench;
- std::chrono::nanoseconds mTargetRuntimePerEpoch{};
- Result mResult;
- Rng mRng{123};
- std::chrono::nanoseconds mTotalElapsed{};
- uint64_t mTotalNumIters = 0;
-
- State mState = State::upscaling_runtime;
+ uint64_t mNumIters = 1; // NOLINT(misc-non-private-member-variables-in-classes)
+ Bench const& mBench; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::chrono::nanoseconds mTargetRuntimePerEpoch{}; // NOLINT(misc-non-private-member-variables-in-classes)
+ Result mResult; // NOLINT(misc-non-private-member-variables-in-classes)
+ Rng mRng{123}; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::chrono::nanoseconds mTotalElapsed{}; // NOLINT(misc-non-private-member-variables-in-classes)
+ uint64_t mTotalNumIters = 0; // NOLINT(misc-non-private-member-variables-in-classes)
+ State mState = State::upscaling_runtime; // NOLINT(misc-non-private-member-variables-in-classes)
};
ANKERL_NANOBENCH(IGNORE_PADDED_POP)
-IterationLogic::IterationLogic(Bench const& bench) noexcept
+IterationLogic::IterationLogic(Bench const& bench)
: mPimpl(new Impl(bench)) {}
IterationLogic::~IterationLogic() {
- if (mPimpl) {
- delete mPimpl;
- }
+ delete mPimpl;
}
uint64_t IterationLogic::numIters() const noexcept {
@@ -2344,11 +2415,16 @@ public:
, correctMeasuringOverhead(correctMeasuringOverhead_)
, correctLoopOverhead(correctLoopOverhead_) {}
- uint64_t* targetValue{};
- bool correctMeasuringOverhead{};
- bool correctLoopOverhead{};
+ uint64_t* targetValue{}; // NOLINT(misc-non-private-member-variables-in-classes)
+ bool correctMeasuringOverhead{}; // NOLINT(misc-non-private-member-variables-in-classes)
+ bool correctLoopOverhead{}; // NOLINT(misc-non-private-member-variables-in-classes)
};
+ LinuxPerformanceCounters() = default;
+ LinuxPerformanceCounters(LinuxPerformanceCounters const&) = delete;
+ LinuxPerformanceCounters(LinuxPerformanceCounters&&) = delete;
+ LinuxPerformanceCounters& operator=(LinuxPerformanceCounters const&) = delete;
+ LinuxPerformanceCounters& operator=(LinuxPerformanceCounters&&) = delete;
~LinuxPerformanceCounters();
// quick operation
@@ -2370,13 +2446,13 @@ public:
return;
}
- // NOLINTNEXTLINE(hicpp-signed-bitwise)
+ // NOLINTNEXTLINE(hicpp-signed-bitwise,cppcoreguidelines-pro-type-vararg)
mHasError = -1 == ioctl(mFd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
if (mHasError) {
return;
}
- // NOLINTNEXTLINE(hicpp-signed-bitwise)
+ // NOLINTNEXTLINE(hicpp-signed-bitwise,cppcoreguidelines-pro-type-vararg)
mHasError = -1 == ioctl(mFd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
}
@@ -2385,7 +2461,7 @@ public:
return;
}
- // NOLINTNEXTLINE(hicpp-signed-bitwise)
+ // NOLINTNEXTLINE(hicpp-signed-bitwise,cppcoreguidelines-pro-type-vararg)
mHasError = (-1 == ioctl(mFd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP));
if (mHasError) {
return;
@@ -2406,9 +2482,9 @@ public:
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined")
static inline uint32_t mix(uint32_t x) noexcept {
- x ^= x << 13;
- x ^= x >> 17;
- x ^= x << 5;
+ x ^= x << 13U;
+ x ^= x >> 17U;
+ x ^= x << 5U;
return x;
}
@@ -2448,7 +2524,7 @@ public:
// marsaglia's xorshift: mov, sal/shr, xor. Times 3.
// This has the nice property that the compiler doesn't seem to be able to optimize multiple calls any further.
// see https://godbolt.org/z/49RVQ5
- uint64_t const numIters = 100000U + (std::random_device{}() & 3);
+ uint64_t const numIters = 100000U + (std::random_device{}() & 3U);
uint64_t n = numIters;
uint32_t x = 1234567;
@@ -2582,6 +2658,7 @@ bool LinuxPerformanceCounters::monitor(uint32_t type, uint64_t eventid, Target t
const unsigned long flags = 0;
# endif
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
auto fd = static_cast<int>(syscall(__NR_perf_event_open, &pea, pid, cpu, mFd, flags));
if (-1 == fd) {
return false;
@@ -2591,7 +2668,7 @@ bool LinuxPerformanceCounters::monitor(uint32_t type, uint64_t eventid, Target t
mFd = fd;
}
uint64_t id = 0;
- // NOLINTNEXTLINE(hicpp-signed-bitwise)
+ // NOLINTNEXTLINE(hicpp-signed-bitwise,cppcoreguidelines-pro-type-vararg)
if (-1 == ioctl(fd, PERF_EVENT_IOC_ID, &id)) {
// couldn't get id
return false;
@@ -2639,9 +2716,8 @@ PerformanceCounters::PerformanceCounters()
}
PerformanceCounters::~PerformanceCounters() {
- if (nullptr != mPc) {
- delete mPc;
- }
+ // no need to check for nullptr, delete nullptr has no effect
+ delete mPc;
}
void PerformanceCounters::beginMeasure() {
@@ -2721,7 +2797,7 @@ Number::Number(int width, int precision, double value)
, mValue(value) {}
std::ostream& Number::write(std::ostream& os) const {
- StreamStateRestorer restorer(os);
+ StreamStateRestorer const restorer(os);
os.imbue(std::locale(os.getloc(), new NumSep(',')));
os << std::setw(mWidth) << std::setprecision(mPrecision) << std::fixed << mValue;
return os;
@@ -2747,11 +2823,11 @@ std::ostream& operator<<(std::ostream& os, Number const& n) {
return n.write(os);
}
-MarkDownColumn::MarkDownColumn(int w, int prec, std::string const& tit, std::string const& suff, double val)
+MarkDownColumn::MarkDownColumn(int w, int prec, std::string tit, std::string suff, double val)
: mWidth(w)
, mPrecision(prec)
- , mTitle(tit)
- , mSuffix(suff)
+ , mTitle(std::move(tit))
+ , mSuffix(std::move(suff))
, mValue(val) {}
std::string MarkDownColumn::title() const {
@@ -2785,7 +2861,7 @@ std::string MarkDownColumn::value() const {
MarkDownCode::MarkDownCode(std::string const& what) {
mWhat.reserve(what.size() + 2);
mWhat.push_back('`');
- for (char c : what) {
+ for (char const c : what) {
mWhat.push_back(c);
if ('`' == c) {
mWhat.push_back('`');
@@ -2808,14 +2884,14 @@ std::ostream& operator<<(std::ostream& os, MarkDownCode const& mdCode) {
Config::Config() = default;
Config::~Config() = default;
Config& Config::operator=(Config const&) = default;
-Config& Config::operator=(Config&&) = default;
+Config& Config::operator=(Config&&) noexcept = default;
Config::Config(Config const&) = default;
Config::Config(Config&&) noexcept = default;
// provide implementation here so it's only generated once
Result::~Result() = default;
Result& Result::operator=(Result const&) = default;
-Result& Result::operator=(Result&&) = default;
+Result& Result::operator=(Result&&) noexcept = default;
Result::Result(Result const&) = default;
Result::Result(Result&&) noexcept = default;
@@ -2827,15 +2903,15 @@ inline constexpr typename std::underlying_type<T>::type u(T val) noexcept {
} // namespace detail
// Result returned after a benchmark has finished. Can be used as a baseline for relative().
-Result::Result(Config const& benchmarkConfig)
- : mConfig(benchmarkConfig)
+Result::Result(Config benchmarkConfig)
+ : mConfig(std::move(benchmarkConfig))
, mNameToMeasurements{detail::u(Result::Measure::_size)} {}
void Result::add(Clock::duration totalElapsed, uint64_t iters, detail::PerformanceCounters const& pc) {
using detail::d;
using detail::u;
- double dIters = d(iters);
+ double const dIters = d(iters);
mNameToMeasurements[u(Result::Measure::iterations)].push_back(dIters);
mNameToMeasurements[u(Result::Measure::elapsed)].push_back(d(totalElapsed) / dIters);
@@ -2987,27 +3063,41 @@ double Result::maximum(Measure m) const noexcept {
return *std::max_element(data.begin(), data.end());
}
+std::string const& Result::context(char const* variableName) const {
+ return mConfig.mContext.at(variableName);
+}
+
+std::string const& Result::context(std::string const& variableName) const {
+ return mConfig.mContext.at(variableName);
+}
+
Result::Measure Result::fromString(std::string const& str) {
if (str == "elapsed") {
return Measure::elapsed;
- } else if (str == "iterations") {
+ }
+ if (str == "iterations") {
return Measure::iterations;
- } else if (str == "pagefaults") {
+ }
+ if (str == "pagefaults") {
return Measure::pagefaults;
- } else if (str == "cpucycles") {
+ }
+ if (str == "cpucycles") {
return Measure::cpucycles;
- } else if (str == "contextswitches") {
+ }
+ if (str == "contextswitches") {
return Measure::contextswitches;
- } else if (str == "instructions") {
+ }
+ if (str == "instructions") {
return Measure::instructions;
- } else if (str == "branchinstructions") {
+ }
+ if (str == "branchinstructions") {
return Measure::branchinstructions;
- } else if (str == "branchmisses") {
+ }
+ if (str == "branchmisses") {
return Measure::branchmisses;
- } else {
- // not found, return _size
- return Measure::_size;
}
+ // not found, return _size
+ return Measure::_size;
}
// Configuration of a microbenchmark.
@@ -3015,8 +3105,8 @@ Bench::Bench() {
mConfig.mOut = &std::cout;
}
-Bench::Bench(Bench&&) = default;
-Bench& Bench::operator=(Bench&&) = default;
+Bench::Bench(Bench&&) noexcept = default;
+Bench& Bench::operator=(Bench&&) noexcept = default;
Bench::Bench(Bench const&) = default;
Bench& Bench::operator=(Bench const&) = default;
Bench::~Bench() noexcept = default;
@@ -3114,6 +3204,21 @@ std::string const& Bench::name() const noexcept {
return mConfig.mBenchmarkName;
}
+Bench& Bench::context(char const* variableName, char const* variableValue) {
+ mConfig.mContext[variableName] = variableValue;
+ return *this;
+}
+
+Bench& Bench::context(std::string const& variableName, std::string const& variableValue) {
+ mConfig.mContext[variableName] = variableValue;
+ return *this;
+}
+
+Bench& Bench::clearContext() {
+ mConfig.mContext.clear();
+ return *this;
+}
+
// Number of epochs to evaluate. The reported result will be the median of evaluation of each epoch.
Bench& Bench::epochs(size_t numEpochs) noexcept {
mConfig.mNumEpochs = numEpochs;
@@ -3295,27 +3400,27 @@ BigO::RangeMeasure BigO::collectRangeMeasure(std::vector<Result> const& results)
return rangeMeasure;
}
-BigO::BigO(std::string const& bigOName, RangeMeasure const& rangeMeasure)
- : mName(bigOName) {
+BigO::BigO(std::string bigOName, RangeMeasure const& rangeMeasure)
+ : mName(std::move(bigOName)) {
// estimate the constant factor
double sumRangeMeasure = 0.0;
double sumRangeRange = 0.0;
- for (size_t i = 0; i < rangeMeasure.size(); ++i) {
- sumRangeMeasure += rangeMeasure[i].first * rangeMeasure[i].second;
- sumRangeRange += rangeMeasure[i].first * rangeMeasure[i].first;
+ for (const auto& rm : rangeMeasure) {
+ sumRangeMeasure += rm.first * rm.second;
+ sumRangeRange += rm.first * rm.first;
}
mConstant = sumRangeMeasure / sumRangeRange;
// calculate root mean square
double err = 0.0;
double sumMeasure = 0.0;
- for (size_t i = 0; i < rangeMeasure.size(); ++i) {
- auto diff = mConstant * rangeMeasure[i].first - rangeMeasure[i].second;
+ for (const auto& rm : rangeMeasure) {
+ auto diff = mConstant * rm.first - rm.second;
err += diff * diff;
- sumMeasure += rangeMeasure[i].second;
+ sumMeasure += rm.second;
}
auto n = static_cast<double>(rangeMeasure.size());
@@ -3347,7 +3452,7 @@ std::ostream& operator<<(std::ostream& os, BigO const& bigO) {
}
std::ostream& operator<<(std::ostream& os, std::vector<ankerl::nanobench::BigO> const& bigOs) {
- detail::fmt::StreamStateRestorer restorer(os);
+ detail::fmt::StreamStateRestorer const restorer(os);
os << std::endl << "| coefficient | err% | complexity" << std::endl << "|--------------:|-------:|------------" << std::endl;
for (auto const& bigO : bigOs) {
os << "|" << std::setw(14) << std::setprecision(7) << std::scientific << bigO.constant() << " ";
diff --git a/src/bench/peer_eviction.cpp b/src/bench/peer_eviction.cpp
index f05f5e8f64..e04f3c403c 100644
--- a/src/bench/peer_eviction.cpp
+++ b/src/bench/peer_eviction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -40,7 +40,7 @@ static void EvictionProtection0Networks250Candidates(benchmark::Bench& bench)
{
EvictionProtectionCommon(
bench,
- 250 /* num_candidates */,
+ /*num_candidates=*/250,
[](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
c.m_network = NET_IPV4;
@@ -51,7 +51,7 @@ static void EvictionProtection1Networks250Candidates(benchmark::Bench& bench)
{
EvictionProtectionCommon(
bench,
- 250 /* num_candidates */,
+ /*num_candidates=*/250,
[](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
c.m_is_local = false;
@@ -67,7 +67,7 @@ static void EvictionProtection2Networks250Candidates(benchmark::Bench& bench)
{
EvictionProtectionCommon(
bench,
- 250 /* num_candidates */,
+ /*num_candidates=*/250,
[](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
c.m_is_local = false;
@@ -85,7 +85,7 @@ static void EvictionProtection3Networks050Candidates(benchmark::Bench& bench)
{
EvictionProtectionCommon(
bench,
- 50 /* num_candidates */,
+ /*num_candidates=*/50,
[](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
c.m_is_local = (c.id == 28 || c.id == 47); // 2 localhost
@@ -103,7 +103,7 @@ static void EvictionProtection3Networks100Candidates(benchmark::Bench& bench)
{
EvictionProtectionCommon(
bench,
- 100 /* num_candidates */,
+ /*num_candidates=*/100,
[](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
c.m_is_local = (c.id >= 55 && c.id < 60); // 5 localhost
@@ -121,7 +121,7 @@ static void EvictionProtection3Networks250Candidates(benchmark::Bench& bench)
{
EvictionProtectionCommon(
bench,
- 250 /* num_candidates */,
+ /*num_candidates=*/250,
[](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
c.m_is_local = (c.id >= 140 && c.id < 160); // 20 localhost
@@ -141,15 +141,15 @@ static void EvictionProtection3Networks250Candidates(benchmark::Bench& bench)
// - 250 candidates is the number of peers reported by operators of busy nodes
// No disadvantaged networks, with 250 eviction candidates.
-BENCHMARK(EvictionProtection0Networks250Candidates);
+BENCHMARK(EvictionProtection0Networks250Candidates, benchmark::PriorityLevel::HIGH);
// 1 disadvantaged network (Tor) with 250 eviction candidates.
-BENCHMARK(EvictionProtection1Networks250Candidates);
+BENCHMARK(EvictionProtection1Networks250Candidates, benchmark::PriorityLevel::HIGH);
// 2 disadvantaged networks (I2P, Tor) with 250 eviction candidates.
-BENCHMARK(EvictionProtection2Networks250Candidates);
+BENCHMARK(EvictionProtection2Networks250Candidates, benchmark::PriorityLevel::HIGH);
// 3 disadvantaged networks (I2P/localhost/Tor) with 50/100/250 eviction candidates.
-BENCHMARK(EvictionProtection3Networks050Candidates);
-BENCHMARK(EvictionProtection3Networks100Candidates);
-BENCHMARK(EvictionProtection3Networks250Candidates);
+BENCHMARK(EvictionProtection3Networks050Candidates, benchmark::PriorityLevel::HIGH);
+BENCHMARK(EvictionProtection3Networks100Candidates, benchmark::PriorityLevel::HIGH);
+BENCHMARK(EvictionProtection3Networks250Candidates, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/poly1305.cpp b/src/bench/poly1305.cpp
index cdef97c0ea..f7d17dfa96 100644
--- a/src/bench/poly1305.cpp
+++ b/src/bench/poly1305.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -36,6 +36,6 @@ static void POLY1305_1MB(benchmark::Bench& bench)
POLY1305(bench, BUFFER_SIZE_LARGE);
}
-BENCHMARK(POLY1305_64BYTES);
-BENCHMARK(POLY1305_256BYTES);
-BENCHMARK(POLY1305_1MB);
+BENCHMARK(POLY1305_64BYTES, benchmark::PriorityLevel::HIGH);
+BENCHMARK(POLY1305_256BYTES, benchmark::PriorityLevel::HIGH);
+BENCHMARK(POLY1305_1MB, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp
index b3688bab1b..59c4af086e 100644
--- a/src/bench/prevector.cpp
+++ b/src/bench/prevector.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -61,7 +61,7 @@ static void PrevectorResize(benchmark::Bench& bench)
template <typename T>
static void PrevectorDeserialize(benchmark::Bench& bench)
{
- CDataStream s0(SER_NETWORK, 0);
+ DataStream s0{};
prevector<28, T> t0;
t0.resize(28);
for (auto x = 0; x < 900; ++x) {
@@ -85,12 +85,12 @@ static void PrevectorDeserialize(benchmark::Bench& bench)
{ \
Prevector##name<nontrivial_t>(bench); \
} \
- BENCHMARK(Prevector##name##Nontrivial); \
+ BENCHMARK(Prevector##name##Nontrivial, benchmark::PriorityLevel::HIGH); \
static void Prevector##name##Trivial(benchmark::Bench& bench) \
{ \
Prevector##name<trivial_t>(bench); \
} \
- BENCHMARK(Prevector##name##Trivial);
+ BENCHMARK(Prevector##name##Trivial, benchmark::PriorityLevel::HIGH);
PREVECTOR_TEST(Clear)
PREVECTOR_TEST(Destructor)
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
index 8f05e3bad0..de76a87278 100644
--- a/src/bench/rollingbloom.cpp
+++ b/src/bench/rollingbloom.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -32,5 +32,5 @@ static void RollingBloomReset(benchmark::Bench& bench)
});
}
-BENCHMARK(RollingBloom);
-BENCHMARK(RollingBloomReset);
+BENCHMARK(RollingBloom, benchmark::PriorityLevel::HIGH);
+BENCHMARK(RollingBloomReset, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
index e6fc8d21f4..f68b6acb5b 100644
--- a/src/bench/rpc_blockchain.cpp
+++ b/src/bench/rpc_blockchain.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -45,7 +45,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench)
});
}
-BENCHMARK(BlockToJsonVerbose);
+BENCHMARK(BlockToJsonVerbose, benchmark::PriorityLevel::HIGH);
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
{
@@ -57,4 +57,4 @@ static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
});
}
-BENCHMARK(BlockToJsonVerboseWrite);
+BENCHMARK(BlockToJsonVerboseWrite, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp
index 0e6fdae3d7..e3e1a07c83 100644
--- a/src/bench/rpc_mempool.cpp
+++ b/src/bench/rpc_mempool.cpp
@@ -1,9 +1,11 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
#include <chainparamsbase.h>
+#include <kernel/cs_main.h>
+#include <kernel/mempool_entry.h>
#include <rpc/mempool.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
@@ -40,4 +42,4 @@ static void RpcMempool(benchmark::Bench& bench)
});
}
-BENCHMARK(RpcMempool);
+BENCHMARK(RpcMempool, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/strencodings.cpp b/src/bench/strencodings.cpp
index 69b3a83cbf..16d14278a7 100644
--- a/src/bench/strencodings.cpp
+++ b/src/bench/strencodings.cpp
@@ -15,4 +15,4 @@ static void HexStrBench(benchmark::Bench& bench)
});
}
-BENCHMARK(HexStrBench);
+BENCHMARK(HexStrBench, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/util_time.cpp b/src/bench/util_time.cpp
index afc733482e..8dbbdec28c 100644
--- a/src/bench/util_time.cpp
+++ b/src/bench/util_time.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -36,7 +36,7 @@ static void BenchTimeMillisSys(benchmark::Bench& bench)
});
}
-BENCHMARK(BenchTimeDeprecated);
-BENCHMARK(BenchTimeMillis);
-BENCHMARK(BenchTimeMillisSys);
-BENCHMARK(BenchTimeMock);
+BENCHMARK(BenchTimeDeprecated, benchmark::PriorityLevel::HIGH);
+BENCHMARK(BenchTimeMillis, benchmark::PriorityLevel::HIGH);
+BENCHMARK(BenchTimeMillisSys, benchmark::PriorityLevel::HIGH);
+BENCHMARK(BenchTimeMock, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index 8e4708f260..757094167a 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,7 +18,6 @@
// modified to measure performance of other types of scripts.
static void VerifyScriptBench(benchmark::Bench& bench)
{
- const ECCVerifyHandle verify_handle;
ECC_Start();
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
@@ -96,5 +95,5 @@ static void VerifyNestedIfScript(benchmark::Bench& bench)
});
}
-BENCHMARK(VerifyScriptBench);
-BENCHMARK(VerifyNestedIfScript);
+BENCHMARK(VerifyScriptBench, benchmark::PriorityLevel::HIGH);
+BENCHMARK(VerifyNestedIfScript, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp
index a5dd2f3bb1..d5d057e96d 100644
--- a/src/bench/wallet_balance.cpp
+++ b/src/bench/wallet_balance.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,7 +7,7 @@
#include <node/context.h>
#include <test/util/mining.h>
#include <test/util/setup_common.h>
-#include <test/util/wallet.h>
+#include <wallet/test/util.h>
#include <validationinterface.h>
#include <wallet/receive.h>
#include <wallet/wallet.h>
@@ -20,13 +20,15 @@ using wallet::DBErrors;
using wallet::GetBalance;
using wallet::WALLET_FLAG_DESCRIPTORS;
+const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj";
+
static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_mine)
{
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
const auto& ADDRESS_WATCHONLY = ADDRESS_BCRT1_UNSPENDABLE;
- CWallet wallet{test_setup->m_node.chain.get(), "", gArgs, CreateMockWalletDatabase()};
+ CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockWalletDatabase()};
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -57,7 +59,7 @@ static void WalletBalanceClean(benchmark::Bench& bench) { WalletBalance(bench, /
static void WalletBalanceMine(benchmark::Bench& bench) { WalletBalance(bench, /*set_dirty=*/false, /*add_mine=*/true); }
static void WalletBalanceWatch(benchmark::Bench& bench) { WalletBalance(bench, /*set_dirty=*/false, /*add_mine=*/false); }
-BENCHMARK(WalletBalanceDirty);
-BENCHMARK(WalletBalanceClean);
-BENCHMARK(WalletBalanceMine);
-BENCHMARK(WalletBalanceWatch);
+BENCHMARK(WalletBalanceDirty, benchmark::PriorityLevel::HIGH);
+BENCHMARK(WalletBalanceClean, benchmark::PriorityLevel::HIGH);
+BENCHMARK(WalletBalanceMine, benchmark::PriorityLevel::HIGH);
+BENCHMARK(WalletBalanceWatch, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/wallet_create_tx.cpp b/src/bench/wallet_create_tx.cpp
new file mode 100644
index 0000000000..bd32a5abdc
--- /dev/null
+++ b/src/bench/wallet_create_tx.cpp
@@ -0,0 +1,183 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or https://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+#include <chainparams.h>
+#include <wallet/coincontrol.h>
+#include <consensus/merkle.h>
+#include <kernel/chain.h>
+#include <node/context.h>
+#include <test/util/setup_common.h>
+#include <validation.h>
+#include <wallet/spend.h>
+#include <wallet/test/util.h>
+#include <wallet/wallet.h>
+
+using wallet::CWallet;
+using wallet::CreateMockWalletDatabase;
+using wallet::DBErrors;
+using wallet::WALLET_FLAG_DESCRIPTORS;
+
+struct TipBlock
+{
+ uint256 prev_block_hash;
+ int64_t prev_block_time;
+ int tip_height;
+};
+
+TipBlock getTip(const CChainParams& params, const node::NodeContext& context)
+{
+ auto tip = WITH_LOCK(::cs_main, return context.chainman->ActiveTip());
+ return (tip) ? TipBlock{tip->GetBlockHash(), tip->GetBlockTime(), tip->nHeight} :
+ TipBlock{params.GenesisBlock().GetHash(), params.GenesisBlock().GetBlockTime(), 0};
+}
+
+void generateFakeBlock(const CChainParams& params,
+ const node::NodeContext& context,
+ CWallet& wallet,
+ const CScript& coinbase_out_script)
+{
+ TipBlock tip{getTip(params, context)};
+
+ // Create block
+ CBlock block;
+ CMutableTransaction coinbase_tx;
+ coinbase_tx.vin.resize(1);
+ coinbase_tx.vin[0].prevout.SetNull();
+ coinbase_tx.vout.resize(2);
+ coinbase_tx.vout[0].scriptPubKey = coinbase_out_script;
+ coinbase_tx.vout[0].nValue = 49 * COIN;
+ coinbase_tx.vin[0].scriptSig = CScript() << ++tip.tip_height << OP_0;
+ coinbase_tx.vout[1].scriptPubKey = coinbase_out_script; // extra output
+ coinbase_tx.vout[1].nValue = 1 * COIN;
+ block.vtx = {MakeTransactionRef(std::move(coinbase_tx))};
+
+ block.nVersion = VERSIONBITS_LAST_OLD_BLOCK_VERSION;
+ block.hashPrevBlock = tip.prev_block_hash;
+ block.hashMerkleRoot = BlockMerkleRoot(block);
+ block.nTime = ++tip.prev_block_time;
+ block.nBits = params.GenesisBlock().nBits;
+ block.nNonce = 0;
+
+ {
+ LOCK(::cs_main);
+ // Add it to the index
+ CBlockIndex* pindex{context.chainman->m_blockman.AddToBlockIndex(block, context.chainman->m_best_header)};
+ // add it to the chain
+ context.chainman->ActiveChain().SetTip(*pindex);
+ }
+
+ // notify wallet
+ const auto& pindex = WITH_LOCK(::cs_main, return context.chainman->ActiveChain().Tip());
+ wallet.blockConnected(kernel::MakeBlockInfo(pindex, &block));
+}
+
+struct PreSelectInputs {
+ // How many coins from the wallet the process should select
+ int num_of_internal_inputs;
+ // future: this could have external inputs as well.
+};
+
+static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type, bool allow_other_inputs, std::optional<PreSelectInputs> preset_inputs)
+{
+ const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
+
+ CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockWalletDatabase()};
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet.SetupDescriptorScriptPubKeyMans();
+ if (wallet.LoadWallet() != DBErrors::LOAD_OK) assert(false);
+ }
+
+ // Generate destinations
+ CScript dest = GetScriptForDestination(getNewDestination(wallet, output_type));
+
+ // Generate chain; each coinbase will have two outputs to fill-up the wallet
+ const auto& params = Params();
+ unsigned int chain_size = 5000; // 5k blocks means 10k UTXO for the wallet (minus 200 due COINBASE_MATURITY)
+ for (unsigned int i = 0; i < chain_size; ++i) {
+ generateFakeBlock(params, test_setup->m_node, wallet, dest);
+ }
+
+ // Check available balance
+ auto bal = wallet::GetAvailableBalance(wallet); // Cache
+ assert(bal == 50 * COIN * (chain_size - COINBASE_MATURITY));
+
+ wallet::CCoinControl coin_control;
+ coin_control.m_allow_other_inputs = allow_other_inputs;
+
+ CAmount target = 0;
+ if (preset_inputs) {
+ // Select inputs, each has 49 BTC
+ wallet::CoinFilterParams filter_coins;
+ filter_coins.max_count = preset_inputs->num_of_internal_inputs;
+ const auto& res = WITH_LOCK(wallet.cs_wallet,
+ return wallet::AvailableCoins(wallet, /*coinControl=*/nullptr, /*feerate=*/std::nullopt, filter_coins));
+ for (int i=0; i < preset_inputs->num_of_internal_inputs; i++) {
+ const auto& coin{res.coins.at(output_type)[i]};
+ target += coin.txout.nValue;
+ coin_control.Select(coin.outpoint);
+ }
+ }
+
+ // If automatic coin selection is enabled, add the value of another UTXO to the target
+ if (coin_control.m_allow_other_inputs) target += 50 * COIN;
+ std::vector<wallet::CRecipient> recipients = {{dest, target, true}};
+
+ bench.epochIterations(5).run([&] {
+ LOCK(wallet.cs_wallet);
+ const auto& tx_res = CreateTransaction(wallet, recipients, -1, coin_control);
+ assert(tx_res);
+ });
+}
+
+static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType>& output_type)
+{
+ const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
+ CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockWalletDatabase()};
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet.SetupDescriptorScriptPubKeyMans();
+ if (wallet.LoadWallet() != DBErrors::LOAD_OK) assert(false);
+ }
+
+ // Generate destinations
+ std::vector<CScript> dest_wallet;
+ for (auto type : output_type) {
+ dest_wallet.emplace_back(GetScriptForDestination(getNewDestination(wallet, type)));
+ }
+
+ // Generate chain; each coinbase will have two outputs to fill-up the wallet
+ const auto& params = Params();
+ unsigned int chain_size = 1000;
+ for (unsigned int i = 0; i < chain_size / dest_wallet.size(); ++i) {
+ for (const auto& dest : dest_wallet) {
+ generateFakeBlock(params, test_setup->m_node, wallet, dest);
+ }
+ }
+
+ // Check available balance
+ auto bal = wallet::GetAvailableBalance(wallet); // Cache
+ assert(bal == 50 * COIN * (chain_size - COINBASE_MATURITY));
+
+ bench.epochIterations(2).run([&] {
+ LOCK(wallet.cs_wallet);
+ const auto& res = wallet::AvailableCoins(wallet);
+ assert(res.All().size() == (chain_size - COINBASE_MATURITY) * 2);
+ });
+}
+
+static void WalletCreateTxUseOnlyPresetInputs(benchmark::Bench& bench) { WalletCreateTx(bench, OutputType::BECH32, /*allow_other_inputs=*/false,
+ {{/*num_of_internal_inputs=*/4}}); }
+
+static void WalletCreateTxUsePresetInputsAndCoinSelection(benchmark::Bench& bench) { WalletCreateTx(bench, OutputType::BECH32, /*allow_other_inputs=*/true,
+ {{/*num_of_internal_inputs=*/4}}); }
+
+static void WalletAvailableCoins(benchmark::Bench& bench) { AvailableCoins(bench, {OutputType::BECH32M}); }
+
+BENCHMARK(WalletCreateTxUseOnlyPresetInputs, benchmark::PriorityLevel::LOW)
+BENCHMARK(WalletCreateTxUsePresetInputsAndCoinSelection, benchmark::PriorityLevel::LOW)
+BENCHMARK(WalletAvailableCoins, benchmark::PriorityLevel::LOW); \ No newline at end of file
diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp
index 27e4dd015d..6b09adcc9d 100644
--- a/src/bench/wallet_loading.cpp
+++ b/src/bench/wallet_loading.cpp
@@ -7,7 +7,7 @@
#include <node/context.h>
#include <test/util/mining.h>
#include <test/util/setup_common.h>
-#include <test/util/wallet.h>
+#include <wallet/test/util.h>
#include <util/translation.h>
#include <validationinterface.h>
#include <wallet/context.h>
@@ -24,7 +24,7 @@ using wallet::WALLET_FLAG_DESCRIPTORS;
using wallet::WalletContext;
using wallet::WalletDatabase;
-static const std::shared_ptr<CWallet> BenchLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, DatabaseOptions& options)
+static std::shared_ptr<CWallet> BenchLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, DatabaseOptions& options)
{
bilingual_str error;
std::vector<bilingual_str> warnings;
@@ -52,30 +52,6 @@ static void AddTx(CWallet& wallet)
wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInactive{});
}
-static std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database, DatabaseOptions& options)
-{
- auto new_database = CreateMockWalletDatabase(options);
-
- // Get a cursor to the original database
- auto batch = database.MakeBatch();
- batch->StartCursor();
-
- // Get a batch for the new database
- auto new_batch = new_database->MakeBatch();
-
- // Read all records from the original database and write them to the new one
- while (true) {
- CDataStream key(SER_DISK, CLIENT_VERSION);
- CDataStream value(SER_DISK, CLIENT_VERSION);
- bool complete;
- batch->ReadAtCursor(key, value, complete);
- if (complete) break;
- new_batch->Write(key, value);
- }
-
- return new_database;
-}
-
static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet)
{
const auto test_setup = MakeNoLogFileContext<TestingSetup>();
@@ -118,10 +94,10 @@ static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet)
#ifdef USE_BDB
static void WalletLoadingLegacy(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/true); }
-BENCHMARK(WalletLoadingLegacy);
+BENCHMARK(WalletLoadingLegacy, benchmark::PriorityLevel::HIGH);
#endif
#ifdef USE_SQLITE
static void WalletLoadingDescriptors(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/false); }
-BENCHMARK(WalletLoadingDescriptors);
+BENCHMARK(WalletLoadingDescriptors, benchmark::PriorityLevel::HIGH);
#endif
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index d972b71a65..abe3af70c3 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -11,6 +11,7 @@
//
// It is part of the libbitcoinkernel project.
+#include <kernel/chainparams.h>
#include <kernel/checks.h>
#include <kernel/context.h>
#include <kernel/validation_cache_sizes.h>
@@ -52,7 +53,7 @@ int main(int argc, char* argv[])
// SETUP: Misc Globals
SelectParams(CBaseChainParams::MAIN);
- const CChainParams& chainparams = Params();
+ auto chainparams = CChainParams::Main();
kernel::Context kernel_context{};
// We can't use a goto here, but we can use an assert since none of the
@@ -81,10 +82,11 @@ int main(int argc, char* argv[])
// SETUP: Chainstate
const ChainstateManager::Options chainman_opts{
- .chainparams = chainparams,
+ .chainparams = *chainparams,
+ .datadir = gArgs.GetDataDirNet(),
.adjusted_time_callback = NodeClock::now,
};
- ChainstateManager chainman{chainman_opts};
+ ChainstateManager chainman{chainman_opts, {}};
node::CacheSizes cache_sizes;
cache_sizes.block_tree_db = 2 << 20;
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index e64e2202ba..eb52b30ae4 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,6 +9,7 @@
#include <chainparamsbase.h>
#include <clientversion.h>
+#include <common/url.h>
#include <compat/compat.h>
#include <compat/stdin.h>
#include <policy/feerate.h>
@@ -18,10 +19,10 @@
#include <rpc/request.h>
#include <tinyformat.h>
#include <univalue.h>
+#include <util/exception.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/translation.h>
-#include <util/url.h>
#include <algorithm>
#include <chrono>
@@ -55,7 +56,10 @@ static constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT = 0;
static const bool DEFAULT_NAMED=false;
static const int CONTINUE_EXECUTION=-1;
static constexpr int8_t UNKNOWN_NETWORK{-1};
-static constexpr std::array NETWORKS{"ipv4", "ipv6", "onion", "i2p", "cjdns"};
+// See GetNetworkName() in netbase.cpp
+static constexpr std::array NETWORKS{"not_publicly_routable", "ipv4", "ipv6", "onion", "i2p", "cjdns", "internal"};
+static constexpr std::array NETWORK_SHORT_NAMES{"npr", "ipv4", "ipv6", "onion", "i2p", "cjdns", "int"};
+static constexpr std::array UNREACHABLE_NETWORK_IDS{/*not_publicly_routable*/0, /*internal*/6};
/** Default number of blocks to generate for RPC generatetoaddress. */
static const std::string DEFAULT_NBLOCKS = "1";
@@ -82,7 +86,7 @@ static void SetupCliArgs(ArgsManager& argsman)
DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES),
ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total, after filtering for quality and recency. The total number of addresses known to the node may be higher.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the output of -getinfo is the result of multiple non-atomic requests. Some entries in the output may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
SetupChainParamsBaseOptions(argsman);
@@ -158,7 +162,7 @@ static int AppInitRPC(int argc, char* argv[])
}
return EXIT_SUCCESS;
}
- if (!CheckDataDirOption()) {
+ if (!CheckDataDirOption(gArgs)) {
tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""));
return EXIT_FAILURE;
}
@@ -289,7 +293,7 @@ public:
// Prepare result to return to user.
UniValue result{UniValue::VOBJ}, addresses{UniValue::VOBJ};
uint64_t total{0}; // Total address count
- for (size_t i = 0; i < NETWORKS.size(); ++i) {
+ for (size_t i = 1; i < NETWORKS.size() - 1; ++i) {
addresses.pushKV(NETWORKS[i], counts.at(i));
total += counts.at(i);
}
@@ -506,7 +510,7 @@ public:
const bool is_addr_relay_enabled{peer["addr_relay_enabled"].isNull() ? false : peer["addr_relay_enabled"].get_bool()};
const bool is_bip152_hb_from{peer["bip152_hb_from"].get_bool()};
const bool is_bip152_hb_to{peer["bip152_hb_to"].get_bool()};
- m_peers.push_back({addr, sub_version, conn_type, network, age, min_ping, ping, addr_processed, addr_rate_limited, last_blck, last_recv, last_send, last_trxn, peer_id, mapped_as, version, is_addr_relay_enabled, is_bip152_hb_from, is_bip152_hb_to, is_outbound, is_tx_relay});
+ m_peers.push_back({addr, sub_version, conn_type, NETWORK_SHORT_NAMES[network_id], age, min_ping, ping, addr_processed, addr_rate_limited, last_blck, last_recv, last_send, last_trxn, peer_id, mapped_as, version, is_addr_relay_enabled, is_bip152_hb_from, is_bip152_hb_to, is_outbound, is_tx_relay});
m_max_addr_length = std::max(addr.length() + 1, m_max_addr_length);
m_max_addr_processed_length = std::max(ToString(addr_processed).length(), m_max_addr_processed_length);
m_max_addr_rate_limited_length = std::max(ToString(addr_rate_limited).length(), m_max_addr_rate_limited_length);
@@ -571,6 +575,13 @@ public:
reachable_networks.push_back(network_id);
}
};
+
+ for (const size_t network_id : UNREACHABLE_NETWORK_IDS) {
+ if (m_counts.at(2).at(network_id) == 0) continue;
+ result += strprintf("%8s", NETWORK_SHORT_NAMES.at(network_id)); // column header
+ reachable_networks.push_back(network_id);
+ }
+
result += " total block";
if (m_manual_peers_count) result += " manual";
@@ -636,13 +647,13 @@ public:
" \"manual\" - peer we manually added using RPC addnode or the -addnode/-connect config options\n"
" \"feeler\" - short-lived connection for testing addresses\n"
" \"addr\" - address fetch; short-lived connection for requesting addresses\n"
- " net Network the peer connected through (\"ipv4\", \"ipv6\", \"onion\", \"i2p\", or \"cjdns\")\n"
+ " net Network the peer connected through (\"ipv4\", \"ipv6\", \"onion\", \"i2p\", \"cjdns\", or \"npr\" (not publicly routable))\n"
" mping Minimum observed ping time, in milliseconds (ms)\n"
" ping Last observed ping time, in milliseconds (ms)\n"
" send Time since last message sent to the peer, in seconds\n"
" recv Time since last message received from the peer, in seconds\n"
" txn Time since last novel transaction received from the peer and accepted into our mempool, in minutes\n"
- " \"*\" - the peer requested we not relay transactions to it (relaytxes is false)\n"
+ " \"*\" - we do not relay transactions to this peer (relaytxes is false)\n"
" blk Time since last novel block passing initial validity checks received from the peer, in minutes\n"
" hb High-bandwidth BIP152 compact block relay\n"
" \".\" (to) - we selected the peer as a high-bandwidth peer\n"
@@ -807,7 +818,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
if (failedToGetAuthCookie) {
throw std::runtime_error(strprintf(
"Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)",
- fs::PathToString(GetConfigFile(gArgs.GetPathArg("-conf", BITCOIN_CONF_FILENAME)))));
+ fs::PathToString(gArgs.GetConfigFilePath())));
} else {
throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
}
@@ -822,7 +833,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
UniValue valReply(UniValue::VSTR);
if (!valReply.read(response.body))
throw std::runtime_error("couldn't parse reply from server");
- const UniValue reply = rh->ProcessReply(valReply);
+ UniValue reply = rh->ProcessReply(valReply);
if (reply.empty())
throw std::runtime_error("expected reply to have result, error and id properties");
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 010cac5920..f36b6054bb 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,14 +12,15 @@
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <core_io.h>
-#include <key_io.h>
#include <fs.h>
+#include <key_io.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <univalue.h>
+#include <util/exception.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/strencodings.h>
@@ -681,8 +682,6 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
class Secp256k1Init
{
- ECCVerifyHandle globalVerifyHandle;
-
public:
Secp256k1Init() {
ECC_Start();
diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp
index fb184c0486..cf59ca9bff 100644
--- a/src/bitcoin-util.cpp
+++ b/src/bitcoin-util.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,6 +14,7 @@
#include <compat/compat.h>
#include <core_io.h>
#include <streams.h>
+#include <util/exception.h>
#include <util/system.h>
#include <util/translation.h>
#include <version.h>
@@ -82,13 +83,12 @@ static int AppInitUtil(ArgsManager& args, int argc, char* argv[])
return CONTINUE_EXECUTION;
}
-static void grind_task(uint32_t nBits, CBlockHeader& header_orig, uint32_t offset, uint32_t step, std::atomic<bool>& found)
+static void grind_task(uint32_t nBits, CBlockHeader header, uint32_t offset, uint32_t step, std::atomic<bool>& found, uint32_t& proposed_nonce)
{
arith_uint256 target;
bool neg, over;
target.SetCompact(nBits, &neg, &over);
if (target == 0 || neg || over) return;
- CBlockHeader header = header_orig; // working copy
header.nNonce = offset;
uint32_t finish = std::numeric_limits<uint32_t>::max() - step;
@@ -99,7 +99,7 @@ static void grind_task(uint32_t nBits, CBlockHeader& header_orig, uint32_t offse
do {
if (UintToArith256(header.GetHash()) <= target) {
if (!found.exchange(true)) {
- header_orig.nNonce = header.nNonce;
+ proposed_nonce = header.nNonce;
}
return;
}
@@ -123,21 +123,24 @@ static int Grind(const std::vector<std::string>& args, std::string& strPrint)
uint32_t nBits = header.nBits;
std::atomic<bool> found{false};
+ uint32_t proposed_nonce{};
std::vector<std::thread> threads;
int n_tasks = std::max(1u, std::thread::hardware_concurrency());
for (int i = 0; i < n_tasks; ++i) {
- threads.emplace_back( grind_task, nBits, std::ref(header), i, n_tasks, std::ref(found) );
+ threads.emplace_back(grind_task, nBits, header, i, n_tasks, std::ref(found), std::ref(proposed_nonce));
}
for (auto& t : threads) {
t.join();
}
- if (!found) {
+ if (found) {
+ header.nNonce = proposed_nonce;
+ } else {
strPrint = "Could not satisfy difficulty target";
return EXIT_FAILURE;
}
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ss{};
ss << header;
strPrint = HexStr(ss);
return EXIT_SUCCESS;
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index d556300ee2..1ebe98b920 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,15 +9,16 @@
#include <chainparams.h>
#include <chainparamsbase.h>
#include <clientversion.h>
+#include <common/url.h>
#include <compat/compat.h>
#include <interfaces/init.h>
#include <key.h>
#include <logging.h>
#include <pubkey.h>
#include <tinyformat.h>
+#include <util/exception.h>
#include <util/system.h>
#include <util/translation.h>
-#include <util/url.h>
#include <wallet/wallettool.h>
#include <exception>
@@ -84,7 +85,7 @@ static std::optional<int> WalletAppInit(ArgsManager& args, int argc, char* argv[
// check for printtoconsole, allow -debug
LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", args.GetBoolArg("-debug", false));
- if (!CheckDataDirOption()) {
+ if (!CheckDataDirOption(args)) {
tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", args.GetArg("-datadir", ""));
return EXIT_FAILURE;
}
@@ -130,7 +131,6 @@ MAIN_FUNCTION
return EXIT_FAILURE;
}
- ECCVerifyHandle globalVerifyHandle;
ECC_Start();
if (!wallet::WalletTool::ExecuteWalletToolFunc(args, command->command)) {
return EXIT_FAILURE;
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 9f81640ddb..2ff34125e1 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,6 +9,8 @@
#include <chainparams.h>
#include <clientversion.h>
+#include <common/init.h>
+#include <common/url.h>
#include <compat/compat.h>
#include <init.h>
#include <interfaces/chain.h>
@@ -18,6 +20,7 @@
#include <noui.h>
#include <shutdown.h>
#include <util/check.h>
+#include <util/exception.h>
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
#include <util/syserror.h>
@@ -25,7 +28,6 @@
#include <util/threadnames.h>
#include <util/tokenpipe.h>
#include <util/translation.h>
-#include <util/url.h>
#include <any>
#include <functional>
@@ -120,7 +122,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
SetupServerArgs(args);
std::string error;
if (!args.ParseParameters(argc, argv, error)) {
- return InitError(Untranslated(strprintf("Error parsing command line arguments: %s\n", error)));
+ return InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error)));
}
// Process help and version before taking care about datadir
@@ -150,31 +152,17 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
std::any context{&node};
try
{
- if (!CheckDataDirOption()) {
- return InitError(Untranslated(strprintf("Specified data directory \"%s\" does not exist.\n", args.GetArg("-datadir", ""))));
- }
- if (!args.ReadConfigFiles(error, true)) {
- return InitError(Untranslated(strprintf("Error reading configuration file: %s\n", error)));
- }
- // Check for chain settings (Params() calls are only valid after this clause)
- try {
- SelectParams(args.GetChainName());
- } catch (const std::exception& e) {
- return InitError(Untranslated(strprintf("%s\n", e.what())));
+ if (auto error = common::InitConfig(args)) {
+ return InitError(error->message, error->details);
}
// Error out when loose non-argument tokens are encountered on command line
for (int i = 1; i < argc; i++) {
if (!IsSwitchChar(argv[i][0])) {
- return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i])));
+ return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.", argv[i])));
}
}
- if (!args.InitSettings(error)) {
- InitError(Untranslated(error));
- return false;
- }
-
// -server defaults to true for bitcoind but not for the GUI so do this here
args.SoftSetBoolArg("-server", true);
// Set this early so that parameter interactions go to console
@@ -210,7 +198,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
}
break;
case -1: // Error happened.
- return InitError(Untranslated(strprintf("fork_daemon() failed: %s\n", SysErrorString(errno))));
+ return InitError(Untranslated(strprintf("fork_daemon() failed: %s", SysErrorString(errno))));
default: { // Parent: wait and exit.
int token = daemon_ep.TokenRead();
if (token) { // Success
@@ -222,7 +210,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
}
}
#else
- return InitError(Untranslated("-daemon is not supported on this operating system\n"));
+ return InitError(Untranslated("-daemon is not supported on this operating system"));
#endif // HAVE_DECL_FORK
}
// Lock data directory after daemonization
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index f96353510f..a29e4f794e 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2020 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -29,7 +29,7 @@ CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block) :
}
void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << header << nonce;
CSHA256 hasher;
hasher.Write((unsigned char*)&(*stream.begin()), stream.end() - stream.begin());
@@ -52,7 +52,8 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_WEIGHT / MIN_SERIALIZABLE_TRANSACTION_WEIGHT)
return READ_STATUS_INVALID;
- assert(header.IsNull() && txn_available.empty());
+ if (!header.IsNull() || !txn_available.empty()) return READ_STATUS_INVALID;
+
header = cmpctblock.header;
txn_available.resize(cmpctblock.BlockTxCount());
@@ -167,14 +168,18 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
return READ_STATUS_OK;
}
-bool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const {
- assert(!header.IsNull());
+bool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const
+{
+ if (header.IsNull()) return false;
+
assert(index < txn_available.size());
return txn_available[index] != nullptr;
}
-ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing) {
- assert(!header.IsNull());
+ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing)
+{
+ if (header.IsNull()) return READ_STATUS_INVALID;
+
uint256 hash = header.GetHash();
block = header;
block.vtx.resize(txn_available.size());
@@ -197,7 +202,8 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
return READ_STATUS_INVALID;
BlockValidationState state;
- if (!CheckBlock(block, state, Params().GetConsensus())) {
+ CheckBlockFn check_block = m_check_block_mock ? m_check_block_mock : CheckBlock;
+ if (!check_block(block, state, Params().GetConsensus(), /*fCheckPoW=*/true, /*fCheckMerkleRoot=*/true)) {
// TODO: We really want to just check merkle tree manually here,
// but that is expensive, and CheckBlock caches a block's
// "checked-status" (in the CBlock?). CBlock should be able to
diff --git a/src/blockencodings.h b/src/blockencodings.h
index 67c4e57156..afdfa426f1 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2020 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,8 +7,13 @@
#include <primitives/block.h>
+#include <functional>
class CTxMemPool;
+class BlockValidationState;
+namespace Consensus {
+struct Params;
+};
// Transaction compression schemes for compact block relay can be introduced by writing
// an actual formatter here.
@@ -129,6 +134,11 @@ protected:
const CTxMemPool* pool;
public:
CBlockHeader header;
+
+ // Can be overridden for testing
+ using CheckBlockFn = std::function<bool(const CBlock&, BlockValidationState&, const Consensus::Params&, bool, bool)>;
+ CheckBlockFn m_check_block_mock{nullptr};
+
explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
// extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 85929747be..88c7526b9e 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -247,21 +247,10 @@ bool BlockFilter::BuildParams(GCSFilter::Params& params) const
uint256 BlockFilter::GetHash() const
{
- const std::vector<unsigned char>& data = GetEncodedFilter();
-
- uint256 result;
- CHash256().Write(data).Finalize(result);
- return result;
+ return Hash(GetEncodedFilter());
}
uint256 BlockFilter::ComputeHeader(const uint256& prev_header) const
{
- const uint256& filter_hash = GetHash();
-
- uint256 result;
- CHash256()
- .Write(filter_hash)
- .Write(prev_header)
- .Finalize(result);
- return result;
+ return Hash(GetHash(), prev_header);
}
diff --git a/src/blockfilter.h b/src/blockfilter.h
index 0cb627d9df..fb5114edb3 100644
--- a/src/blockfilter.h
+++ b/src/blockfilter.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/chain.cpp b/src/chain.cpp
index 66a0830394..82007a8a1e 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/chain.h b/src/chain.h
index 2d3b084b9b..f5dd0fd315 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,6 +9,7 @@
#include <arith_uint256.h>
#include <consensus/params.h>
#include <flatfile.h>
+#include <kernel/cs_main.h>
#include <primitives/block.h>
#include <sync.h>
#include <uint256.h>
@@ -38,8 +39,6 @@ static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
*/
static constexpr int64_t MAX_BLOCK_TIME_GAP = 90 * 60;
-extern RecursiveMutex cs_main;
-
class CBlockFileInfo
{
public:
@@ -213,10 +212,6 @@ public:
//! (memory only) Maximum nTime in the chain up to and including this block.
unsigned int nTimeMax{0};
- CBlockIndex()
- {
- }
-
explicit CBlockIndex(const CBlockHeader& block)
: nVersion{block.nVersion},
hashMerkleRoot{block.hashMerkleRoot},
@@ -355,6 +350,24 @@ public:
//! Efficiently find an ancestor of this block.
CBlockIndex* GetAncestor(int height);
const CBlockIndex* GetAncestor(int height) const;
+
+ CBlockIndex() = default;
+ ~CBlockIndex() = default;
+
+protected:
+ //! CBlockIndex should not allow public copy construction because equality
+ //! comparison via pointer is very common throughout the codebase, making
+ //! use of copy a footgun. Also, use of copies do not have the benefit
+ //! of simplifying lifetime considerations due to attributes like pprev and
+ //! pskip, which are at risk of becoming dangling pointers in a copied
+ //! instance.
+ //!
+ //! We declare these protected instead of simply deleting them so that
+ //! CDiskBlockIndex can reuse copy construction.
+ CBlockIndex(const CBlockIndex&) = default;
+ CBlockIndex& operator=(const CBlockIndex&) = delete;
+ CBlockIndex(CBlockIndex&&) = delete;
+ CBlockIndex& operator=(CBlockIndex&&) = delete;
};
arith_uint256 GetBlockProof(const CBlockIndex& block);
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index c6d4eee7b9..6f48ee41b3 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,513 +15,43 @@
#include <assert.h>
-static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
+void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& options)
{
- CMutableTransaction txNew;
- txNew.nVersion = 1;
- txNew.vin.resize(1);
- txNew.vout.resize(1);
- txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
- txNew.vout[0].nValue = genesisReward;
- txNew.vout[0].scriptPubKey = genesisOutputScript;
-
- CBlock genesis;
- genesis.nTime = nTime;
- genesis.nBits = nBits;
- genesis.nNonce = nNonce;
- genesis.nVersion = nVersion;
- genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));
- genesis.hashPrevBlock.SetNull();
- genesis.hashMerkleRoot = BlockMerkleRoot(genesis);
- return genesis;
-}
-
-/**
- * Build the genesis block. Note that the output of its generation
- * transaction cannot be spent since it did not originally exist in the
- * database.
- *
- * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
- * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
- * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
- * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
- * vMerkleTree: 4a5e1e
- */
-static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
-{
- const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
- const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
- return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
-}
-
-/**
- * Main network on which people trade goods and services.
- */
-class CMainParams : public CChainParams {
-public:
- CMainParams() {
- strNetworkID = CBaseChainParams::MAIN;
- consensus.signet_blocks = false;
- consensus.signet_challenge.clear();
- consensus.nSubsidyHalvingInterval = 210000;
- consensus.script_flag_exceptions.emplace( // BIP16 exception
- uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22"), SCRIPT_VERIFY_NONE);
- consensus.script_flag_exceptions.emplace( // Taproot exception
- uint256S("0x0000000000000000000f14c35b2d841e986ab5441de8c585d5ffe55ea1e395ad"), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS);
- consensus.BIP34Height = 227931;
- consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
- consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
- consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
- consensus.CSVHeight = 419328; // 000000000000000004a1b34462cb8aeebd5799177f7a29cf28f2d1961716b5b5
- consensus.SegwitHeight = 481824; // 0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893
- consensus.MinBIP9WarningHeight = 483840; // segwit activation height + miner confirmation window
- consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
- consensus.nPowTargetSpacing = 10 * 60;
- consensus.fPowAllowMinDifficultyBlocks = false;
- consensus.fPowNoRetargeting = false;
- consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016
- consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
-
- // Deployment of Taproot (BIPs 340-342)
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021
-
- consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000003404ba0801921119f903495e");
- consensus.defaultAssumeValid = uint256S("0x00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd"); // 751565
-
- /**
- * The message start string is designed to be unlikely to occur in normal data.
- * The characters are rarely used upper ASCII, not valid as UTF-8, and produce
- * a large 32-bit integer with any alignment.
- */
- pchMessageStart[0] = 0xf9;
- pchMessageStart[1] = 0xbe;
- pchMessageStart[2] = 0xb4;
- pchMessageStart[3] = 0xd9;
- nDefaultPort = 8333;
- nPruneAfterHeight = 100000;
- m_assumed_blockchain_size = 496;
- m_assumed_chain_state_size = 6;
-
- genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
- consensus.hashGenesisBlock = genesis.GetHash();
- assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
-
- // Note that of those which support the service bits prefix, most only support a subset of
- // possible options.
- // This is fine at runtime as we'll fall back to using them as an addrfetch if they don't support the
- // service bits we want, but we should get them updated to support all service bits wanted by any
- // release ASAP to avoid it where possible.
- vSeeds.emplace_back("seed.bitcoin.sipa.be."); // Pieter Wuille, only supports x1, x5, x9, and xd
- vSeeds.emplace_back("dnsseed.bluematt.me."); // Matt Corallo, only supports x9
- vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org."); // Luke Dashjr
- vSeeds.emplace_back("seed.bitcoinstats.com."); // Christian Decker, supports x1 - xf
- 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
- vSeeds.emplace_back("seed.bitcoin.wiz.biz."); // Jason Maurice
-
- base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
- base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
- base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
- base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
- base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
-
- bech32_hrp = "bc";
-
- vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_main), std::end(chainparams_seed_main));
-
- fDefaultConsistencyChecks = false;
- fRequireStandard = true;
- m_is_test_chain = false;
- m_is_mockable_chain = false;
-
- checkpointData = {
- {
- { 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")},
- { 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")},
- { 74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")},
- {105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")},
- {134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")},
- {168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")},
- {193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")},
- {210000, uint256S("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")},
- {216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")},
- {225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")},
- {250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")},
- {279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")},
- {295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")},
- }
- };
-
- m_assumeutxo_data = MapAssumeutxo{
- // TODO to be specified in a future patch.
- };
-
- chainTxData = ChainTxData{
- // Data from RPC: getchaintxstats 4096 00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd
- .nTime = 1661697692,
- .nTxCount = 760120522,
- .dTxRate = 2.925802860942233,
- };
- }
-};
-
-/**
- * Testnet (v3): public test network which is reset from time to time.
- */
-class CTestNetParams : public CChainParams {
-public:
- CTestNetParams() {
- strNetworkID = CBaseChainParams::TESTNET;
- consensus.signet_blocks = false;
- consensus.signet_challenge.clear();
- consensus.nSubsidyHalvingInterval = 210000;
- consensus.script_flag_exceptions.emplace( // BIP16 exception
- uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105"), SCRIPT_VERIFY_NONE);
- consensus.BIP34Height = 21111;
- consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
- consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
- consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
- consensus.CSVHeight = 770112; // 00000000025e930139bac5c6c31a403776da130831ab85be56578f3fa75369bb
- consensus.SegwitHeight = 834624; // 00000000002b980fcd729daaa248fd9316a5200e9b367f4ff2c42453e84201ca
- consensus.MinBIP9WarningHeight = 836640; // segwit activation height + miner confirmation window
- consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
- consensus.nPowTargetSpacing = 10 * 60;
- consensus.fPowAllowMinDifficultyBlocks = true;
- consensus.fPowNoRetargeting = false;
- consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
- consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
-
- // Deployment of Taproot (BIPs 340-342)
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
-
- consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000076f6e7cbd0beade5d20");
- consensus.defaultAssumeValid = uint256S("0x0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060"); // 2344474
-
- pchMessageStart[0] = 0x0b;
- pchMessageStart[1] = 0x11;
- pchMessageStart[2] = 0x09;
- pchMessageStart[3] = 0x07;
- nDefaultPort = 18333;
- nPruneAfterHeight = 1000;
- m_assumed_blockchain_size = 42;
- m_assumed_chain_state_size = 2;
-
- genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
- consensus.hashGenesisBlock = genesis.GetHash();
- assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
-
- vFixedSeeds.clear();
- vSeeds.clear();
- // nodes with support for servicebits filtering should be at the top
- vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch.");
- vSeeds.emplace_back("seed.tbtc.petertodd.org.");
- vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl.");
- vSeeds.emplace_back("testnet-seed.bluematt.me."); // Just a static list of stable node(s), only supports x9
-
- base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
- base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
- base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
- base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
- base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
-
- bech32_hrp = "tb";
-
- vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_test), std::end(chainparams_seed_test));
-
- fDefaultConsistencyChecks = false;
- fRequireStandard = false;
- m_is_test_chain = true;
- m_is_mockable_chain = false;
-
- checkpointData = {
- {
- {546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")},
- }
- };
-
- m_assumeutxo_data = MapAssumeutxo{
- // TODO to be specified in a future patch.
- };
-
- chainTxData = ChainTxData{
- // Data from RPC: getchaintxstats 4096 0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060
- .nTime = 1661705221,
- .nTxCount = 63531852,
- .dTxRate = 0.1079119341520164,
- };
+ if (args.IsArgSet("-signetseednode")) {
+ options.seeds.emplace(args.GetArgs("-signetseednode"));
}
-};
-
-/**
- * Signet: test network with an additional consensus parameter (see BIP325).
- */
-class SigNetParams : public CChainParams {
-public:
- explicit SigNetParams(const ArgsManager& args) {
- std::vector<uint8_t> bin;
- vSeeds.clear();
-
- if (!args.IsArgSet("-signetchallenge")) {
- bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae");
- vSeeds.emplace_back("seed.signet.bitcoin.sprovoost.nl.");
-
- // Hardcoded nodes can be removed once there are more DNS seeds
- vSeeds.emplace_back("178.128.221.177");
- vSeeds.emplace_back("v7ajjeirttkbnt32wpy3c6w3emwnfr3fkla7hpxcfokr3ysd3kqtzmqd.onion:38333");
-
- consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000001291fc22898");
- consensus.defaultAssumeValid = uint256S("0x000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09"); // 105495
- m_assumed_blockchain_size = 1;
- m_assumed_chain_state_size = 0;
- chainTxData = ChainTxData{
- // Data from RPC: getchaintxstats 4096 000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09
- .nTime = 1661702566,
- .nTxCount = 1903567,
- .dTxRate = 0.02336701143027275,
- };
- } else {
- const auto signet_challenge = args.GetArgs("-signetchallenge");
- if (signet_challenge.size() != 1) {
- throw std::runtime_error(strprintf("%s: -signetchallenge cannot be multiple values.", __func__));
- }
- bin = ParseHex(signet_challenge[0]);
-
- consensus.nMinimumChainWork = uint256{};
- consensus.defaultAssumeValid = uint256{};
- m_assumed_blockchain_size = 0;
- m_assumed_chain_state_size = 0;
- chainTxData = ChainTxData{
- 0,
- 0,
- 0,
- };
- LogPrintf("Signet with challenge %s\n", signet_challenge[0]);
- }
-
- if (args.IsArgSet("-signetseednode")) {
- vSeeds = args.GetArgs("-signetseednode");
+ if (args.IsArgSet("-signetchallenge")) {
+ const auto signet_challenge = args.GetArgs("-signetchallenge");
+ if (signet_challenge.size() != 1) {
+ throw std::runtime_error(strprintf("%s: -signetchallenge cannot be multiple values.", __func__));
}
-
- strNetworkID = CBaseChainParams::SIGNET;
- consensus.signet_blocks = true;
- consensus.signet_challenge.assign(bin.begin(), bin.end());
- consensus.nSubsidyHalvingInterval = 210000;
- consensus.BIP34Height = 1;
- consensus.BIP34Hash = uint256{};
- consensus.BIP65Height = 1;
- consensus.BIP66Height = 1;
- consensus.CSVHeight = 1;
- consensus.SegwitHeight = 1;
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
- consensus.nPowTargetSpacing = 10 * 60;
- consensus.fPowAllowMinDifficultyBlocks = false;
- consensus.fPowNoRetargeting = false;
- consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016
- consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
- consensus.MinBIP9WarningHeight = 0;
- consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
-
- // Activation of Taproot (BIPs 340-342)
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
-
- // message start is defined as the first 4 bytes of the sha256d of the block script
- HashWriter h{};
- h << consensus.signet_challenge;
- uint256 hash = h.GetHash();
- memcpy(pchMessageStart, hash.begin(), 4);
-
- nDefaultPort = 38333;
- nPruneAfterHeight = 1000;
-
- genesis = CreateGenesisBlock(1598918400, 52613770, 0x1e0377ae, 1, 50 * COIN);
- consensus.hashGenesisBlock = genesis.GetHash();
- assert(consensus.hashGenesisBlock == uint256S("0x00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"));
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
-
- vFixedSeeds.clear();
-
- base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
- base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
- base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
- base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
- base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
-
- bech32_hrp = "tb";
-
- fDefaultConsistencyChecks = false;
- fRequireStandard = true;
- m_is_test_chain = true;
- m_is_mockable_chain = false;
+ options.challenge.emplace(ParseHex(signet_challenge[0]));
}
-};
-
-/**
- * Regression test: intended for private networks only. Has minimal difficulty to ensure that
- * blocks can be found instantly.
- */
-class CRegTestParams : public CChainParams {
-public:
- explicit CRegTestParams(const ArgsManager& args) {
- strNetworkID = CBaseChainParams::REGTEST;
- consensus.signet_blocks = false;
- consensus.signet_challenge.clear();
- consensus.nSubsidyHalvingInterval = 150;
- consensus.BIP34Height = 1; // Always active unless overridden
- consensus.BIP34Hash = uint256();
- consensus.BIP65Height = 1; // Always active unless overridden
- consensus.BIP66Height = 1; // Always active unless overridden
- consensus.CSVHeight = 1; // Always active unless overridden
- consensus.SegwitHeight = 0; // Always active unless overridden
- consensus.MinBIP9WarningHeight = 0;
- consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
- consensus.nPowTargetSpacing = 10 * 60;
- consensus.fPowAllowMinDifficultyBlocks = true;
- consensus.fPowNoRetargeting = true;
- consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
- consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
-
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
-
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
-
- consensus.nMinimumChainWork = uint256{};
- consensus.defaultAssumeValid = uint256{};
-
- pchMessageStart[0] = 0xfa;
- pchMessageStart[1] = 0xbf;
- pchMessageStart[2] = 0xb5;
- pchMessageStart[3] = 0xda;
- nDefaultPort = 18444;
- nPruneAfterHeight = args.GetBoolArg("-fastprune", false) ? 100 : 1000;
- m_assumed_blockchain_size = 0;
- m_assumed_chain_state_size = 0;
-
- UpdateActivationParametersFromArgs(args);
-
- genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
- consensus.hashGenesisBlock = genesis.GetHash();
- assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
-
- vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
- vSeeds.clear();
- vSeeds.emplace_back("dummySeed.invalid.");
-
- fDefaultConsistencyChecks = true;
- fRequireStandard = true;
- m_is_test_chain = true;
- m_is_mockable_chain = true;
-
- checkpointData = {
- {
- {0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")},
- }
- };
-
- m_assumeutxo_data = MapAssumeutxo{
- {
- 110,
- {AssumeutxoHash{uint256S("0x1ebbf5850204c0bdb15bf030f47c7fe91d45c44c712697e4509ba67adb01c618")}, 110},
- },
- {
- 200,
- {AssumeutxoHash{uint256S("0x51c8d11d8b5c1de51543c579736e786aa2736206d1e11e627568029ce092cf62")}, 200},
- },
- };
-
- chainTxData = ChainTxData{
- 0,
- 0,
- 0
- };
-
- base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
- base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
- base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
- base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
- base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
-
- bech32_hrp = "bcrt";
- }
-
- /**
- * Allows modifying the Version Bits regtest parameters.
- */
- void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout, int min_activation_height)
- {
- consensus.vDeployments[d].nStartTime = nStartTime;
- consensus.vDeployments[d].nTimeout = nTimeout;
- consensus.vDeployments[d].min_activation_height = min_activation_height;
- }
- void UpdateActivationParametersFromArgs(const ArgsManager& args);
-};
+}
-static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& consensus)
+void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& options)
{
+ if (auto value = args.GetBoolArg("-fastprune")) options.fastprune = *value;
+
for (const std::string& arg : args.GetArgs("-testactivationheight")) {
const auto found{arg.find('@')};
if (found == std::string::npos) {
throw std::runtime_error(strprintf("Invalid format (%s) for -testactivationheight=name@height.", arg));
}
- const auto name{arg.substr(0, found)};
+
const auto value{arg.substr(found + 1)};
int32_t height;
if (!ParseInt32(value, &height) || height < 0 || height >= std::numeric_limits<int>::max()) {
throw std::runtime_error(strprintf("Invalid height value (%s) for -testactivationheight=name@height.", arg));
}
- if (name == "segwit") {
- consensus.SegwitHeight = int{height};
- } else if (name == "bip34") {
- consensus.BIP34Height = int{height};
- } else if (name == "dersig") {
- consensus.BIP66Height = int{height};
- } else if (name == "cltv") {
- consensus.BIP65Height = int{height};
- } else if (name == "csv") {
- consensus.CSVHeight = int{height};
+
+ const auto deployment_name{arg.substr(0, found)};
+ if (const auto buried_deployment = GetBuriedDeployment(deployment_name)) {
+ options.activation_heights[*buried_deployment] = height;
} else {
throw std::runtime_error(strprintf("Invalid name (%s) for -testactivationheight=name@height.", arg));
}
}
-}
-
-void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
-{
- MaybeUpdateHeights(args, consensus);
if (!args.IsArgSet("-vbparams")) return;
@@ -530,23 +60,26 @@ void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) {
throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]");
}
- int64_t nStartTime, nTimeout;
- int min_activation_height = 0;
- if (!ParseInt64(vDeploymentParams[1], &nStartTime)) {
+ CChainParams::VersionBitsParameters vbparams{};
+ if (!ParseInt64(vDeploymentParams[1], &vbparams.start_time)) {
throw std::runtime_error(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1]));
}
- if (!ParseInt64(vDeploymentParams[2], &nTimeout)) {
+ if (!ParseInt64(vDeploymentParams[2], &vbparams.timeout)) {
throw std::runtime_error(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2]));
}
- if (vDeploymentParams.size() >= 4 && !ParseInt32(vDeploymentParams[3], &min_activation_height)) {
- throw std::runtime_error(strprintf("Invalid min_activation_height (%s)", vDeploymentParams[3]));
+ if (vDeploymentParams.size() >= 4) {
+ if (!ParseInt32(vDeploymentParams[3], &vbparams.min_activation_height)) {
+ throw std::runtime_error(strprintf("Invalid min_activation_height (%s)", vDeploymentParams[3]));
+ }
+ } else {
+ vbparams.min_activation_height = 0;
}
bool found = false;
for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) {
- UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout, min_activation_height);
+ options.version_bits_parameters[Consensus::DeploymentPos(j)] = vbparams;
found = true;
- LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], nStartTime, nTimeout, min_activation_height);
+ LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], vbparams.start_time, vbparams.timeout, vbparams.min_activation_height);
break;
}
}
@@ -566,13 +99,17 @@ const CChainParams &Params() {
std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, const std::string& chain)
{
if (chain == CBaseChainParams::MAIN) {
- return std::unique_ptr<CChainParams>(new CMainParams());
+ return CChainParams::Main();
} else if (chain == CBaseChainParams::TESTNET) {
- return std::unique_ptr<CChainParams>(new CTestNetParams());
+ return CChainParams::TestNet();
} else if (chain == CBaseChainParams::SIGNET) {
- return std::unique_ptr<CChainParams>(new SigNetParams(args));
+ auto opts = CChainParams::SigNetOptions{};
+ ReadSigNetArgs(args, opts);
+ return CChainParams::SigNet(opts);
} else if (chain == CBaseChainParams::REGTEST) {
- return std::unique_ptr<CChainParams>(new CRegTestParams(args));
+ auto opts = CChainParams::RegTestOptions{};
+ ReadRegTestArgs(args, opts);
+ return CChainParams::RegTest(opts);
}
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
diff --git a/src/chainparams.h b/src/chainparams.h
index 66592ffdda..cb34d068e1 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -6,6 +6,8 @@
#ifndef BITCOIN_CHAINPARAMS_H
#define BITCOIN_CHAINPARAMS_H
+#include <kernel/chainparams.h>
+
#include <chainparamsbase.h>
#include <consensus/params.h>
#include <netaddress.h>
@@ -13,139 +15,12 @@
#include <protocol.h>
#include <util/hash_type.h>
+#include <cstdint>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
-typedef std::map<int, uint256> MapCheckpoints;
-
-struct CCheckpointData {
- MapCheckpoints mapCheckpoints;
-
- int GetHeight() const {
- const auto& final_checkpoint = mapCheckpoints.rbegin();
- return final_checkpoint->first /* height */;
- }
-};
-
-struct AssumeutxoHash : public BaseHash<uint256> {
- explicit AssumeutxoHash(const uint256& hash) : BaseHash(hash) {}
-};
-
-/**
- * Holds configuration for use during UTXO snapshot load and validation. The contents
- * here are security critical, since they dictate which UTXO snapshots are recognized
- * as valid.
- */
-struct AssumeutxoData {
- //! The expected hash of the deserialized UTXO set.
- const AssumeutxoHash hash_serialized;
-
- //! Used to populate the nChainTx value, which is used during BlockManager::LoadBlockIndex().
- //!
- //! We need to hardcode the value here because this is computed cumulatively using block data,
- //! which we do not necessarily have at the time of snapshot load.
- const unsigned int nChainTx;
-};
-
-using MapAssumeutxo = std::map<int, const AssumeutxoData>;
-
-/**
- * Holds various statistics on transactions within a chain. Used to estimate
- * verification progress during chain sync.
- *
- * See also: CChainParams::TxData, GuessVerificationProgress.
- */
-struct ChainTxData {
- int64_t nTime; //!< UNIX timestamp of last known number of transactions
- int64_t nTxCount; //!< total number of transactions between genesis and that timestamp
- double dTxRate; //!< estimated number of transactions per second after that timestamp
-};
-
-/**
- * CChainParams defines various tweakable parameters of a given instance of the
- * Bitcoin system.
- */
-class CChainParams
-{
-public:
- enum Base58Type {
- PUBKEY_ADDRESS,
- SCRIPT_ADDRESS,
- SECRET_KEY,
- EXT_PUBLIC_KEY,
- EXT_SECRET_KEY,
-
- MAX_BASE58_TYPES
- };
-
- const Consensus::Params& GetConsensus() const { return consensus; }
- const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
- uint16_t GetDefaultPort() const { return nDefaultPort; }
- uint16_t GetDefaultPort(Network net) const
- {
- return net == NET_I2P ? I2P_SAM31_PORT : GetDefaultPort();
- }
- uint16_t GetDefaultPort(const std::string& addr) const
- {
- CNetAddr a;
- return a.SetSpecial(addr) ? GetDefaultPort(a.GetNetwork()) : GetDefaultPort();
- }
-
- const CBlock& GenesisBlock() const { return genesis; }
- /** Default value for -checkmempool and -checkblockindex argument */
- bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
- /** Policy: Filter transactions that do not match well-defined patterns */
- bool RequireStandard() const { return fRequireStandard; }
- /** If this chain is exclusively used for testing */
- bool IsTestChain() const { return m_is_test_chain; }
- /** If this chain allows time to be mocked */
- bool IsMockableChain() const { return m_is_mockable_chain; }
- uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
- /** Minimum free space (in GB) needed for data directory */
- uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; }
- /** Minimum free space (in GB) needed for data directory when pruned; Does not include prune target*/
- uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; }
- /** Whether it is possible to mine blocks on demand (no retargeting) */
- bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; }
- /** Return the network string */
- std::string NetworkIDString() const { return strNetworkID; }
- /** Return the list of hostnames to look up for DNS seeds */
- const std::vector<std::string>& DNSSeeds() const { return vSeeds; }
- const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
- const std::string& Bech32HRP() const { return bech32_hrp; }
- const std::vector<uint8_t>& FixedSeeds() const { return vFixedSeeds; }
- const CCheckpointData& Checkpoints() const { return checkpointData; }
-
- //! Get allowed assumeutxo configuration.
- //! @see ChainstateManager
- const MapAssumeutxo& Assumeutxo() const { return m_assumeutxo_data; }
-
- const ChainTxData& TxData() const { return chainTxData; }
-protected:
- CChainParams() {}
-
- Consensus::Params consensus;
- CMessageHeader::MessageStartChars pchMessageStart;
- uint16_t nDefaultPort;
- uint64_t nPruneAfterHeight;
- uint64_t m_assumed_blockchain_size;
- uint64_t m_assumed_chain_state_size;
- std::vector<std::string> vSeeds;
- std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
- std::string bech32_hrp;
- std::string strNetworkID;
- CBlock genesis;
- std::vector<uint8_t> vFixedSeeds;
- bool fDefaultConsistencyChecks;
- bool fRequireStandard;
- bool m_is_test_chain;
- bool m_is_mockable_chain;
- CCheckpointData checkpointData;
- MapAssumeutxo m_assumeutxo_data;
- ChainTxData chainTxData;
-};
-
/**
* Creates and returns a std::unique_ptr<CChainParams> of the chosen chain.
* @returns a CChainParams* of the chosen chain.
diff --git a/src/checkqueue.h b/src/checkqueue.h
index bead6f0c6f..d83f717fb7 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -199,11 +199,12 @@ public:
WITH_LOCK(m_mutex, m_request_stop = false);
}
+ bool HasThreads() const { return !m_worker_threads.empty(); }
+
~CCheckQueue()
{
assert(m_worker_threads.empty());
}
-
};
/**
diff --git a/src/clientversion.cpp b/src/clientversion.cpp
index 192e9c52bc..e7d63e34c6 100644
--- a/src/clientversion.cpp
+++ b/src/clientversion.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/clientversion.h b/src/clientversion.h
index d2efd7dcab..9da0cd0b39 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/coins.cpp b/src/coins.cpp
index 5983a8a39f..5a6ae525a7 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,7 +13,7 @@
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
-bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
+bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase) { return false; }
std::unique_ptr<CCoinsViewCursor> CCoinsView::Cursor() const { return nullptr; }
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const
@@ -28,11 +28,14 @@ bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
-bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
+bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase) { return base->BatchWrite(mapCoins, hashBlock, erase); }
std::unique_ptr<CCoinsViewCursor> CCoinsViewBacked::Cursor() const { return base->Cursor(); }
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
-CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
+CCoinsViewCache::CCoinsViewCache(CCoinsView* baseIn, bool deterministic) :
+ CCoinsViewBacked(baseIn), m_deterministic(deterministic),
+ cacheCoins(0, SaltedOutpointHasher(/*deterministic=*/deterministic))
+{}
size_t CCoinsViewCache::DynamicMemoryUsage() const {
return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage;
@@ -176,8 +179,10 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
hashBlock = hashBlockIn;
}
-bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
- for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
+bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn, bool erase) {
+ for (CCoinsMap::iterator it = mapCoins.begin();
+ it != mapCoins.end();
+ it = erase ? mapCoins.erase(it) : std::next(it)) {
// Ignore non-dirty entries (optimization).
if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
continue;
@@ -190,7 +195,14 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
// Create the coin in the parent cache, move the data up
// and mark it as dirty.
CCoinsCacheEntry& entry = cacheCoins[it->first];
- entry.coin = std::move(it->second.coin);
+ if (erase) {
+ // The `move` call here is purely an optimization; we rely on the
+ // `mapCoins.erase` call in the `for` expression to actually remove
+ // the entry from the child map.
+ entry.coin = std::move(it->second.coin);
+ } else {
+ entry.coin = it->second.coin;
+ }
cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
entry.flags = CCoinsCacheEntry::DIRTY;
// We can mark it FRESH in the parent if it was FRESH in the child
@@ -218,7 +230,14 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
} else {
// A normal modification.
cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
- itUs->second.coin = std::move(it->second.coin);
+ if (erase) {
+ // The `move` call here is purely an optimization; we rely on the
+ // `mapCoins.erase` call in the `for` expression to actually remove
+ // the entry from the child map.
+ itUs->second.coin = std::move(it->second.coin);
+ } else {
+ itUs->second.coin = it->second.coin;
+ }
cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
itUs->second.flags |= CCoinsCacheEntry::DIRTY;
// NOTE: It isn't safe to mark the coin as FRESH in the parent
@@ -233,12 +252,32 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
}
bool CCoinsViewCache::Flush() {
- bool fOk = base->BatchWrite(cacheCoins, hashBlock);
- cacheCoins.clear();
+ bool fOk = base->BatchWrite(cacheCoins, hashBlock, /*erase=*/true);
+ if (fOk && !cacheCoins.empty()) {
+ /* BatchWrite must erase all cacheCoins elements when erase=true. */
+ throw std::logic_error("Not all cached coins were erased");
+ }
cachedCoinsUsage = 0;
return fOk;
}
+bool CCoinsViewCache::Sync()
+{
+ bool fOk = base->BatchWrite(cacheCoins, hashBlock, /*erase=*/false);
+ // Instead of clearing `cacheCoins` as we would in Flush(), just clear the
+ // FRESH/DIRTY flags of any coin that isn't spent.
+ for (auto it = cacheCoins.begin(); it != cacheCoins.end(); ) {
+ if (it->second.coin.IsSpent()) {
+ cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
+ it = cacheCoins.erase(it);
+ } else {
+ it->second.flags = 0;
+ ++it;
+ }
+ }
+ return fOk;
+}
+
void CCoinsViewCache::Uncache(const COutPoint& hash)
{
CCoinsMap::iterator it = cacheCoins.find(hash);
@@ -275,7 +314,24 @@ void CCoinsViewCache::ReallocateCache()
// Cache should be empty when we're calling this.
assert(cacheCoins.size() == 0);
cacheCoins.~CCoinsMap();
- ::new (&cacheCoins) CCoinsMap();
+ ::new (&cacheCoins) CCoinsMap(0, SaltedOutpointHasher(/*deterministic=*/m_deterministic));
+}
+
+void CCoinsViewCache::SanityCheck() const
+{
+ size_t recomputed_usage = 0;
+ for (const auto& [_, entry] : cacheCoins) {
+ unsigned attr = 0;
+ if (entry.flags & CCoinsCacheEntry::DIRTY) attr |= 1;
+ if (entry.flags & CCoinsCacheEntry::FRESH) attr |= 2;
+ if (entry.coin.IsSpent()) attr |= 4;
+ // Only 5 combinations are possible.
+ assert(attr != 2 && attr != 4 && attr != 7);
+
+ // Recompute cachedCoinsUsage.
+ recomputed_usage += entry.coin.DynamicMemoryUsage();
+ }
+ assert(recomputed_usage == cachedCoinsUsage);
}
static const size_t MIN_TRANSACTION_OUTPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxOut(), PROTOCOL_VERSION);
diff --git a/src/coins.h b/src/coins.h
index 67fecc9785..dd336b210a 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -176,7 +176,7 @@ public:
//! Do a bulk modification (multiple Coin changes + BestBlock change).
//! The passed mapCoins can be modified.
- virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
+ virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase = true);
//! Get a cursor to iterate over the whole state
virtual std::unique_ptr<CCoinsViewCursor> Cursor() const;
@@ -202,7 +202,7 @@ public:
uint256 GetBestBlock() const override;
std::vector<uint256> GetHeadBlocks() const override;
void SetBackend(CCoinsView &viewIn);
- bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase = true) override;
std::unique_ptr<CCoinsViewCursor> Cursor() const override;
size_t EstimateSize() const override;
};
@@ -211,6 +211,9 @@ public:
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
class CCoinsViewCache : public CCoinsViewBacked
{
+private:
+ const bool m_deterministic;
+
protected:
/**
* Make mutable so that we can "fill the cache" even from Get-methods
@@ -220,10 +223,10 @@ protected:
mutable CCoinsMap cacheCoins;
/* Cached dynamic memory usage for the inner Coin objects. */
- mutable size_t cachedCoinsUsage;
+ mutable size_t cachedCoinsUsage{0};
public:
- CCoinsViewCache(CCoinsView *baseIn);
+ CCoinsViewCache(CCoinsView *baseIn, bool deterministic = false);
/**
* By deleting the copy constructor, we prevent accidentally using it when one intends to create a cache on top of a base cache.
@@ -235,7 +238,7 @@ public:
bool HaveCoin(const COutPoint &outpoint) const override;
uint256 GetBestBlock() const override;
void SetBestBlock(const uint256 &hashBlock);
- bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase = true) override;
std::unique_ptr<CCoinsViewCursor> Cursor() const override {
throw std::logic_error("CCoinsViewCache cursor iteration not supported.");
}
@@ -282,13 +285,23 @@ public:
bool SpendCoin(const COutPoint &outpoint, Coin* moveto = nullptr);
/**
- * Push the modifications applied to this cache to its base.
- * Failure to call this method before destruction will cause the changes to be forgotten.
+ * Push the modifications applied to this cache to its base and wipe local state.
+ * Failure to call this method or Sync() before destruction will cause the changes
+ * to be forgotten.
* If false is returned, the state of this cache (and its backing view) will be undefined.
*/
bool Flush();
/**
+ * Push the modifications applied to this cache to its base while retaining
+ * the contents of this cache (except for spent coins, which we erase).
+ * Failure to call this method or Flush() before destruction will cause the changes
+ * to be forgotten.
+ * If false is returned, the state of this cache (and its backing view) will be undefined.
+ */
+ bool Sync();
+
+ /**
* Removes the UTXO with the given outpoint from the cache, if it is
* not modified.
*/
@@ -310,6 +323,9 @@ public:
//! See: https://stackoverflow.com/questions/42114044/how-to-release-unordered-map-memory
void ReallocateCache();
+ //! Run an internal sanity check on the cache data structure. */
+ void SanityCheck() const;
+
private:
/**
* @note this is marked const, but may actually append to `cacheCoins`, increasing
diff --git a/src/common/bloom.cpp b/src/common/bloom.cpp
index aa3fcf1ce2..fd3276b5a7 100644
--- a/src/common/bloom.cpp
+++ b/src/common/bloom.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -60,7 +60,7 @@ void CBloomFilter::insert(Span<const unsigned char> vKey)
void CBloomFilter::insert(const COutPoint& outpoint)
{
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << outpoint;
insert(MakeUCharSpan(stream));
}
@@ -81,7 +81,7 @@ bool CBloomFilter::contains(Span<const unsigned char> vKey) const
bool CBloomFilter::contains(const COutPoint& outpoint) const
{
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << outpoint;
return contains(MakeUCharSpan(stream));
}
diff --git a/src/common/init.cpp b/src/common/init.cpp
new file mode 100644
index 0000000000..159eb7e2ef
--- /dev/null
+++ b/src/common/init.cpp
@@ -0,0 +1,74 @@
+// Copyright (c) 2023 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 <common/init.h>
+#include <chainparams.h>
+#include <fs.h>
+#include <tinyformat.h>
+#include <util/system.h>
+#include <util/translation.h>
+
+#include <algorithm>
+#include <exception>
+#include <optional>
+
+namespace common {
+std::optional<ConfigError> InitConfig(ArgsManager& args, SettingsAbortFn settings_abort_fn)
+{
+ try {
+ if (!CheckDataDirOption(args)) {
+ return ConfigError{ConfigStatus::FAILED, strprintf(_("Specified data directory \"%s\" does not exist."), args.GetArg("-datadir", ""))};
+ }
+ std::string error;
+ if (!args.ReadConfigFiles(error, true)) {
+ return ConfigError{ConfigStatus::FAILED, strprintf(_("Error reading configuration file: %s"), error)};
+ }
+
+ // Check for chain settings (Params() calls are only valid after this clause)
+ SelectParams(args.GetChainName());
+
+ // Create datadir if it does not exist.
+ const auto base_path{args.GetDataDirBase()};
+ if (!fs::exists(base_path)) {
+ // When creating a *new* datadir, also create a "wallets" subdirectory,
+ // whether or not the wallet is enabled now, so if the wallet is enabled
+ // in the future, it will use the "wallets" subdirectory for creating
+ // and listing wallets, rather than the top-level directory where
+ // wallets could be mixed up with other files. For backwards
+ // compatibility, wallet code will use the "wallets" subdirectory only
+ // if it already exists, but never create it itself. There is discussion
+ // in https://github.com/bitcoin/bitcoin/issues/16220 about ways to
+ // change wallet code so it would no longer be necessary to create
+ // "wallets" subdirectories here.
+ fs::create_directories(base_path / "wallets");
+ }
+ const auto net_path{args.GetDataDirNet()};
+ if (!fs::exists(net_path)) {
+ fs::create_directories(net_path / "wallets");
+ }
+
+ // Create settings.json if -nosettings was not specified.
+ if (args.GetSettingsPath()) {
+ std::vector<std::string> details;
+ if (!args.ReadSettingsFile(&details)) {
+ const bilingual_str& message = _("Settings file could not be read");
+ if (!settings_abort_fn) {
+ return ConfigError{ConfigStatus::FAILED, message, details};
+ } else if (settings_abort_fn(message, details)) {
+ return ConfigError{ConfigStatus::ABORTED, message, details};
+ } else {
+ details.clear(); // User chose to ignore the error and proceed.
+ }
+ }
+ if (!args.WriteSettingsFile(&details)) {
+ const bilingual_str& message = _("Settings file could not be written");
+ return ConfigError{ConfigStatus::FAILED_WRITE, message, details};
+ }
+ }
+ } catch (const std::exception& e) {
+ return ConfigError{ConfigStatus::FAILED, Untranslated(e.what())};
+ }
+ return {};
+}
+} // namespace common
diff --git a/src/common/init.h b/src/common/init.h
new file mode 100644
index 0000000000..380ac3ac7e
--- /dev/null
+++ b/src/common/init.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 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_COMMON_INIT_H
+#define BITCOIN_COMMON_INIT_H
+
+#include <util/translation.h>
+
+#include <functional>
+#include <optional>
+#include <string>
+#include <vector>
+
+class ArgsManager;
+
+namespace common {
+enum class ConfigStatus {
+ FAILED, //!< Failed generically.
+ FAILED_WRITE, //!< Failed to write settings.json
+ ABORTED, //!< Aborted by user
+};
+
+struct ConfigError {
+ ConfigStatus status;
+ bilingual_str message{};
+ std::vector<std::string> details{};
+};
+
+//! Callback function to let the user decide whether to abort loading if
+//! settings.json file exists and can't be parsed, or to ignore the error and
+//! overwrite the file.
+using SettingsAbortFn = std::function<bool(const bilingual_str& message, const std::vector<std::string>& details)>;
+
+/* Read config files, and create datadir and settings.json if they don't exist. */
+std::optional<ConfigError> InitConfig(ArgsManager& args, SettingsAbortFn settings_abort_fn = nullptr);
+} // namespace common
+
+#endif // BITCOIN_COMMON_INIT_H
diff --git a/src/common/interfaces.cpp b/src/common/interfaces.cpp
new file mode 100644
index 0000000000..c8bbe2b3c0
--- /dev/null
+++ b/src/common/interfaces.cpp
@@ -0,0 +1,53 @@
+// Copyright (c) 2021-2022 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 <interfaces/echo.h>
+#include <interfaces/handler.h>
+
+#include <boost/signals2/connection.hpp>
+#include <memory>
+#include <utility>
+
+namespace common {
+namespace {
+class CleanupHandler : public interfaces::Handler
+{
+public:
+ explicit CleanupHandler(std::function<void()> cleanup) : m_cleanup(std::move(cleanup)) {}
+ ~CleanupHandler() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; }
+ void disconnect() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; }
+ std::function<void()> m_cleanup;
+};
+
+class SignalHandler : public interfaces::Handler
+{
+public:
+ explicit SignalHandler(boost::signals2::connection connection) : m_connection(std::move(connection)) {}
+
+ void disconnect() override { m_connection.disconnect(); }
+
+ boost::signals2::scoped_connection m_connection;
+};
+
+class EchoImpl : public interfaces::Echo
+{
+public:
+ std::string echo(const std::string& echo) override { return echo; }
+};
+} // namespace
+} // namespace common
+
+namespace interfaces {
+std::unique_ptr<Handler> MakeCleanupHandler(std::function<void()> cleanup)
+{
+ return std::make_unique<common::CleanupHandler>(std::move(cleanup));
+}
+
+std::unique_ptr<Handler> MakeSignalHandler(boost::signals2::connection connection)
+{
+ return std::make_unique<common::SignalHandler>(std::move(connection));
+}
+
+std::unique_ptr<Echo> MakeEcho() { return std::make_unique<common::EchoImpl>(); }
+} // namespace interfaces
diff --git a/src/common/run_command.cpp b/src/common/run_command.cpp
new file mode 100644
index 0000000000..6ad9f75b5d
--- /dev/null
+++ b/src/common/run_command.cpp
@@ -0,0 +1,64 @@
+// Copyright (c) 2022 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 <common/run_command.h>
+
+#include <tinyformat.h>
+#include <univalue.h>
+
+#ifdef ENABLE_EXTERNAL_SIGNER
+#if defined(__GNUC__)
+// Boost 1.78 requires the following workaround.
+// See: https://github.com/boostorg/process/issues/235
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnarrowing"
+#endif
+#include <boost/process.hpp>
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+#endif // ENABLE_EXTERNAL_SIGNER
+
+UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in)
+{
+#ifdef ENABLE_EXTERNAL_SIGNER
+ namespace bp = boost::process;
+
+ UniValue result_json;
+ bp::opstream stdin_stream;
+ bp::ipstream stdout_stream;
+ bp::ipstream stderr_stream;
+
+ if (str_command.empty()) return UniValue::VNULL;
+
+ bp::child c(
+ str_command,
+ bp::std_out > stdout_stream,
+ bp::std_err > stderr_stream,
+ bp::std_in < stdin_stream
+ );
+ if (!str_std_in.empty()) {
+ stdin_stream << str_std_in << std::endl;
+ }
+ stdin_stream.pipe().close();
+
+ std::string result;
+ std::string error;
+ std::getline(stdout_stream, result);
+ std::getline(stderr_stream, error);
+
+ c.wait();
+ const int n_error = c.exit_code();
+ if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error));
+ if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result);
+
+ return result_json;
+#else
+ throw std::runtime_error("Compiled without external signing support (required for external signing).");
+#endif // ENABLE_EXTERNAL_SIGNER
+}
diff --git a/src/common/run_command.h b/src/common/run_command.h
new file mode 100644
index 0000000000..2fbdc071ee
--- /dev/null
+++ b/src/common/run_command.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2022 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_COMMON_RUN_COMMAND_H
+#define BITCOIN_COMMON_RUN_COMMAND_H
+
+#include <string>
+
+class UniValue;
+
+/**
+ * Execute a command which returns JSON, and parse the result.
+ *
+ * @param str_command The command to execute, including any arguments
+ * @param str_std_in string to pass to stdin
+ * @return parsed JSON
+ */
+UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in="");
+
+#endif // BITCOIN_COMMON_RUN_COMMAND_H
diff --git a/src/util/url.cpp b/src/common/url.cpp
index ea9323e666..053e1a825c 100644
--- a/src/util/url.cpp
+++ b/src/common/url.cpp
@@ -1,8 +1,8 @@
-// Copyright (c) 2015-2019 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/url.h>
+#include <common/url.h>
#include <event2/http.h>
diff --git a/src/util/url.h b/src/common/url.h
index 5a7b11fa04..b16b8241af 100644
--- a/src/util/url.h
+++ b/src/common/url.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_UTIL_URL_H
-#define BITCOIN_UTIL_URL_H
+#ifndef BITCOIN_COMMON_URL_H
+#define BITCOIN_COMMON_URL_H
#include <string>
@@ -11,4 +11,4 @@ using UrlDecodeFn = std::string(const std::string& url_encoded);
UrlDecodeFn urlDecode;
extern UrlDecodeFn* const URL_DECODE;
-#endif // BITCOIN_UTIL_URL_H
+#endif // BITCOIN_COMMON_URL_H
diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h
index 2f4232fa5c..9ee71ef267 100644
--- a/src/compat/byteswap.h
+++ b/src/compat/byteswap.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/compat/compat.h b/src/compat/compat.h
index a8e5552c0a..88f58120b8 100644
--- a/src/compat/compat.h
+++ b/src/compat/compat.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -109,14 +109,6 @@ typedef char* sockopt_arg_type;
#define USE_POLL
#endif
-bool static inline IsSelectableSocket(const SOCKET& s) {
-#if defined(USE_POLL) || defined(WIN32)
- return true;
-#else
- return (s < FD_SETSIZE);
-#endif
-}
-
// MSG_NOSIGNAL is not available on some platforms, if it doesn't exist define it as 0
#if !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
diff --git a/src/compat/cpuid.h b/src/compat/cpuid.h
index e78c1ce6d1..4237c8ebc9 100644
--- a/src/compat/cpuid.h
+++ b/src/compat/cpuid.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/compat/endian.h b/src/compat/endian.h
index bdd8b84c1b..882de2dbf0 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/compat/stdin.cpp b/src/compat/stdin.cpp
index 61d66e39f2..c11763f68f 100644
--- a/src/compat/stdin.cpp
+++ b/src/compat/stdin.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -58,7 +58,7 @@ bool StdinReady()
return false;
#else
struct pollfd fds;
- fds.fd = 0; /* this is STDIN */
+ fds.fd = STDIN_FILENO;
fds.events = POLLIN;
return poll(&fds, 1, 0) == 1;
#endif
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index 10bdbf31a8..384f70bc10 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 7c35222713..25f53eb620 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@
#include <chrono>
#include <limits>
#include <map>
+#include <vector>
namespace Consensus {
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
index 1209c0faa5..d2cf792cf3 100644
--- a/src/consensus/tx_verify.h
+++ b/src/consensus/tx_verify.h
@@ -63,8 +63,8 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
/**
* Calculates the block height and previous block's median time past at
* which the transaction will be considered final in the context of BIP 68.
- * Also removes from the vector of input heights any entries which did not
- * correspond to sequence locked inputs as they do not affect the calculation.
+ * For each input that is not sequence locked, the corresponding entries in
+ * prevHeights are set to 0 as they do not affect the calculation.
*/
std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>& prevHeights, const CBlockIndex& block);
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 9c0aa09356..ad8ee676b2 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/core_io.h b/src/core_io.h
index c91c8199d8..997f3bfd5b 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,6 +15,7 @@ class CBlockHeader;
class CScript;
class CTransaction;
struct CMutableTransaction;
+class SigningProvider;
class uint256;
class UniValue;
class CTxUndo;
@@ -52,7 +53,7 @@ UniValue ValueFromAmount(const CAmount amount);
std::string FormatScript(const CScript& script);
std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
std::string SighashToStr(unsigned char sighash_type);
-void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex = true, bool include_address = false);
+void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex = true, bool include_address = false, const SigningProvider* provider = nullptr);
void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr, TxVerbosity verbosity = TxVerbosity::SHOW_DETAILS);
#endif // BITCOIN_CORE_IO_H
diff --git a/src/core_read.cpp b/src/core_read.cpp
index ec21a2f7f4..84cd559b7f 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -207,7 +207,7 @@ bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header)
if (!IsHex(hex_header)) return false;
const std::vector<unsigned char> header_data{ParseHex(hex_header)};
- CDataStream ser_header(header_data, SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ser_header{header_data};
try {
ser_header >> header;
} catch (const std::exception&) {
diff --git a/src/core_write.cpp b/src/core_write.cpp
index cfd4cb1b49..b0e3b0b3c4 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -147,13 +147,13 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags)
return HexStr(ssTx);
}
-void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex, bool include_address)
+void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex, bool include_address, const SigningProvider* provider)
{
CTxDestination address;
out.pushKV("asm", ScriptToAsmStr(script));
if (include_address) {
- out.pushKV("desc", InferDescriptor(script, DUMMY_SIGNING_PROVIDER)->ToString());
+ out.pushKV("desc", InferDescriptor(script, provider ? *provider : DUMMY_SIGNING_PROVIDER)->ToString());
}
if (include_hex) {
out.pushKV("hex", HexStr(script));
@@ -170,6 +170,8 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex, bool i
void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo, TxVerbosity verbosity)
{
+ CHECK_NONFATAL(verbosity >= TxVerbosity::SHOW_DETAILS);
+
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
// Transaction version is actually unsigned in consensus checks, just signed in memory,
diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp
index c7e12b0612..6934cef163 100644
--- a/src/crypto/chacha20.cpp
+++ b/src/crypto/chacha20.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,6 +8,7 @@
#include <crypto/common.h>
#include <crypto/chacha20.h>
+#include <algorithm>
#include <string.h>
constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (v >> (32 - c)); }
@@ -20,95 +21,69 @@ constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (
#define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0)
-static const unsigned char sigma[] = "expand 32-byte k";
-static const unsigned char tau[] = "expand 16-byte k";
-
-void ChaCha20::SetKey(const unsigned char* k, size_t keylen)
+void ChaCha20Aligned::SetKey32(const unsigned char* k)
{
- const unsigned char *constants;
-
- input[4] = ReadLE32(k + 0);
- input[5] = ReadLE32(k + 4);
- input[6] = ReadLE32(k + 8);
- input[7] = ReadLE32(k + 12);
- if (keylen == 32) { /* recommended */
- k += 16;
- constants = sigma;
- } else { /* keylen == 16 */
- constants = tau;
- }
- input[8] = ReadLE32(k + 0);
- input[9] = ReadLE32(k + 4);
- input[10] = ReadLE32(k + 8);
- input[11] = ReadLE32(k + 12);
- input[0] = ReadLE32(constants + 0);
- input[1] = ReadLE32(constants + 4);
- input[2] = ReadLE32(constants + 8);
- input[3] = ReadLE32(constants + 12);
- input[12] = 0;
- input[13] = 0;
- input[14] = 0;
- input[15] = 0;
+ input[0] = ReadLE32(k + 0);
+ input[1] = ReadLE32(k + 4);
+ input[2] = ReadLE32(k + 8);
+ input[3] = ReadLE32(k + 12);
+ input[4] = ReadLE32(k + 16);
+ input[5] = ReadLE32(k + 20);
+ input[6] = ReadLE32(k + 24);
+ input[7] = ReadLE32(k + 28);
+ input[8] = 0;
+ input[9] = 0;
+ input[10] = 0;
+ input[11] = 0;
}
-ChaCha20::ChaCha20()
+ChaCha20Aligned::ChaCha20Aligned()
{
memset(input, 0, sizeof(input));
}
-ChaCha20::ChaCha20(const unsigned char* k, size_t keylen)
+ChaCha20Aligned::ChaCha20Aligned(const unsigned char* key32)
{
- SetKey(k, keylen);
+ SetKey32(key32);
}
-void ChaCha20::SetIV(uint64_t iv)
+void ChaCha20Aligned::SetIV(uint64_t iv)
{
- input[14] = iv;
- input[15] = iv >> 32;
+ input[10] = iv;
+ input[11] = iv >> 32;
}
-void ChaCha20::Seek(uint64_t pos)
+void ChaCha20Aligned::Seek64(uint64_t pos)
{
- input[12] = pos;
- input[13] = pos >> 32;
+ input[8] = pos;
+ input[9] = pos >> 32;
}
-void ChaCha20::Keystream(unsigned char* c, size_t bytes)
+inline void ChaCha20Aligned::Keystream64(unsigned char* c, size_t blocks)
{
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
- uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
- unsigned char *ctarget = nullptr;
- unsigned char tmp[64];
- unsigned int i;
-
- if (!bytes) return;
-
- j0 = input[0];
- j1 = input[1];
- j2 = input[2];
- j3 = input[3];
- j4 = input[4];
- j5 = input[5];
- j6 = input[6];
- j7 = input[7];
- j8 = input[8];
- j9 = input[9];
- j10 = input[10];
- j11 = input[11];
- j12 = input[12];
- j13 = input[13];
- j14 = input[14];
- j15 = input[15];
+ uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+
+ if (!blocks) return;
+
+ j4 = input[0];
+ j5 = input[1];
+ j6 = input[2];
+ j7 = input[3];
+ j8 = input[4];
+ j9 = input[5];
+ j10 = input[6];
+ j11 = input[7];
+ j12 = input[8];
+ j13 = input[9];
+ j14 = input[10];
+ j15 = input[11];
for (;;) {
- if (bytes < 64) {
- ctarget = c;
- c = tmp;
- }
- x0 = j0;
- x1 = j1;
- x2 = j2;
- x3 = j3;
+ x0 = 0x61707865;
+ x1 = 0x3320646e;
+ x2 = 0x79622d32;
+ x3 = 0x6b206574;
x4 = j4;
x5 = j5;
x6 = j6;
@@ -134,10 +109,10 @@ void ChaCha20::Keystream(unsigned char* c, size_t bytes)
QUARTERROUND( x3, x4, x9,x14);
);
- x0 += j0;
- x1 += j1;
- x2 += j2;
- x3 += j3;
+ x0 += 0x61707865;
+ x1 += 0x3320646e;
+ x2 += 0x79622d32;
+ x3 += 0x6b206574;
x4 += j4;
x5 += j5;
x6 += j6;
@@ -171,59 +146,41 @@ void ChaCha20::Keystream(unsigned char* c, size_t bytes)
WriteLE32(c + 56, x14);
WriteLE32(c + 60, x15);
- if (bytes <= 64) {
- if (bytes < 64) {
- for (i = 0;i < bytes;++i) ctarget[i] = c[i];
- }
- input[12] = j12;
- input[13] = j13;
+ if (blocks == 1) {
+ input[8] = j12;
+ input[9] = j13;
return;
}
- bytes -= 64;
+ blocks -= 1;
c += 64;
}
}
-void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
+inline void ChaCha20Aligned::Crypt64(const unsigned char* m, unsigned char* c, size_t blocks)
{
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
- uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
- unsigned char *ctarget = nullptr;
- unsigned char tmp[64];
- unsigned int i;
-
- if (!bytes) return;
-
- j0 = input[0];
- j1 = input[1];
- j2 = input[2];
- j3 = input[3];
- j4 = input[4];
- j5 = input[5];
- j6 = input[6];
- j7 = input[7];
- j8 = input[8];
- j9 = input[9];
- j10 = input[10];
- j11 = input[11];
- j12 = input[12];
- j13 = input[13];
- j14 = input[14];
- j15 = input[15];
+ uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+
+ if (!blocks) return;
+
+ j4 = input[0];
+ j5 = input[1];
+ j6 = input[2];
+ j7 = input[3];
+ j8 = input[4];
+ j9 = input[5];
+ j10 = input[6];
+ j11 = input[7];
+ j12 = input[8];
+ j13 = input[9];
+ j14 = input[10];
+ j15 = input[11];
for (;;) {
- if (bytes < 64) {
- // if m has fewer than 64 bytes available, copy m to tmp and
- // read from tmp instead
- for (i = 0;i < bytes;++i) tmp[i] = m[i];
- m = tmp;
- ctarget = c;
- c = tmp;
- }
- x0 = j0;
- x1 = j1;
- x2 = j2;
- x3 = j3;
+ x0 = 0x61707865;
+ x1 = 0x3320646e;
+ x2 = 0x79622d32;
+ x3 = 0x6b206574;
x4 = j4;
x5 = j5;
x6 = j6;
@@ -249,10 +206,10 @@ void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
QUARTERROUND( x3, x4, x9,x14);
);
- x0 += j0;
- x1 += j1;
- x2 += j2;
- x3 += j3;
+ x0 += 0x61707865;
+ x1 += 0x3320646e;
+ x2 += 0x79622d32;
+ x3 += 0x6b206574;
x4 += j4;
x5 += j5;
x6 += j6;
@@ -303,16 +260,65 @@ void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
WriteLE32(c + 56, x14);
WriteLE32(c + 60, x15);
- if (bytes <= 64) {
- if (bytes < 64) {
- for (i = 0;i < bytes;++i) ctarget[i] = c[i];
- }
- input[12] = j12;
- input[13] = j13;
+ if (blocks == 1) {
+ input[8] = j12;
+ input[9] = j13;
return;
}
- bytes -= 64;
+ blocks -= 1;
c += 64;
m += 64;
}
}
+
+void ChaCha20::Keystream(unsigned char* c, size_t bytes)
+{
+ if (!bytes) return;
+ if (m_bufleft) {
+ unsigned reuse = std::min<size_t>(m_bufleft, bytes);
+ memcpy(c, m_buffer + 64 - m_bufleft, reuse);
+ m_bufleft -= reuse;
+ bytes -= reuse;
+ c += reuse;
+ }
+ if (bytes >= 64) {
+ size_t blocks = bytes / 64;
+ m_aligned.Keystream64(c, blocks);
+ c += blocks * 64;
+ bytes -= blocks * 64;
+ }
+ if (bytes) {
+ m_aligned.Keystream64(m_buffer, 1);
+ memcpy(c, m_buffer, bytes);
+ m_bufleft = 64 - bytes;
+ }
+}
+
+void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
+{
+ if (!bytes) return;
+ if (m_bufleft) {
+ unsigned reuse = std::min<size_t>(m_bufleft, bytes);
+ for (unsigned i = 0; i < reuse; i++) {
+ c[i] = m[i] ^ m_buffer[64 - m_bufleft + i];
+ }
+ m_bufleft -= reuse;
+ bytes -= reuse;
+ c += reuse;
+ m += reuse;
+ }
+ if (bytes >= 64) {
+ size_t blocks = bytes / 64;
+ m_aligned.Crypt64(m, c, blocks);
+ c += blocks * 64;
+ m += blocks * 64;
+ bytes -= blocks * 64;
+ }
+ if (bytes) {
+ m_aligned.Keystream64(m_buffer, 1);
+ for (unsigned i = 0; i < bytes; i++) {
+ c[i] = m[i] ^ m_buffer[i];
+ }
+ m_bufleft = 64 - bytes;
+ }
+}
diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h
index de16a77878..b286ef59fe 100644
--- a/src/crypto/chacha20.h
+++ b/src/crypto/chacha20.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,19 +8,69 @@
#include <cstdlib>
#include <stdint.h>
-/** A class for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein
- https://cr.yp.to/chacha/chacha-20080128.pdf */
+// classes for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein
+// https://cr.yp.to/chacha/chacha-20080128.pdf */
+
+/** ChaCha20 cipher that only operates on multiples of 64 bytes. */
+class ChaCha20Aligned
+{
+private:
+ uint32_t input[12];
+
+public:
+ ChaCha20Aligned();
+
+ /** Initialize a cipher with specified 32-byte key. */
+ ChaCha20Aligned(const unsigned char* key32);
+
+ /** set 32-byte key. */
+ void SetKey32(const unsigned char* key32);
+
+ /** set the 64-bit nonce. */
+ void SetIV(uint64_t iv);
+
+ /** set the 64bit block counter (pos seeks to byte position 64*pos). */
+ void Seek64(uint64_t pos);
+
+ /** outputs the keystream of size <64*blocks> into <c> */
+ void Keystream64(unsigned char* c, size_t blocks);
+
+ /** enciphers the message <input> of length <64*blocks> and write the enciphered representation into <output>
+ * Used for encryption and decryption (XOR)
+ */
+ void Crypt64(const unsigned char* input, unsigned char* output, size_t blocks);
+};
+
+/** Unrestricted ChaCha20 cipher. */
class ChaCha20
{
private:
- uint32_t input[16];
+ ChaCha20Aligned m_aligned;
+ unsigned char m_buffer[64] = {0};
+ unsigned m_bufleft{0};
public:
- ChaCha20();
- ChaCha20(const unsigned char* key, size_t keylen);
- void SetKey(const unsigned char* key, size_t keylen); //!< set key with flexible keylength; 256bit recommended */
- void SetIV(uint64_t iv); // set the 64bit nonce
- void Seek(uint64_t pos); // set the 64bit block counter
+ ChaCha20() = default;
+
+ /** Initialize a cipher with specified 32-byte key. */
+ ChaCha20(const unsigned char* key32) : m_aligned(key32) {}
+
+ /** set 32-byte key. */
+ void SetKey32(const unsigned char* key32)
+ {
+ m_aligned.SetKey32(key32);
+ m_bufleft = 0;
+ }
+
+ /** set the 64-bit nonce. */
+ void SetIV(uint64_t iv) { m_aligned.SetIV(iv); }
+
+ /** set the 64bit block counter (pos seeks to byte position 64*pos). */
+ void Seek64(uint64_t pos)
+ {
+ m_aligned.Seek64(pos);
+ m_bufleft = 0;
+ }
/** outputs the keystream of size <bytes> into <c> */
void Keystream(unsigned char* c, size_t bytes);
diff --git a/src/crypto/chacha_poly_aead.cpp b/src/crypto/chacha_poly_aead.cpp
index f736b2d867..119ad6902f 100644
--- a/src/crypto/chacha_poly_aead.cpp
+++ b/src/crypto/chacha_poly_aead.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -36,8 +36,9 @@ ChaCha20Poly1305AEAD::ChaCha20Poly1305AEAD(const unsigned char* K_1, size_t K_1_
assert(K_1_len == CHACHA20_POLY1305_AEAD_KEY_LEN);
assert(K_2_len == CHACHA20_POLY1305_AEAD_KEY_LEN);
- m_chacha_header.SetKey(K_1, CHACHA20_POLY1305_AEAD_KEY_LEN);
- m_chacha_main.SetKey(K_2, CHACHA20_POLY1305_AEAD_KEY_LEN);
+ static_assert(CHACHA20_POLY1305_AEAD_KEY_LEN == 32);
+ m_chacha_header.SetKey32(K_1);
+ m_chacha_main.SetKey32(K_2);
// set the cached sequence number to uint64 max which hints for an unset cache.
// we can't hit uint64 max since the rekey rule (which resets the sequence number) is 1GB
@@ -62,7 +63,7 @@ bool ChaCha20Poly1305AEAD::Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int
// block counter 0 for the poly1305 key
// use lower 32bytes for the poly1305 key
// (throws away 32 unused bytes (upper 32) from this ChaCha20 round)
- m_chacha_main.Seek(0);
+ m_chacha_main.Seek64(0);
m_chacha_main.Crypt(poly_key, poly_key, sizeof(poly_key));
// if decrypting, verify the tag prior to decryption
@@ -85,7 +86,7 @@ bool ChaCha20Poly1305AEAD::Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int
if (m_cached_aad_seqnr != seqnr_aad) {
m_cached_aad_seqnr = seqnr_aad;
m_chacha_header.SetIV(seqnr_aad);
- m_chacha_header.Seek(0);
+ m_chacha_header.Seek64(0);
m_chacha_header.Keystream(m_aad_keystream_buffer, CHACHA20_ROUND_OUTPUT);
}
// crypt the AAD (3 bytes message length) with given position in AAD cipher instance keystream
@@ -94,7 +95,7 @@ bool ChaCha20Poly1305AEAD::Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int
dest[2] = src[2] ^ m_aad_keystream_buffer[aad_pos + 2];
// Set the playload ChaCha instance block counter to 1 and crypt the payload
- m_chacha_main.Seek(1);
+ m_chacha_main.Seek64(1);
m_chacha_main.Crypt(src + CHACHA20_POLY1305_AEAD_AAD_LEN, dest + CHACHA20_POLY1305_AEAD_AAD_LEN, src_len - CHACHA20_POLY1305_AEAD_AAD_LEN);
// If encrypting, calculate and append tag
@@ -117,7 +118,7 @@ bool ChaCha20Poly1305AEAD::GetLength(uint32_t* len24_out, uint64_t seqnr_aad, in
// we need to calculate the 64 keystream bytes since we reached a new aad sequence number
m_cached_aad_seqnr = seqnr_aad;
m_chacha_header.SetIV(seqnr_aad); // use LE for the nonce
- m_chacha_header.Seek(0); // block counter 0
+ m_chacha_header.Seek64(0); // block counter 0
m_chacha_header.Keystream(m_aad_keystream_buffer, CHACHA20_ROUND_OUTPUT); // write keystream to the cache
}
diff --git a/src/crypto/hkdf_sha256_32.h b/src/crypto/hkdf_sha256_32.h
index 878b03a37f..d373520300 100644
--- a/src/crypto/hkdf_sha256_32.h
+++ b/src/crypto/hkdf_sha256_32.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/crypto/hmac_sha256.h b/src/crypto/hmac_sha256.h
index 9c25edd7c1..abd731d1fe 100644
--- a/src/crypto/hmac_sha256.h
+++ b/src/crypto/hmac_sha256.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/crypto/hmac_sha512.h b/src/crypto/hmac_sha512.h
index 6acce8992e..8fa55d2844 100644
--- a/src/crypto/hmac_sha512.h
+++ b/src/crypto/hmac_sha512.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp
index 7d14b7938e..471ee6af97 100644
--- a/src/crypto/muhash.cpp
+++ b/src/crypto/muhash.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -299,7 +299,7 @@ Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
unsigned char tmp[Num3072::BYTE_SIZE];
uint256 hashed_in{(HashWriter{} << in).GetSHA256()};
- ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, Num3072::BYTE_SIZE);
+ ChaCha20Aligned(hashed_in.data()).Keystream64(tmp, Num3072::BYTE_SIZE / 64);
Num3072 out{tmp};
return out;
diff --git a/src/crypto/poly1305.h b/src/crypto/poly1305.h
index c80faada7e..650e35bbca 100644
--- a/src/crypto/poly1305.h
+++ b/src/crypto/poly1305.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp
index 29a4ad906f..a2f7c6e156 100644
--- a/src/crypto/ripemd160.cpp
+++ b/src/crypto/ripemd160.cpp
@@ -239,7 +239,7 @@ void Transform(uint32_t* s, const unsigned char* chunk)
////// RIPEMD160
-CRIPEMD160::CRIPEMD160() : bytes(0)
+CRIPEMD160::CRIPEMD160()
{
ripemd160::Initialize(s);
}
diff --git a/src/crypto/ripemd160.h b/src/crypto/ripemd160.h
index f1d89b8407..fb631a66d2 100644
--- a/src/crypto/ripemd160.h
+++ b/src/crypto/ripemd160.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,7 +14,7 @@ class CRIPEMD160
private:
uint32_t s[5];
unsigned char buf[64];
- uint64_t bytes;
+ uint64_t bytes{0};
public:
static const size_t OUTPUT_SIZE = 20;
diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp
index 1fb9bb2b72..2610108f60 100644
--- a/src/crypto/sha1.cpp
+++ b/src/crypto/sha1.cpp
@@ -146,7 +146,7 @@ void Transform(uint32_t* s, const unsigned char* chunk)
////// SHA1
-CSHA1::CSHA1() : bytes(0)
+CSHA1::CSHA1()
{
sha1::Initialize(s);
}
diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h
index 6ef0187efd..741cdaad58 100644
--- a/src/crypto/sha1.h
+++ b/src/crypto/sha1.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,7 +14,7 @@ class CSHA1
private:
uint32_t s[5];
unsigned char buf[64];
- uint64_t bytes;
+ uint64_t bytes{0};
public:
static const size_t OUTPUT_SIZE = 20;
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index 196f81ea16..a4eef36480 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -673,7 +673,7 @@ std::string SHA256AutoDetect()
////// SHA-256
-CSHA256::CSHA256() : bytes(0)
+CSHA256::CSHA256()
{
sha256::Initialize(s);
}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index 24bd1f2e7e..7625508665 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,7 +15,7 @@ class CSHA256
private:
uint32_t s[8];
unsigned char buf[64];
- uint64_t bytes;
+ uint64_t bytes{0};
public:
static const size_t OUTPUT_SIZE = 32;
diff --git a/src/crypto/sha256_sse4.cpp b/src/crypto/sha256_sse4.cpp
index bc69703607..f4557291ce 100644
--- a/src/crypto/sha256_sse4.cpp
+++ b/src/crypto/sha256_sse4.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2020 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
diff --git a/src/crypto/sha256_x86_shani.cpp b/src/crypto/sha256_x86_shani.cpp
index a82802199f..e3143a55c2 100644
--- a/src/crypto/sha256_x86_shani.cpp
+++ b/src/crypto/sha256_x86_shani.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
diff --git a/src/crypto/sha3.h b/src/crypto/sha3.h
index 78608eae76..e8e91f1ee4 100644
--- a/src/crypto/sha3.h
+++ b/src/crypto/sha3.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp
index 85a7bbcb53..2713f06210 100644
--- a/src/crypto/sha512.cpp
+++ b/src/crypto/sha512.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -30,7 +30,7 @@ void inline Round(uint64_t a, uint64_t b, uint64_t c, uint64_t& d, uint64_t e, u
h = t1 + t2;
}
-/** Initialize SHA-256 state. */
+/** Initialize SHA-512 state. */
void inline Initialize(uint64_t* s)
{
s[0] = 0x6a09e667f3bcc908ull;
@@ -151,7 +151,7 @@ void Transform(uint64_t* s, const unsigned char* chunk)
////// SHA-512
-CSHA512::CSHA512() : bytes(0)
+CSHA512::CSHA512()
{
sha512::Initialize(s);
}
diff --git a/src/crypto/sha512.h b/src/crypto/sha512.h
index 7356dff6d9..d2f7d6a05e 100644
--- a/src/crypto/sha512.h
+++ b/src/crypto/sha512.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,7 +14,7 @@ class CSHA512
private:
uint64_t s[8];
unsigned char buf[128];
- uint64_t bytes;
+ uint64_t bytes{0};
public:
static constexpr size_t OUTPUT_SIZE = 64;
diff --git a/src/crypto/siphash.cpp b/src/crypto/siphash.cpp
index 2e90c393e1..2f7555d02e 100644
--- a/src/crypto/siphash.cpp
+++ b/src/crypto/siphash.cpp
@@ -119,10 +119,10 @@ uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
SIPROUND;
SIPROUND;
v0 ^= d;
- v3 ^= ((uint64_t)4) << 59;
+ v3 ^= (uint64_t{4}) << 59;
SIPROUND;
SIPROUND;
- v0 ^= ((uint64_t)4) << 59;
+ v0 ^= (uint64_t{4}) << 59;
v2 ^= 0xFF;
SIPROUND;
SIPROUND;
@@ -159,7 +159,7 @@ uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint3
SIPROUND;
SIPROUND;
v0 ^= d;
- d = (((uint64_t)36) << 56) | extra;
+ d = ((uint64_t{36}) << 56) | extra;
v3 ^= d;
SIPROUND;
SIPROUND;
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
index 61f553806e..cb0b362143 100644
--- a/src/cuckoocache.h
+++ b/src/cuckoocache.h
@@ -166,7 +166,7 @@ private:
std::vector<Element> table;
/** size stores the total available slots in the hash table */
- uint32_t size;
+ uint32_t size{0};
/** The bit_packed_atomic_flags array is marked mutable because we want
* garbage collection to be allowed to occur from const methods */
@@ -183,7 +183,7 @@ private:
* decremented on insert and reset to the new number of inserts which would
* cause the epoch to reach epoch_size when it reaches zero.
*/
- uint32_t epoch_heuristic_counter;
+ uint32_t epoch_heuristic_counter{0};
/** epoch_size is set to be the number of elements supposed to be in a
* epoch. When the number of non-erased elements in an epoch
@@ -193,12 +193,12 @@ private:
* one "dead" which has been erased, one "dying" which has been marked to be
* erased next, and one "living" which new inserts add to.
*/
- uint32_t epoch_size;
+ uint32_t epoch_size{0};
/** depth_limit determines how many elements insert should try to replace.
* Should be set to log2(n).
*/
- uint8_t depth_limit;
+ uint8_t depth_limit{0};
/** hash_function is a const instance of the hash function. It cannot be
* static or initialized at call time as it may have internal state (such as
@@ -322,8 +322,7 @@ public:
/** You must always construct a cache with some elements via a subsequent
* call to setup or setup_bytes, otherwise operations may segfault.
*/
- cache() : table(), size(), collection_flags(0), epoch_flags(),
- epoch_heuristic_counter(), epoch_size(), depth_limit(0), hash_function()
+ cache() : table(), collection_flags(0), epoch_flags(), hash_function()
{
}
@@ -344,7 +343,7 @@ public:
collection_flags.setup(size);
epoch_flags.resize(size);
// Set to 45% as described above
- epoch_size = std::max((uint32_t)1, (45 * size) / 100);
+ epoch_size = std::max(uint32_t{1}, (45 * size) / 100);
// Initially set to wait for a whole epoch
epoch_heuristic_counter = epoch_size;
return size;
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 4dbc839941..0c6debfa80 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -127,40 +127,40 @@ static leveldb::Options GetOptions(size_t nCacheSize)
return options;
}
-CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
- : m_name{fs::PathToString(path.stem())}
+CDBWrapper::CDBWrapper(const DBParams& params)
+ : m_name{fs::PathToString(params.path.stem())}, m_path{params.path}, m_is_memory{params.memory_only}
{
penv = nullptr;
readoptions.verify_checksums = true;
iteroptions.verify_checksums = true;
iteroptions.fill_cache = false;
syncoptions.sync = true;
- options = GetOptions(nCacheSize);
+ options = GetOptions(params.cache_bytes);
options.create_if_missing = true;
- if (fMemory) {
+ if (params.memory_only) {
penv = leveldb::NewMemEnv(leveldb::Env::Default());
options.env = penv;
} else {
- if (fWipe) {
- LogPrintf("Wiping LevelDB in %s\n", fs::PathToString(path));
- leveldb::Status result = leveldb::DestroyDB(fs::PathToString(path), options);
+ if (params.wipe_data) {
+ LogPrintf("Wiping LevelDB in %s\n", fs::PathToString(params.path));
+ leveldb::Status result = leveldb::DestroyDB(fs::PathToString(params.path), options);
dbwrapper_private::HandleError(result);
}
- TryCreateDirectories(path);
- LogPrintf("Opening LevelDB in %s\n", fs::PathToString(path));
+ TryCreateDirectories(params.path);
+ LogPrintf("Opening LevelDB in %s\n", fs::PathToString(params.path));
}
// PathToString() return value is safe to pass to leveldb open function,
// because on POSIX leveldb passes the byte string directly to ::open(), and
// on Windows it converts from UTF-8 to UTF-16 before calling ::CreateFileW
// (see env_posix.cc and env_windows.cc).
- leveldb::Status status = leveldb::DB::Open(options, fs::PathToString(path), &pdb);
+ leveldb::Status status = leveldb::DB::Open(options, fs::PathToString(params.path), &pdb);
dbwrapper_private::HandleError(status);
LogPrintf("Opened LevelDB successfully\n");
- if (gArgs.GetBoolArg("-forcecompactdb", false)) {
- LogPrintf("Starting database compaction of %s\n", fs::PathToString(path));
+ if (params.options.force_compact) {
+ LogPrintf("Starting database compaction of %s\n", fs::PathToString(params.path));
pdb->CompactRange(nullptr, nullptr);
- LogPrintf("Finished database compaction of %s\n", fs::PathToString(path));
+ LogPrintf("Finished database compaction of %s\n", fs::PathToString(params.path));
}
// The base-case obfuscation key, which is a noop.
@@ -168,7 +168,7 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo
bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key);
- if (!key_exists && obfuscate && IsEmpty()) {
+ if (!key_exists && params.obfuscate && IsEmpty()) {
// Initialize non-degenerate obfuscation if it won't upset
// existing, non-obfuscated data.
std::vector<unsigned char> new_key = CreateObfuscateKey();
@@ -177,10 +177,10 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo
Write(OBFUSCATE_KEY_KEY, new_key);
obfuscate_key = new_key;
- LogPrintf("Wrote new obfuscate key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key));
+ LogPrintf("Wrote new obfuscate key for %s: %s\n", fs::PathToString(params.path), HexStr(obfuscate_key));
}
- LogPrintf("Using obfuscation key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key));
+ LogPrintf("Using obfuscation key for %s: %s\n", fs::PathToString(params.path), HexStr(obfuscate_key));
}
CDBWrapper::~CDBWrapper()
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index 665eaa0e98..578d9880ac 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -31,6 +31,29 @@ class Env;
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
+//! User-controlled performance and debug options.
+struct DBOptions {
+ //! Compact database on startup.
+ bool force_compact = false;
+};
+
+//! Application-specific storage settings.
+struct DBParams {
+ //! Location in the filesystem where leveldb data will be stored.
+ fs::path path;
+ //! Configures various leveldb cache settings.
+ size_t cache_bytes;
+ //! If true, use leveldb's memory environment.
+ bool memory_only = false;
+ //! If true, remove all existing data.
+ bool wipe_data = false;
+ //! If true, store data obfuscated via simple XOR. If false, XOR with a
+ //! zero'd byte array.
+ bool obfuscate = false;
+ //! Passed-through options.
+ DBOptions options{};
+};
+
class dbwrapper_error : public std::runtime_error
{
public:
@@ -39,6 +62,10 @@ public:
class CDBWrapper;
+namespace dbwrapper {
+ using leveldb::DestroyDB;
+}
+
/** These should be considered an implementation detail of the specific database.
*/
namespace dbwrapper_private {
@@ -64,16 +91,16 @@ private:
const CDBWrapper &parent;
leveldb::WriteBatch batch;
- CDataStream ssKey;
+ DataStream ssKey{};
CDataStream ssValue;
- size_t size_estimate;
+ size_t size_estimate{0};
public:
/**
* @param[in] _parent CDBWrapper that this batch is to be submitted to
*/
- explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };
+ explicit CDBBatch(const CDBWrapper& _parent) : parent(_parent), ssValue(SER_DISK, CLIENT_VERSION){};
void Clear()
{
@@ -147,7 +174,7 @@ public:
void SeekToFirst();
template<typename K> void Seek(const K& key) {
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ DataStream ssKey{};
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
@@ -159,7 +186,7 @@ public:
template<typename K> bool GetKey(K& key) {
leveldb::Slice slKey = piter->key();
try {
- CDataStream ssKey{MakeByteSpan(slKey), SER_DISK, CLIENT_VERSION};
+ DataStream ssKey{MakeByteSpan(slKey)};
ssKey >> key;
} catch (const std::exception&) {
return false;
@@ -219,16 +246,14 @@ private:
std::vector<unsigned char> CreateObfuscateKey() const;
+ //! path to filesystem storage
+ const fs::path m_path;
+
+ //! whether or not the database resides in memory
+ bool m_is_memory;
+
public:
- /**
- * @param[in] path Location in the filesystem where leveldb data will be stored.
- * @param[in] nCacheSize Configures various leveldb cache settings.
- * @param[in] fMemory If true, use leveldb's memory environment.
- * @param[in] fWipe If true, remove all existing data.
- * @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
- * with a zero'd byte array.
- */
- CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
+ CDBWrapper(const DBParams& params);
~CDBWrapper();
CDBWrapper(const CDBWrapper&) = delete;
@@ -237,7 +262,7 @@ public:
template <typename K, typename V>
bool Read(const K& key, V& value) const
{
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ DataStream ssKey{};
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
@@ -268,10 +293,18 @@ public:
return WriteBatch(batch, fSync);
}
+ //! @returns filesystem path to the on-disk data.
+ std::optional<fs::path> StoragePath() {
+ if (m_is_memory) {
+ return {};
+ }
+ return m_path;
+ }
+
template <typename K>
bool Exists(const K& key) const
{
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ DataStream ssKey{};
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
@@ -313,7 +346,7 @@ public:
template<typename K>
size_t EstimateSize(const K& key_begin, const K& key_end) const
{
- CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);
+ DataStream ssKey1{}, ssKey2{};
ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey1 << key_begin;
diff --git a/src/deploymentinfo.cpp b/src/deploymentinfo.cpp
index 246932e56d..185a7dcb54 100644
--- a/src/deploymentinfo.cpp
+++ b/src/deploymentinfo.cpp
@@ -6,6 +6,8 @@
#include <consensus/params.h>
+#include <string_view>
+
const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {
{
/*.name =*/ "testdummy",
@@ -34,3 +36,19 @@ std::string DeploymentName(Consensus::BuriedDeployment dep)
} // no default case, so the compiler can warn about missing cases
return "";
}
+
+std::optional<Consensus::BuriedDeployment> GetBuriedDeployment(const std::string_view name)
+{
+ if (name == "segwit") {
+ return Consensus::BuriedDeployment::DEPLOYMENT_SEGWIT;
+ } else if (name == "bip34") {
+ return Consensus::BuriedDeployment::DEPLOYMENT_HEIGHTINCB;
+ } else if (name == "dersig") {
+ return Consensus::BuriedDeployment::DEPLOYMENT_DERSIG;
+ } else if (name == "cltv") {
+ return Consensus::BuriedDeployment::DEPLOYMENT_CLTV;
+ } else if (name == "csv") {
+ return Consensus::BuriedDeployment::DEPLOYMENT_CSV;
+ }
+ return std::nullopt;
+}
diff --git a/src/deploymentinfo.h b/src/deploymentinfo.h
index 8b909dedb4..72ba297ea0 100644
--- a/src/deploymentinfo.h
+++ b/src/deploymentinfo.h
@@ -7,6 +7,7 @@
#include <consensus/params.h>
+#include <optional>
#include <string>
struct VBDeploymentInfo {
@@ -26,4 +27,6 @@ inline std::string DeploymentName(Consensus::DeploymentPos pos)
return VersionBitsDeploymentInfo[pos].name;
}
+std::optional<Consensus::BuriedDeployment> GetBuriedDeployment(const std::string_view deployment_name);
+
#endif // BITCOIN_DEPLOYMENTINFO_H
diff --git a/src/deploymentstatus.cpp b/src/deploymentstatus.cpp
index 3a524af29e..71f2702430 100644
--- a/src/deploymentstatus.cpp
+++ b/src/deploymentstatus.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/deploymentstatus.h b/src/deploymentstatus.h
index 9f5919f71b..03d3c531cc 100644
--- a/src/deploymentstatus.h
+++ b/src/deploymentstatus.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/external_signer.cpp b/src/external_signer.cpp
index 094314e878..5524b943f4 100644
--- a/src/external_signer.cpp
+++ b/src/external_signer.cpp
@@ -1,12 +1,12 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 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 <chainparams.h>
+#include <common/run_command.h>
#include <core_io.h>
#include <psbt.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <external_signer.h>
#include <algorithm>
@@ -16,7 +16,7 @@
ExternalSigner::ExternalSigner(const std::string& command, const std::string chain, const std::string& fingerprint, const std::string name): m_command(command), m_chain(chain), m_fingerprint(fingerprint), m_name(name) {}
-const std::string ExternalSigner::NetworkArg() const
+std::string ExternalSigner::NetworkArg() const
{
return " --chain " + m_chain;
}
@@ -81,6 +81,9 @@ bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::str
for (const auto& entry : input.hd_keypaths) {
if (parsed_m_fingerprint == MakeUCharSpan(entry.second.fingerprint)) return true;
}
+ for (const auto& entry : input.m_tap_bip32_paths) {
+ if (parsed_m_fingerprint == MakeUCharSpan(entry.second.second.fingerprint)) return true;
+ }
return false;
};
diff --git a/src/external_signer.h b/src/external_signer.h
index e40fd7f010..90f07478e3 100644
--- a/src/external_signer.h
+++ b/src/external_signer.h
@@ -24,7 +24,7 @@ private:
//! Bitcoin mainnet, testnet, etc
std::string m_chain;
- const std::string NetworkArg() const;
+ std::string NetworkArg() const;
public:
//! @param[in] command the command which handles interaction with the external signer
diff --git a/src/flatfile.cpp b/src/flatfile.cpp
index 0fecf4f504..d6e84d02c1 100644
--- a/src/flatfile.cpp
+++ b/src/flatfile.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/fs.cpp b/src/fs.cpp
index 07cce269ed..64411fe41f 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -60,36 +60,20 @@ FileLock::~FileLock()
}
}
-static bool IsWSL()
-{
- struct utsname uname_data;
- return uname(&uname_data) == 0 && std::string(uname_data.version).find("Microsoft") != std::string::npos;
-}
-
bool FileLock::TryLock()
{
if (fd == -1) {
return false;
}
- // Exclusive file locking is broken on WSL using fcntl (issue #18622)
- // This workaround can be removed once the bug on WSL is fixed
- static const bool is_wsl = IsWSL();
- if (is_wsl) {
- if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
- reason = GetErrorReason();
- return false;
- }
- } else {
- struct flock lock;
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- if (fcntl(fd, F_SETLK, &lock) == -1) {
- reason = GetErrorReason();
- return false;
- }
+ struct flock lock;
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ if (fcntl(fd, F_SETLK, &lock) == -1) {
+ reason = GetErrorReason();
+ return false;
}
return true;
diff --git a/src/fs.h b/src/fs.h
index ac58c4a2ba..0ece256acb 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -35,7 +35,7 @@ public:
// Allow path objects arguments for compatibility.
path(std::filesystem::path path) : std::filesystem::path::path(std::move(path)) {}
path& operator=(std::filesystem::path path) { std::filesystem::path::operator=(std::move(path)); return *this; }
- path& operator/=(std::filesystem::path path) { std::filesystem::path::operator/=(std::move(path)); return *this; }
+ path& operator/=(std::filesystem::path path) { std::filesystem::path::operator/=(path); return *this; }
// Allow literal string arguments, which are safe as long as the literals are ASCII.
path(const char* c) : std::filesystem::path(c) {}
diff --git a/src/hash.cpp b/src/hash.cpp
index 06caaac6ee..1ece8c5a79 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2021 The Bitcoin Core developers
+// Copyright (c) 2013-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/hash.h b/src/hash.h
index b1ff3acc7d..2e3ed11b43 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -1,16 +1,18 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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_HASH_H
#define BITCOIN_HASH_H
+#include <attributes.h>
#include <crypto/common.h>
#include <crypto/ripemd160.h>
#include <crypto/sha256.h>
#include <prevector.h>
#include <serialize.h>
+#include <span.h>
#include <uint256.h>
#include <version.h>
@@ -165,6 +167,39 @@ public:
};
/** Reads data from an underlying stream, while hashing the read data. */
+template <typename Source>
+class HashVerifier : public HashWriter
+{
+private:
+ Source& m_source;
+
+public:
+ explicit HashVerifier(Source& source LIFETIMEBOUND) : m_source{source} {}
+
+ void read(Span<std::byte> dst)
+ {
+ m_source.read(dst);
+ this->write(dst);
+ }
+
+ void ignore(size_t num_bytes)
+ {
+ std::byte data[1024];
+ while (num_bytes > 0) {
+ size_t now = std::min<size_t>(num_bytes, 1024);
+ read({data, now});
+ num_bytes -= now;
+ }
+ }
+
+ template <typename T>
+ HashVerifier<Source>& operator>>(T&& obj)
+ {
+ ::Unserialize(*this, obj);
+ return *this;
+ }
+};
+
template<typename Source>
class CHashVerifier : public CHashWriter
{
@@ -199,6 +234,30 @@ public:
}
};
+/** Writes data to an underlying source stream, while hashing the written data. */
+template <typename Source>
+class HashedSourceWriter : public CHashWriter
+{
+private:
+ Source& m_source;
+
+public:
+ explicit HashedSourceWriter(Source& source LIFETIMEBOUND) : CHashWriter{source.GetType(), source.GetVersion()}, m_source{source} {}
+
+ void write(Span<const std::byte> src)
+ {
+ m_source.write(src);
+ CHashWriter::write(src);
+ }
+
+ template <typename T>
+ HashedSourceWriter& operator<<(const T& obj)
+ {
+ ::Serialize(*this, obj);
+ return *this;
+ }
+};
+
/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
@@ -223,4 +282,12 @@ void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char he
*/
HashWriter TaggedHash(const std::string& tag);
+/** Compute the 160-bit RIPEMD-160 hash of an array. */
+inline uint160 RIPEMD160(Span<const unsigned char> data)
+{
+ uint160 result;
+ CRIPEMD160().Write(data.data(), data.size()).Finalize(result.begin());
+ return result;
+}
+
#endif // BITCOIN_HASH_H
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 4e7e72b037..86166a5ca4 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -160,7 +160,7 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
JSONRPCRequest jreq;
jreq.context = context;
- jreq.peerAddr = req->GetPeer().ToString();
+ jreq.peerAddr = req->GetPeer().ToStringAddrPort();
if (!RPCAuthorized(authHeader.second, jreq.authUser)) {
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", jreq.peerAddr);
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 1a19555f76..942caa042d 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -21,12 +21,14 @@
#include <util/threadnames.h>
#include <util/translation.h>
+#include <condition_variable>
#include <cstdio>
#include <cstdlib>
#include <deque>
#include <memory>
#include <optional>
#include <string>
+#include <unordered_set>
#include <sys/types.h>
#include <sys/stat.h>
@@ -34,6 +36,7 @@
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/http.h>
+#include <event2/http_struct.h>
#include <event2/keyvalq_struct.h>
#include <event2/thread.h>
#include <event2/util.h>
@@ -146,6 +149,10 @@ static GlobalMutex g_httppathhandlers_mutex;
static std::vector<HTTPPathHandler> pathHandlers GUARDED_BY(g_httppathhandlers_mutex);
//! Bound listening sockets
static std::vector<evhttp_bound_socket *> boundSockets;
+//! Track active requests
+static GlobalMutex g_requests_mutex;
+static std::condition_variable g_requests_cv;
+static std::unordered_set<evhttp_request*> g_requests GUARDED_BY(g_requests_mutex);
/** Check if a network address is allowed to access the HTTP server */
static bool ClientAllowed(const CNetAddr& netaddr)
@@ -192,24 +199,32 @@ std::string RequestMethodString(HTTPRequest::RequestMethod m)
switch (m) {
case HTTPRequest::GET:
return "GET";
- break;
case HTTPRequest::POST:
return "POST";
- break;
case HTTPRequest::HEAD:
return "HEAD";
- break;
case HTTPRequest::PUT:
return "PUT";
- break;
- default:
+ case HTTPRequest::UNKNOWN:
return "unknown";
- }
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
/** HTTP request callback */
static void http_request_cb(struct evhttp_request* req, void* arg)
{
+ // Track requests and notify when a request is completed.
+ {
+ WITH_LOCK(g_requests_mutex, g_requests.insert(req));
+ g_requests_cv.notify_all();
+ evhttp_request_set_on_complete_cb(req, [](struct evhttp_request* req, void*) {
+ auto n{WITH_LOCK(g_requests_mutex, return g_requests.erase(req))};
+ assert(n == 1);
+ g_requests_cv.notify_all();
+ }, nullptr);
+ }
+
// Disable reading to work around a libevent bug, fixed in 2.2.0.
if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
evhttp_connection* conn = evhttp_request_get_connection(req);
@@ -225,7 +240,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
// Early address-based allow check
if (!ClientAllowed(hreq->GetPeer())) {
LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n",
- hreq->GetPeer().ToString());
+ hreq->GetPeer().ToStringAddrPort());
hreq->WriteReply(HTTP_FORBIDDEN);
return;
}
@@ -233,13 +248,13 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
// Early reject unknown HTTP methods
if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n",
- hreq->GetPeer().ToString());
+ hreq->GetPeer().ToStringAddrPort());
hreq->WriteReply(HTTP_BAD_METHOD);
return;
}
LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
- RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToString());
+ RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToStringAddrPort());
// Find registered handler for prefix
std::string strURI = hreq->GetURI();
@@ -282,7 +297,7 @@ static void http_reject_request_cb(struct evhttp_request* req, void*)
}
/** Event dispatcher thread */
-static bool ThreadHTTP(struct event_base* base)
+static void ThreadHTTP(struct event_base* base)
{
util::ThreadRename("http");
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_HTTP_SERVER);
@@ -290,7 +305,6 @@ static bool ThreadHTTP(struct event_base* base)
event_base_dispatch(base);
// Event loop will be interrupted by InterruptHTTPServer()
LogPrint(BCLog::HTTP, "Exited http event loop\n");
- return event_base_got_break(base) == 0;
}
/** Bind HTTP server to specified addresses */
@@ -462,15 +476,27 @@ void StopHTTPServer()
evhttp_del_accept_socket(eventHTTP, socket);
}
boundSockets.clear();
- if (eventBase) {
- LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n");
- if (g_thread_http.joinable()) g_thread_http.join();
+ {
+ WAIT_LOCK(g_requests_mutex, lock);
+ if (!g_requests.empty()) {
+ LogPrint(BCLog::HTTP, "Waiting for %d requests to stop HTTP server\n", g_requests.size());
+ }
+ g_requests_cv.wait(lock, []() EXCLUSIVE_LOCKS_REQUIRED(g_requests_mutex) {
+ return g_requests.empty();
+ });
}
if (eventHTTP) {
- evhttp_free(eventHTTP);
- eventHTTP = nullptr;
+ // Schedule a callback to call evhttp_free in the event base thread, so
+ // that evhttp_free does not need to be called again after the handling
+ // of unfinished request connections that follows.
+ event_base_once(eventBase, -1, EV_TIMEOUT, [](evutil_socket_t, short, void*) {
+ evhttp_free(eventHTTP);
+ eventHTTP = nullptr;
+ }, nullptr, nullptr);
}
if (eventBase) {
+ LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n");
+ if (g_thread_http.joinable()) g_thread_http.join();
event_base_free(eventBase);
eventBase = nullptr;
}
@@ -626,19 +652,14 @@ HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod() const
switch (evhttp_request_get_command(req)) {
case EVHTTP_REQ_GET:
return GET;
- break;
case EVHTTP_REQ_POST:
return POST;
- break;
case EVHTTP_REQ_HEAD:
return HEAD;
- break;
case EVHTTP_REQ_PUT:
return PUT;
- break;
default:
return UNKNOWN;
- break;
}
}
diff --git a/src/httpserver.h b/src/httpserver.h
index 5ab3f18927..036a39a023 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/i2p.cpp b/src/i2p.cpp
index 28be8009dc..a3bfc23a65 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,6 +18,7 @@
#include <util/spanparsing.h>
#include <util/strencodings.h>
#include <util/system.h>
+#include <util/threadinterrupt.h>
#include <chrono>
#include <memory>
@@ -205,7 +206,7 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error)
}
const Reply& lookup_reply =
- SendRequestAndGetReply(*sock, strprintf("NAMING LOOKUP NAME=%s", to.ToStringIP()));
+ SendRequestAndGetReply(*sock, strprintf("NAMING LOOKUP NAME=%s", to.ToStringAddr()));
const std::string& dest = lookup_reply.Get("VALUE");
@@ -232,7 +233,7 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error)
throw std::runtime_error(strprintf("\"%s\"", connect_reply.full));
} catch (const std::runtime_error& e) {
- Log("Error connecting to %s: %s", to.ToString(), e.what());
+ Log("Error connecting to %s: %s", to.ToStringAddrPort(), e.what());
CheckControlSock();
return false;
}
@@ -301,7 +302,7 @@ std::unique_ptr<Sock> Session::Hello() const
}
if (!ConnectSocketDirectly(m_control_host, *sock, nConnectTimeout, true)) {
- throw std::runtime_error(strprintf("Cannot connect to %s", m_control_host.ToString()));
+ throw std::runtime_error(strprintf("Cannot connect to %s", m_control_host.ToStringAddrPort()));
}
SendRequestAndGetReply(*sock, "HELLO VERSION MIN=3.1 MAX=3.1");
@@ -335,7 +336,7 @@ void Session::GenerateAndSavePrivateKey(const Sock& sock)
{
DestGenerate(sock);
- // umask is set to 077 in init.cpp, which is ok (unless -sysperms is given)
+ // umask is set to 0077 in util/system.cpp, which is ok.
if (!WriteBinaryFile(m_private_key_file,
std::string(m_private_key.begin(), m_private_key.end()))) {
throw std::runtime_error(
@@ -370,7 +371,7 @@ void Session::CreateIfNotCreatedAlready()
const auto session_type = m_transient ? "transient" : "persistent";
const auto session_id = GetRandHash().GetHex().substr(0, 10); // full is overkill, too verbose in the logs
- Log("Creating %s SAM session %s with %s", session_type, session_id, m_control_host.ToString());
+ Log("Creating %s SAM session %s with %s", session_type, session_id, m_control_host.ToStringAddrPort());
auto sock = Hello();
@@ -379,7 +380,9 @@ void Session::CreateIfNotCreatedAlready()
// in the reply in DESTINATION=.
const Reply& reply = SendRequestAndGetReply(
*sock,
- strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT SIGNATURE_TYPE=7", session_id));
+ strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT SIGNATURE_TYPE=7 "
+ "inbound.quantity=1 outbound.quantity=1",
+ session_id));
m_private_key = DecodeI2PBase64(reply.Get("DESTINATION"));
} else {
@@ -395,7 +398,8 @@ void Session::CreateIfNotCreatedAlready()
const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key));
SendRequestAndGetReply(*sock,
- strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
+ strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s "
+ "inbound.quantity=3 outbound.quantity=3",
session_id,
private_key_b64));
}
@@ -407,7 +411,7 @@ void Session::CreateIfNotCreatedAlready()
Log("%s SAM session %s created, my address=%s",
Capitalize(session_type),
m_session_id,
- m_my_addr.ToString());
+ m_my_addr.ToStringAddrPort());
}
std::unique_ptr<Sock> Session::StreamAccept()
diff --git a/src/i2p.h b/src/i2p.h
index ebbcb437da..6e7bafc945 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,8 +9,8 @@
#include <fs.h>
#include <netaddress.h>
#include <sync.h>
-#include <threadinterrupt.h>
#include <util/sock.h>
+#include <util/threadinterrupt.h>
#include <memory>
#include <optional>
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 88c2ce98fa..8a311296c2 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,8 +6,10 @@
#include <index/base.h>
#include <interfaces/chain.h>
#include <kernel/chain.h>
+#include <logging.h>
#include <node/blockstorage.h>
#include <node/context.h>
+#include <node/database_args.h>
#include <node/interface_ui.h>
#include <shutdown.h>
#include <tinyformat.h>
@@ -34,7 +36,7 @@ static void FatalError(const char* fmt, const Args&... args)
std::string strMessage = tfm::format(fmt, args...);
SetMiscWarning(Untranslated(strMessage));
LogPrintf("*** %s\n", strMessage);
- AbortError(_("A fatal internal error occurred, see debug.log for details"));
+ InitError(_("A fatal internal error occurred, see debug.log for details"));
StartShutdown();
}
@@ -48,7 +50,13 @@ CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash)
}
BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) :
- CDBWrapper(path, n_cache_size, f_memory, f_wipe, f_obfuscate)
+ CDBWrapper{DBParams{
+ .path = path,
+ .cache_bytes = n_cache_size,
+ .memory_only = f_memory,
+ .wipe_data = f_wipe,
+ .obfuscate = f_obfuscate,
+ .options = [] { DBOptions options; node::ReadDatabaseArgs(gArgs, options); return options; }()}}
{}
bool BaseIndex::DB::ReadBestBlock(CBlockLocator& locator) const
@@ -298,6 +306,10 @@ void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const
}
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block.get());
if (CustomAppend(block_info)) {
+ // Setting the best block index is intentionally the last step of this
+ // function, so BlockUntilSyncedToCurrentChain callers waiting for the
+ // best block index to be updated can rely on the block being fully
+ // processed, and the index object being safe to delete.
SetBestBlockIndex(pindex);
} else {
FatalError("%s: Failed to write block %s to index",
@@ -411,13 +423,21 @@ IndexSummary BaseIndex::GetSummary() const
return summary;
}
-void BaseIndex::SetBestBlockIndex(const CBlockIndex* block) {
- assert(!node::fPruneMode || AllowPrune());
+void BaseIndex::SetBestBlockIndex(const CBlockIndex* block)
+{
+ assert(!m_chainstate->m_blockman.IsPruneMode() || AllowPrune());
- m_best_block_index = block;
if (AllowPrune() && block) {
node::PruneLockInfo prune_lock;
prune_lock.height_first = block->nHeight;
WITH_LOCK(::cs_main, m_chainstate->m_blockman.UpdatePruneLock(GetName(), prune_lock));
}
+
+ // Intentionally set m_best_block_index as the last step in this function,
+ // after updating prune locks above, and after making any other references
+ // to *this, so the BlockUntilSyncedToCurrentChain function (which checks
+ // m_best_block_index as an optimization) can be used to wait for the last
+ // BlockConnected notification and safely assume that prune locks are
+ // updated and that the index object is safe to delete.
+ m_best_block_index = block;
}
diff --git a/src/index/base.h b/src/index/base.h
index 349178a535..231f36b605 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,7 +7,7 @@
#include <dbwrapper.h>
#include <interfaces/chain.h>
-#include <threadinterrupt.h>
+#include <util/threadinterrupt.h>
#include <validationinterface.h>
#include <string>
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index 292e11c874..59bf6d34cf 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -157,9 +157,7 @@ bool BlockFilterIndex::ReadFilterFromDisk(const FlatFilePos& pos, const uint256&
std::vector<uint8_t> encoded_filter;
try {
filein >> block_hash >> encoded_filter;
- uint256 result;
- CHash256().Write(encoded_filter).Finalize(result);
- if (result != hash) return error("Checksum mismatch in filter decode.");
+ if (Hash(encoded_filter) != hash) return error("Checksum mismatch in filter decode.");
filter = BlockFilter(GetFilterType(), block_hash, std::move(encoded_filter), /*skip_decode_check=*/true);
}
catch (const std::exception& e) {
diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h
index 9e69388dc8..ce1961c776 100644
--- a/src/index/blockfilterindex.h
+++ b/src/index/blockfilterindex.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index d3559b1b75..4d637e217a 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,6 +7,7 @@
#include <crypto/muhash.h>
#include <index/coinstatsindex.h>
#include <kernel/coinstats.h>
+#include <logging.h>
#include <node/blockstorage.h>
#include <serialize.h>
#include <txdb.h>
@@ -144,17 +145,13 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
}
}
- // TODO: Deduplicate BIP30 related code
- bool is_bip30_block{(block.height == 91722 && block.hash == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) ||
- (block.height == 91812 && block.hash == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))};
-
// Add the new utxos created from the block
assert(block.data);
for (size_t i = 0; i < block.data->vtx.size(); ++i) {
const auto& tx{block.data->vtx.at(i)};
// Skip duplicate txid coinbase transactions (BIP30).
- if (is_bip30_block && tx->IsCoinBase()) {
+ if (IsBIP30Unspendable(*pindex) && tx->IsCoinBase()) {
m_total_unspendable_amount += block_subsidy;
m_total_unspendables_bip30 += block_subsidy;
continue;
diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h
index aa0d7f9fd5..21ce4c4767 100644
--- a/src/index/coinstatsindex.h
+++ b/src/index/coinstatsindex.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index a4fe1b611e..9095e7afeb 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 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 <index/txindex.h>
#include <index/disktxpos.h>
+#include <logging.h>
#include <node/blockstorage.h>
#include <util/system.h>
#include <validation.h>
diff --git a/src/index/txindex.h b/src/index/txindex.h
index 4cea35045d..ef835fe5d7 100644
--- a/src/index/txindex.h
+++ b/src/index/txindex.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/init.cpp b/src/init.cpp
index 25b40c6c6e..8a45c38ce3 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -37,14 +37,17 @@
#include <net_processing.h>
#include <netbase.h>
#include <netgroup.h>
+#include <node/blockmanager_args.h>
#include <node/blockstorage.h>
#include <node/caches.h>
#include <node/chainstate.h>
+#include <node/chainstatemanager_args.h>
#include <node/context.h>
#include <node/interface_ui.h>
#include <node/mempool_args.h>
#include <node/mempool_persist_args.h>
#include <node/miner.h>
+#include <node/txreconciliation.h>
#include <node/validation_cache_args.h>
#include <policy/feerate.h>
#include <policy/fees.h>
@@ -65,7 +68,6 @@
#include <torcontrol.h>
#include <txdb.h>
#include <txmempool.h>
-#include <txorphanage.h>
#include <util/asmap.h>
#include <util/check.h>
#include <util/moneystr.h>
@@ -121,12 +123,11 @@ using node::ShouldPersistMempool;
using node::NodeContext;
using node::ThreadImport;
using node::VerifyLoadedChainstate;
-using node::fPruneMode;
using node::fReindex;
-using node::nPruneTarget;
-static const bool DEFAULT_PROXYRANDOMIZE = true;
-static const bool DEFAULT_REST_ENABLE = false;
+static constexpr bool DEFAULT_PROXYRANDOMIZE{true};
+static constexpr bool DEFAULT_REST_ENABLE{false};
+static constexpr bool DEFAULT_I2P_ACCEPT_INCOMING{true};
#ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
@@ -146,7 +147,7 @@ static const char* BITCOIN_PID_FILENAME = "bitcoind.pid";
static fs::path GetPidFile(const ArgsManager& args)
{
- return AbsPathForConfigVal(args.GetPathArg("-pid", BITCOIN_PID_FILENAME));
+ return AbsPathForConfigVal(args, args.GetPathArg("-pid", BITCOIN_PID_FILENAME));
}
[[nodiscard]] static bool CreatePidFile(const ArgsManager& args)
@@ -189,8 +190,24 @@ static fs::path GetPidFile(const ArgsManager& args)
// shutdown thing.
//
+#if HAVE_SYSTEM
+static void ShutdownNotify(const ArgsManager& args)
+{
+ std::vector<std::thread> threads;
+ for (const auto& cmd : args.GetArgs("-shutdownnotify")) {
+ threads.emplace_back(runCommand, cmd);
+ }
+ for (auto& t : threads) {
+ t.join();
+ }
+}
+#endif
+
void Interrupt(NodeContext& node)
{
+#if HAVE_SYSTEM
+ ShutdownNotify(*node.args);
+#endif
InterruptHTTPServer();
InterruptHTTPRPC();
InterruptRPC();
@@ -439,11 +456,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
#if HAVE_SYSTEM
argsman.AddArg("-startupnotify=<cmd>", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
-#endif
-#ifndef WIN32
- argsman.AddArg("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
-#else
- hidden_args.emplace_back("-sysperms");
+ argsman.AddArg("-shutdownnotify=<cmd>", "Execute command immediately before beginning shutdown. The need for shutdown may be urgent, so be careful not to delay it long (if the command doesn't require interaction with the server, consider having it fork into the background).", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
#endif
argsman.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-blockfilterindex=<type>",
@@ -463,7 +476,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-externalip=<ip>", "Specify your own public address", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-fixedseeds", strprintf("Allow fixed seeds if DNS seeds don't provide peers (default: %u)", DEFAULT_FIXEDSEEDS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
- argsman.AddArg("-listen", "Accept connections from outside (default: 1 if no -proxy or -connect)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-listen", strprintf("Accept connections from outside (default: %u if no -proxy or -connect)", DEFAULT_LISTEN), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-listenonion", strprintf("Automatically create Tor onion service (default: %d)", DEFAULT_LISTEN_ONION), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxconnections=<n>", strprintf("Maintain at most <n> connections to peers (default: %u). This limit does not apply to connections manually added via -addnode or the addnode RPC, which have a separate limit of %u.", DEFAULT_MAX_PEER_CONNECTIONS, MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxreceivebuffer=<n>", strprintf("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -472,10 +485,11 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target per 24h. Limit does not apply to peers with 'download' permission or blocks created within past week. 0 = no limit (default: %s). Optional suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000 base while uppercase is 1024 base", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
- argsman.AddArg("-i2pacceptincoming", "If set and -i2psam is also set then incoming I2P connections are accepted via the SAM proxy. If this is not set but -i2psam is set then only outgoing connections will be made to the I2P network. Ignored if -i2psam is not set. Listening for incoming I2P connections is done through the SAM proxy, not by binding to a local address and port (default: 1)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
// TODO: remove the sentence "Nodes not using ... incoming connections." once the changes from
// https://github.com/bitcoin/bitcoin/pull/23542 have become widespread.
argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port>. Nodes not using the default ports (default: %u, testnet: %u, signet: %u, regtest: %u) are unlikely to get incoming connections. Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
@@ -552,7 +566,10 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
- argsman.AddArg("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
+ argsman.AddArg("-maxtipage=<n>",
+ strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)",
+ Ticks<std::chrono::seconds>(DEFAULT_MAX_TIP_AGE)),
+ ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in " + CURRENCY_UNIT + "/kvB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
@@ -580,7 +597,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
argsman.AddArg("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
argsman.AddArg("-rpcauth=<userpw>", "Username and HMAC-SHA-256 hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
- argsman.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
+ argsman.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
argsman.AddArg("-rpcdoccheck", strprintf("Throw a non-fatal error at runtime if the documentation for an RPC is incorrect (default: %u)", DEFAULT_RPC_DOC_CHECK), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
@@ -713,10 +730,13 @@ void InitParameterInteraction(ArgsManager& args)
LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__);
}
- // disable whitelistrelay in blocksonly mode
if (args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
+ // disable whitelistrelay in blocksonly mode
if (args.SoftSetBoolArg("-whitelistrelay", false))
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__);
+ // Reduce default mempool size in blocksonly mode to avoid unexpected resource usage
+ if (args.SoftSetArg("-maxmempool", ToString(DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB)))
+ LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -maxmempool=%d\n", __func__, DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB);
}
// Forcing relay from whitelisted hosts implies we will accept relays from them in the first place.
@@ -795,10 +815,6 @@ bool AppInitBasicSetup(const ArgsManager& args)
}
#ifndef WIN32
- if (!args.GetBoolArg("-sysperms", false)) {
- umask(077);
- }
-
// Clean shutdown on SIGTERM
registerSignalHandler(SIGTERM, HandleSIGTERM);
registerSignalHandler(SIGINT, HandleSIGTERM);
@@ -850,7 +866,7 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
InitWarning(warnings);
}
- if (!fs::is_directory(gArgs.GetBlocksDirPath())) {
+ if (!fs::is_directory(args.GetBlocksDirPath())) {
return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), args.GetArg("-blocksdir", "")));
}
@@ -928,37 +944,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
init::SetLoggingCategories(args);
init::SetLoggingLevel(args);
- fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
- fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
-
- hashAssumeValid = uint256S(args.GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex()));
-
- if (args.IsArgSet("-minimumchainwork")) {
- const std::string minChainWorkStr = args.GetArg("-minimumchainwork", "");
- if (!IsHexNumber(minChainWorkStr)) {
- return InitError(strprintf(Untranslated("Invalid non-hex (%s) minimum chain work value specified"), minChainWorkStr));
- }
- nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr));
- } else {
- nMinimumChainWork = UintToArith256(chainparams.GetConsensus().nMinimumChainWork);
- }
-
- // block pruning; get the amount of disk space (in MiB) to allot for block & undo files
- int64_t nPruneArg = args.GetIntArg("-prune", 0);
- if (nPruneArg < 0) {
- return InitError(_("Prune cannot be configured with a negative value."));
- }
- nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024;
- if (nPruneArg == 1) { // manual pruning: -prune=1
- nPruneTarget = std::numeric_limits<uint64_t>::max();
- fPruneMode = true;
- } else if (nPruneTarget) {
- 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));
- }
- fPruneMode = true;
- }
-
nConnectTimeout = args.GetIntArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
if (nConnectTimeout <= 0) {
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
@@ -993,8 +978,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
if (args.GetIntArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1)
return InitError(Untranslated("Unknown rpcserialversion requested."));
- nMaxTipAge = args.GetIntArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
-
if (args.GetBoolArg("-reindex-chainstate", false)) {
// indexes that must be deactivated to prevent index corruption, see #24630
if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
@@ -1042,6 +1025,21 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
}
#endif // USE_SYSCALL_SANDBOX
+ // Also report errors from parsing before daemonization
+ {
+ ChainstateManager::Options chainman_opts_dummy{
+ .chainparams = chainparams,
+ .datadir = args.GetDataDirNet(),
+ };
+ if (const auto error{ApplyArgsManOptions(args, chainman_opts_dummy)}) {
+ return InitError(*error);
+ }
+ node::BlockManager::Options blockman_opts_dummy{};
+ if (const auto error{ApplyArgsManOptions(args, blockman_opts_dummy)}) {
+ return InitError(*error);
+ }
+ }
+
return true;
}
@@ -1144,7 +1142,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
LogPrintf("Script verification uses %d additional threads\n", script_threads);
if (script_threads >= 1) {
- g_parallel_script_checks = true;
StartScriptCheckWorkerThreads(script_threads);
}
@@ -1214,7 +1211,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (args.IsArgSet("-asmap")) {
fs::path asmap_path = args.GetPathArg("-asmap", DEFAULT_ASMAP_FILENAME);
if (!asmap_path.is_absolute()) {
- asmap_path = gArgs.GetDataDirNet() / asmap_path;
+ asmap_path = args.GetDataDirNet() / asmap_path;
}
if (!fs::exists(asmap_path)) {
InitError(strprintf(_("Could not find asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
@@ -1244,7 +1241,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
assert(!node.banman);
- node.banman = std::make_unique<BanMan>(gArgs.GetDataDirNet() / "banlist", &uiInterface, args.GetIntArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
+ node.banman = std::make_unique<BanMan>(args.GetDataDirNet() / "banlist", &uiInterface, args.GetIntArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman);
node.connman = std::make_unique<CConnman>(GetRand<uint64_t>(),
GetRand<uint64_t>(),
@@ -1255,6 +1252,51 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// as they would never get updated.
if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(args));
+ // Check port numbers
+ for (const std::string port_option : {
+ "-port",
+ "-rpcport",
+ }) {
+ if (args.IsArgSet(port_option)) {
+ const std::string port = args.GetArg(port_option, "");
+ uint16_t n;
+ if (!ParseUInt16(port, &n) || n == 0) {
+ return InitError(InvalidPortErrMsg(port_option, port));
+ }
+ }
+ }
+
+ for (const std::string port_option : {
+ "-i2psam",
+ "-onion",
+ "-proxy",
+ "-rpcbind",
+ "-torcontrol",
+ "-whitebind",
+ "-zmqpubhashblock",
+ "-zmqpubhashtx",
+ "-zmqpubrawblock",
+ "-zmqpubrawtx",
+ "-zmqpubsequence",
+ }) {
+ for (const std::string& socket_addr : args.GetArgs(port_option)) {
+ std::string host_out;
+ uint16_t port_out{0};
+ if (!SplitHostPort(socket_addr, port_out, host_out)) {
+ return InitError(InvalidPortErrMsg(port_option, socket_addr));
+ }
+ }
+ }
+
+ for (const std::string& socket_addr : args.GetArgs("-bind")) {
+ std::string host_out;
+ uint16_t port_out{0};
+ std::string bind_socket_addr = socket_addr.substr(0, socket_addr.rfind('='));
+ if (!SplitHostPort(bind_socket_addr, port_out, host_out)) {
+ return InitError(InvalidPortErrMsg("-bind", socket_addr));
+ }
+ }
+
// sanitize comments per BIP-0014, format user agent and check total size
std::vector<std::string> uacomments;
for (const std::string& cmt : args.GetArgs("-uacomment")) {
@@ -1388,6 +1430,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
fReindex = args.GetBoolArg("-reindex", false);
bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
+ ChainstateManager::Options chainman_opts{
+ .chainparams = chainparams,
+ .datadir = args.GetDataDirNet(),
+ .adjusted_time_callback = GetAdjustedTime,
+ };
+ Assert(!ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction
+
+ node::BlockManager::Options blockman_opts{};
+ Assert(!ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
// cache size calculations
CacheSizes cache_sizes = CalculateCacheSizes(args, g_enabled_filter_types.size());
@@ -1424,20 +1475,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
- const ChainstateManager::Options chainman_opts{
- .chainparams = chainparams,
- .adjusted_time_callback = GetAdjustedTime,
- };
- node.chainman = std::make_unique<ChainstateManager>(chainman_opts);
+ node.chainman = std::make_unique<ChainstateManager>(chainman_opts, blockman_opts);
ChainstateManager& chainman = *node.chainman;
node::ChainstateLoadOptions options;
options.mempool = Assert(node.mempool.get());
options.reindex = node::fReindex;
options.reindex_chainstate = fReindexChainState;
- options.prune = node::fPruneMode;
+ options.prune = chainman.m_blockman.IsPruneMode();
options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
+ options.require_full_verification = args.IsArgSet("-checkblocks") || args.IsArgSet("-checklevel");
options.check_interrupt = ShutdownRequested;
options.coins_error_cb = [] {
uiInterface.ThreadSafeMessageBox(
@@ -1469,7 +1517,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
}
- if (status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB) {
+ if (status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || status == node::ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE) {
return InitError(error);
}
@@ -1528,7 +1576,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
- g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /* cache size */ 0, false, fReindex);
+ g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /*cache_size=*/0, false, fReindex);
if (!g_coin_stats_index->Start()) {
return false;
}
@@ -1545,7 +1593,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// if pruning, perform the initial blockstore prune
// after any wallet rescanning has taken place.
- if (fPruneMode) {
+ if (chainman.m_blockman.IsPruneMode()) {
if (!fReindex) {
LOCK(cs_main);
for (Chainstate* chainstate : chainman.GetAll()) {
@@ -1560,15 +1608,36 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 11: import blocks
- if (!CheckDiskSpace(gArgs.GetDataDirNet())) {
- InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(gArgs.GetDataDirNet()))));
+ if (!CheckDiskSpace(args.GetDataDirNet())) {
+ InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(args.GetDataDirNet()))));
return false;
}
- if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
- InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(gArgs.GetBlocksDirPath()))));
+ if (!CheckDiskSpace(args.GetBlocksDirPath())) {
+ InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(args.GetBlocksDirPath()))));
return false;
}
+ int chain_active_height = WITH_LOCK(cs_main, return chainman.ActiveChain().Height());
+
+ // On first startup, warn on low block storage space
+ if (!fReindex && !fReindexChainState && chain_active_height <= 1) {
+ uint64_t assumed_chain_bytes{chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024};
+ uint64_t additional_bytes_needed{
+ chainman.m_blockman.IsPruneMode() ?
+ std::min(chainman.m_blockman.GetPruneTarget(), assumed_chain_bytes) :
+ assumed_chain_bytes};
+
+ if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) {
+ InitWarning(strprintf(_(
+ "Disk space for %s may not accommodate the block files. " \
+ "Approximately %u GB of data will be stored in this directory."
+ ),
+ fs::quoted(fs::PathToString(args.GetBlocksDirPath())),
+ chainparams.AssumedBlockchainSize()
+ ));
+ }
+ }
+
// Either install a handler to notify us when genesis activates, or set fHaveGenesis directly.
// No locking, as this happens before any background thread is started.
boost::signals2::connection block_notify_genesis_wait_connection;
@@ -1618,8 +1687,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 12: start node
- int chain_active_height;
-
//// debug print
{
LOCK(cs_main);
@@ -1639,7 +1706,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (node.peerman) node.peerman->SetBestHeight(chain_active_height);
// Map ports with UPnP or NAT-PMP.
- StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), gArgs.GetBoolArg("-natpmp", DEFAULT_NATPMP));
+ StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), args.GetBoolArg("-natpmp", DEFAULT_NATPMP));
CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
@@ -1663,7 +1730,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
const auto BadPortWarning = [](const char* prefix, uint16_t port) {
return strprintf(_("%s request to listen on port %u. This port is considered \"bad\" and "
- "thus it is unlikely that any Bitcoin Core peers connect to it. See "
+ "thus it is unlikely that any peer will connect to it. See "
"doc/p2p-bad-ports.md for details and a full list."),
prefix,
port);
@@ -1725,7 +1792,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (connOptions.onion_binds.size() > 1) {
InitWarning(strprintf(_("More than one onion bind address is provided. Using %s "
"for the automatically created Tor onion service."),
- onion_service_target.ToStringIPPort()));
+ onion_service_target.ToStringAddrPort()));
}
StartTorControl(onion_service_target);
}
@@ -1752,6 +1819,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (connect.size() != 1 || connect[0] != "0") {
connOptions.m_specified_outgoing = connect;
}
+ if (!connOptions.m_specified_outgoing.empty() && !connOptions.vSeedNodes.empty()) {
+ LogPrintf("-seednode is ignored when -connect is used\n");
+ }
+
+ if (args.IsArgSet("-dnsseed") && args.GetBoolArg("-dnsseed", DEFAULT_DNSSEED) && args.IsArgSet("-proxy")) {
+ LogPrintf("-dnsseed is ignored when -connect is used and -proxy is specified\n");
+ }
}
const std::string& i2psam_arg = args.GetArg("-i2psam", "");
@@ -1770,7 +1844,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
SetReachable(NET_I2P, false);
}
- connOptions.m_i2p_accept_incoming = args.GetBoolArg("-i2pacceptincoming", true);
+ connOptions.m_i2p_accept_incoming = args.GetBoolArg("-i2pacceptincoming", DEFAULT_I2P_ACCEPT_INCOMING);
if (!node.connman->Start(*node.scheduler, connOptions)) {
return false;
diff --git a/src/init.h b/src/init.h
index e8e6a55eba..8c5b2e77d3 100644
--- a/src/init.h
+++ b/src/init.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp
index 2fa4add4e5..100b4ef7ee 100644
--- a/src/init/bitcoin-gui.cpp
+++ b/src/init/bitcoin-gui.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp
index 78bc3e5980..1418e63777 100644
--- a/src/init/bitcoin-node.cpp
+++ b/src/init/bitcoin-node.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp
index bb3bb945d0..e27be0e598 100644
--- a/src/init/bitcoin-qt.cpp
+++ b/src/init/bitcoin-qt.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/init/bitcoin-wallet.cpp b/src/init/bitcoin-wallet.cpp
index c8d499da10..f3a9ea267c 100644
--- a/src/init/bitcoin-wallet.cpp
+++ b/src/init/bitcoin-wallet.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp
index b473ebb805..7ad1f64e64 100644
--- a/src/init/bitcoind.cpp
+++ b/src/init/bitcoind.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/init/common.cpp b/src/init/common.cpp
index f2d2c5640a..791424f5f6 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -45,7 +45,7 @@ void AddLoggingArgs(ArgsManager& argsman)
void SetLoggingOptions(const ArgsManager& args)
{
LogInstance().m_print_to_file = !args.IsArgNegated("-debuglogfile");
- LogInstance().m_file_path = AbsPathForConfigVal(args.GetPathArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
+ LogInstance().m_file_path = AbsPathForConfigVal(args, args.GetPathArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", !args.GetBoolArg("-daemon", false));
LogInstance().m_log_timestamps = args.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
LogInstance().m_log_time_micros = args.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
@@ -121,7 +121,7 @@ bool StartLogging(const ArgsManager& args)
LogPrintf("Using data directory %s\n", fs::PathToString(gArgs.GetDataDirNet()));
// Only log conf file usage message if conf file actually exists.
- fs::path config_file_path = GetConfigFile(args.GetPathArg("-conf", BITCOIN_CONF_FILENAME));
+ fs::path config_file_path = args.GetConfigFilePath();
if (fs::exists(config_file_path)) {
LogPrintf("Config file: %s\n", fs::PathToString(config_file_path));
} else if (args.IsArgSet("-conf")) {
diff --git a/src/init/common.h b/src/init/common.h
index 53c860c297..44c3a502ee 100644
--- a/src/init/common.h
+++ b/src/init/common.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index 5fc0e540a9..a3fa753a98 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -1,10 +1,11 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 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_INTERFACES_CHAIN_H
#define BITCOIN_INTERFACES_CHAIN_H
+#include <blockfilter.h>
#include <primitives/transaction.h> // For CTransactionRef
#include <util/settings.h> // For util::SettingsValue
@@ -143,6 +144,13 @@ public:
//! or one of its ancestors.
virtual std::optional<int> findLocatorFork(const CBlockLocator& locator) = 0;
+ //! Returns whether a block filter index is available.
+ virtual bool hasBlockFilterIndex(BlockFilterType filter_type) = 0;
+
+ //! Returns whether any of the elements match the block via a BIP 157 block filter
+ //! or std::nullopt if the block filter for this block couldn't be found.
+ virtual std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const GCSFilter::ElementSet& filter_set) = 0;
+
//! Return whether node has the block and optionally return block metadata
//! or contents.
virtual bool findBlock(const uint256& hash, const FoundBlock& block={}) = 0;
@@ -260,8 +268,8 @@ public:
{
public:
virtual ~Notifications() {}
- virtual void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {}
- virtual void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {}
+ virtual void transactionAddedToMempool(const CTransactionRef& tx) {}
+ virtual void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {}
virtual void blockConnected(const BlockInfo& block) {}
virtual void blockDisconnected(const BlockInfo& block) {}
virtual void updatedBlockTip() {}
diff --git a/src/interfaces/echo.cpp b/src/interfaces/echo.cpp
deleted file mode 100644
index 9bbb42217b..0000000000
--- a/src/interfaces/echo.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2021 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 <interfaces/echo.h>
-
-#include <memory>
-
-namespace interfaces {
-namespace {
-class EchoImpl : public Echo
-{
-public:
- std::string echo(const std::string& echo) override { return echo; }
-};
-} // namespace
-std::unique_ptr<Echo> MakeEcho() { return std::make_unique<EchoImpl>(); }
-} // namespace interfaces
diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp
deleted file mode 100644
index adb7031cbc..0000000000
--- a/src/interfaces/handler.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2018-2021 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 <interfaces/handler.h>
-
-
-#include <boost/signals2/connection.hpp>
-#include <utility>
-
-namespace interfaces {
-namespace {
-
-class HandlerImpl : public Handler
-{
-public:
- explicit HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {}
-
- void disconnect() override { m_connection.disconnect(); }
-
- boost::signals2::scoped_connection m_connection;
-};
-
-class CleanupHandler : public Handler
-{
-public:
- explicit CleanupHandler(std::function<void()> cleanup) : m_cleanup(std::move(cleanup)) {}
- ~CleanupHandler() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; }
- void disconnect() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; }
- std::function<void()> m_cleanup;
-};
-
-} // namespace
-
-std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection)
-{
- return std::make_unique<HandlerImpl>(std::move(connection));
-}
-
-std::unique_ptr<Handler> MakeHandler(std::function<void()> cleanup)
-{
- return std::make_unique<CleanupHandler>(std::move(cleanup));
-}
-
-} // namespace interfaces
diff --git a/src/interfaces/handler.h b/src/interfaces/handler.h
index 11baf9dd65..7751d82347 100644
--- a/src/interfaces/handler.h
+++ b/src/interfaces/handler.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -29,10 +29,10 @@ public:
};
//! Return handler wrapping a boost signal connection.
-std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection);
+std::unique_ptr<Handler> MakeSignalHandler(boost::signals2::connection connection);
//! Return handler wrapping a cleanup function.
-std::unique_ptr<Handler> MakeHandler(std::function<void()> cleanup);
+std::unique_ptr<Handler> MakeCleanupHandler(std::function<void()> cleanup);
} // namespace interfaces
diff --git a/src/interfaces/init.cpp b/src/interfaces/init.cpp
deleted file mode 100644
index f0f8aa5fed..0000000000
--- a/src/interfaces/init.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2021 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 <interfaces/chain.h>
-#include <interfaces/echo.h>
-#include <interfaces/init.h>
-#include <interfaces/node.h>
-#include <interfaces/wallet.h>
-
-namespace interfaces {
-std::unique_ptr<Node> Init::makeNode() { return {}; }
-std::unique_ptr<Chain> Init::makeChain() { return {}; }
-std::unique_ptr<WalletLoader> Init::makeWalletLoader(Chain& chain) { return {}; }
-std::unique_ptr<Echo> Init::makeEcho() { return {}; }
-Ipc* Init::ipc() { return nullptr; }
-} // namespace interfaces
diff --git a/src/interfaces/init.h b/src/interfaces/init.h
index 2153076366..addc45aa26 100644
--- a/src/interfaces/init.h
+++ b/src/interfaces/init.h
@@ -1,10 +1,15 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 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_INTERFACES_INIT_H
#define BITCOIN_INTERFACES_INIT_H
+#include <interfaces/chain.h>
+#include <interfaces/echo.h>
+#include <interfaces/node.h>
+#include <interfaces/wallet.h>
+
#include <memory>
namespace node {
@@ -12,11 +17,7 @@ struct NodeContext;
} // namespace node
namespace interfaces {
-class Chain;
-class Echo;
class Ipc;
-class Node;
-class WalletLoader;
//! Initial interface created when a process is first started, and used to give
//! and get access to other interfaces (Node, Chain, Wallet, etc).
@@ -29,11 +30,11 @@ class Init
{
public:
virtual ~Init() = default;
- virtual std::unique_ptr<Node> makeNode();
- virtual std::unique_ptr<Chain> makeChain();
- virtual std::unique_ptr<WalletLoader> makeWalletLoader(Chain& chain);
- virtual std::unique_ptr<Echo> makeEcho();
- virtual Ipc* ipc();
+ virtual std::unique_ptr<Node> makeNode() { return nullptr; }
+ virtual std::unique_ptr<Chain> makeChain() { return nullptr; }
+ virtual std::unique_ptr<WalletLoader> makeWalletLoader(Chain& chain) { return nullptr; }
+ virtual std::unique_ptr<Echo> makeEcho() { return nullptr; }
+ virtual Ipc* ipc() { return nullptr; }
};
//! Return implementation of Init interface for the node process. If the argv
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index dbdb21eb91..7e87d5a523 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -177,11 +177,8 @@ public:
//! Is initial block download.
virtual bool isInitialBlockDownload() = 0;
- //! Get reindex.
- virtual bool getReindex() = 0;
-
- //! Get importing.
- virtual bool getImporting() = 0;
+ //! Is loading blocks.
+ virtual bool isLoadingBlocks() = 0;
//! Set network active.
virtual void setNetworkActive(bool active) = 0;
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 1148dc7e4c..86707b20b1 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/ipc/interfaces.cpp b/src/ipc/interfaces.cpp
index ee0d4123ce..396f3ddf25 100644
--- a/src/ipc/interfaces.cpp
+++ b/src/ipc/interfaces.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/ipc/process.cpp b/src/ipc/process.cpp
index 9474ad2c4a..4dc88ae44b 100644
--- a/src/ipc/process.cpp
+++ b/src/ipc/process.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/kernel/blockmanager_opts.h b/src/kernel/blockmanager_opts.h
new file mode 100644
index 0000000000..9dc93b6dd2
--- /dev/null
+++ b/src/kernel/blockmanager_opts.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2022 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_KERNEL_BLOCKMANAGER_OPTS_H
+#define BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
+
+namespace kernel {
+
+/**
+ * An options struct for `BlockManager`, more ergonomically referred to as
+ * `BlockManager::Options` due to the using-declaration in `BlockManager`.
+ */
+struct BlockManagerOpts {
+ uint64_t prune_target{0};
+};
+
+} // namespace kernel
+
+#endif // BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp
new file mode 100644
index 0000000000..e0c4aff6f4
--- /dev/null
+++ b/src/kernel/chainparams.cpp
@@ -0,0 +1,532 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// Copyright (c) 2009-2021 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 <kernel/chainparams.h>
+
+#include <chainparamsseeds.h>
+#include <consensus/amount.h>
+#include <consensus/merkle.h>
+#include <consensus/params.h>
+#include <hash.h>
+#include <chainparamsbase.h>
+#include <logging.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <script/interpreter.h>
+#include <script/script.h>
+#include <uint256.h>
+#include <util/strencodings.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <type_traits>
+
+static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
+{
+ CMutableTransaction txNew;
+ txNew.nVersion = 1;
+ txNew.vin.resize(1);
+ txNew.vout.resize(1);
+ txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
+ txNew.vout[0].nValue = genesisReward;
+ txNew.vout[0].scriptPubKey = genesisOutputScript;
+
+ CBlock genesis;
+ genesis.nTime = nTime;
+ genesis.nBits = nBits;
+ genesis.nNonce = nNonce;
+ genesis.nVersion = nVersion;
+ genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));
+ genesis.hashPrevBlock.SetNull();
+ genesis.hashMerkleRoot = BlockMerkleRoot(genesis);
+ return genesis;
+}
+
+/**
+ * Build the genesis block. Note that the output of its generation
+ * transaction cannot be spent since it did not originally exist in the
+ * database.
+ *
+ * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
+ * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
+ * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
+ * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
+ * vMerkleTree: 4a5e1e
+ */
+static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
+{
+ const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
+ const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
+ return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
+}
+
+/**
+ * Main network on which people trade goods and services.
+ */
+class CMainParams : public CChainParams {
+public:
+ CMainParams() {
+ strNetworkID = CBaseChainParams::MAIN;
+ consensus.signet_blocks = false;
+ consensus.signet_challenge.clear();
+ consensus.nSubsidyHalvingInterval = 210000;
+ consensus.script_flag_exceptions.emplace( // BIP16 exception
+ uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22"), SCRIPT_VERIFY_NONE);
+ consensus.script_flag_exceptions.emplace( // Taproot exception
+ uint256S("0x0000000000000000000f14c35b2d841e986ab5441de8c585d5ffe55ea1e395ad"), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS);
+ consensus.BIP34Height = 227931;
+ consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
+ consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
+ consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
+ consensus.CSVHeight = 419328; // 000000000000000004a1b34462cb8aeebd5799177f7a29cf28f2d1961716b5b5
+ consensus.SegwitHeight = 481824; // 0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893
+ consensus.MinBIP9WarningHeight = 483840; // segwit activation height + miner confirmation window
+ consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ consensus.nPowTargetSpacing = 10 * 60;
+ consensus.fPowAllowMinDifficultyBlocks = false;
+ consensus.fPowNoRetargeting = false;
+ consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016
+ consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
+
+ // Deployment of Taproot (BIPs 340-342)
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021
+
+ consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000003404ba0801921119f903495e");
+ consensus.defaultAssumeValid = uint256S("0x00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd"); // 751565
+
+ /**
+ * The message start string is designed to be unlikely to occur in normal data.
+ * The characters are rarely used upper ASCII, not valid as UTF-8, and produce
+ * a large 32-bit integer with any alignment.
+ */
+ pchMessageStart[0] = 0xf9;
+ pchMessageStart[1] = 0xbe;
+ pchMessageStart[2] = 0xb4;
+ pchMessageStart[3] = 0xd9;
+ nDefaultPort = 8333;
+ nPruneAfterHeight = 100000;
+ m_assumed_blockchain_size = 496;
+ m_assumed_chain_state_size = 6;
+
+ genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
+ consensus.hashGenesisBlock = genesis.GetHash();
+ assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
+ assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
+
+ // Note that of those which support the service bits prefix, most only support a subset of
+ // possible options.
+ // This is fine at runtime as we'll fall back to using them as an addrfetch if they don't support the
+ // service bits we want, but we should get them updated to support all service bits wanted by any
+ // release ASAP to avoid it where possible.
+ vSeeds.emplace_back("seed.bitcoin.sipa.be."); // Pieter Wuille, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("dnsseed.bluematt.me."); // Matt Corallo, only supports x9
+ vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org."); // Luke Dashjr
+ vSeeds.emplace_back("seed.bitcoinstats.com."); // Christian Decker, supports x1 - xf
+ 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
+ vSeeds.emplace_back("seed.bitcoin.wiz.biz."); // Jason Maurice
+
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
+ base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
+ base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
+
+ bech32_hrp = "bc";
+
+ vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_main), std::end(chainparams_seed_main));
+
+ fDefaultConsistencyChecks = false;
+ fRequireStandard = true;
+ m_is_test_chain = false;
+ m_is_mockable_chain = false;
+
+ checkpointData = {
+ {
+ { 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")},
+ { 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")},
+ { 74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")},
+ {105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")},
+ {134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")},
+ {168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")},
+ {193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")},
+ {210000, uint256S("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")},
+ {216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")},
+ {225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")},
+ {250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")},
+ {279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")},
+ {295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")},
+ }
+ };
+
+ m_assumeutxo_data = MapAssumeutxo{
+ // TODO to be specified in a future patch.
+ };
+
+ chainTxData = ChainTxData{
+ // Data from RPC: getchaintxstats 4096 00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd
+ .nTime = 1661697692,
+ .nTxCount = 760120522,
+ .dTxRate = 2.925802860942233,
+ };
+ }
+};
+
+/**
+ * Testnet (v3): public test network which is reset from time to time.
+ */
+class CTestNetParams : public CChainParams {
+public:
+ CTestNetParams() {
+ strNetworkID = CBaseChainParams::TESTNET;
+ consensus.signet_blocks = false;
+ consensus.signet_challenge.clear();
+ consensus.nSubsidyHalvingInterval = 210000;
+ consensus.script_flag_exceptions.emplace( // BIP16 exception
+ uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105"), SCRIPT_VERIFY_NONE);
+ consensus.BIP34Height = 21111;
+ consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
+ consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
+ consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
+ consensus.CSVHeight = 770112; // 00000000025e930139bac5c6c31a403776da130831ab85be56578f3fa75369bb
+ consensus.SegwitHeight = 834624; // 00000000002b980fcd729daaa248fd9316a5200e9b367f4ff2c42453e84201ca
+ consensus.MinBIP9WarningHeight = 836640; // segwit activation height + miner confirmation window
+ consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ consensus.nPowTargetSpacing = 10 * 60;
+ consensus.fPowAllowMinDifficultyBlocks = true;
+ consensus.fPowNoRetargeting = false;
+ consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
+ consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
+
+ // Deployment of Taproot (BIPs 340-342)
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
+
+ consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000076f6e7cbd0beade5d20");
+ consensus.defaultAssumeValid = uint256S("0x0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060"); // 2344474
+
+ pchMessageStart[0] = 0x0b;
+ pchMessageStart[1] = 0x11;
+ pchMessageStart[2] = 0x09;
+ pchMessageStart[3] = 0x07;
+ nDefaultPort = 18333;
+ nPruneAfterHeight = 1000;
+ m_assumed_blockchain_size = 42;
+ m_assumed_chain_state_size = 2;
+
+ genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
+ consensus.hashGenesisBlock = genesis.GetHash();
+ assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
+ assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
+
+ vFixedSeeds.clear();
+ vSeeds.clear();
+ // nodes with support for servicebits filtering should be at the top
+ vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch.");
+ vSeeds.emplace_back("seed.tbtc.petertodd.org.");
+ vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl.");
+ vSeeds.emplace_back("testnet-seed.bluematt.me."); // Just a static list of stable node(s), only supports x9
+
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
+ base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
+ base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
+
+ bech32_hrp = "tb";
+
+ vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_test), std::end(chainparams_seed_test));
+
+ fDefaultConsistencyChecks = false;
+ fRequireStandard = false;
+ m_is_test_chain = true;
+ m_is_mockable_chain = false;
+
+ checkpointData = {
+ {
+ {546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")},
+ }
+ };
+
+ m_assumeutxo_data = MapAssumeutxo{
+ // TODO to be specified in a future patch.
+ };
+
+ chainTxData = ChainTxData{
+ // Data from RPC: getchaintxstats 4096 0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060
+ .nTime = 1661705221,
+ .nTxCount = 63531852,
+ .dTxRate = 0.1079119341520164,
+ };
+ }
+};
+
+/**
+ * Signet: test network with an additional consensus parameter (see BIP325).
+ */
+class SigNetParams : public CChainParams {
+public:
+ explicit SigNetParams(const SigNetOptions& options)
+ {
+ std::vector<uint8_t> bin;
+ vSeeds.clear();
+
+ if (!options.challenge) {
+ bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae");
+ vSeeds.emplace_back("seed.signet.bitcoin.sprovoost.nl.");
+
+ // Hardcoded nodes can be removed once there are more DNS seeds
+ vSeeds.emplace_back("178.128.221.177");
+ vSeeds.emplace_back("v7ajjeirttkbnt32wpy3c6w3emwnfr3fkla7hpxcfokr3ysd3kqtzmqd.onion:38333");
+
+ consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000001291fc22898");
+ consensus.defaultAssumeValid = uint256S("0x000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09"); // 105495
+ m_assumed_blockchain_size = 1;
+ m_assumed_chain_state_size = 0;
+ chainTxData = ChainTxData{
+ // Data from RPC: getchaintxstats 4096 000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09
+ .nTime = 1661702566,
+ .nTxCount = 1903567,
+ .dTxRate = 0.02336701143027275,
+ };
+ } else {
+ bin = *options.challenge;
+ consensus.nMinimumChainWork = uint256{};
+ consensus.defaultAssumeValid = uint256{};
+ m_assumed_blockchain_size = 0;
+ m_assumed_chain_state_size = 0;
+ chainTxData = ChainTxData{
+ 0,
+ 0,
+ 0,
+ };
+ LogPrintf("Signet with challenge %s\n", HexStr(bin));
+ }
+
+ if (options.seeds) {
+ vSeeds = *options.seeds;
+ }
+
+ strNetworkID = CBaseChainParams::SIGNET;
+ consensus.signet_blocks = true;
+ consensus.signet_challenge.assign(bin.begin(), bin.end());
+ consensus.nSubsidyHalvingInterval = 210000;
+ consensus.BIP34Height = 1;
+ consensus.BIP34Hash = uint256{};
+ consensus.BIP65Height = 1;
+ consensus.BIP66Height = 1;
+ consensus.CSVHeight = 1;
+ consensus.SegwitHeight = 1;
+ consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ consensus.nPowTargetSpacing = 10 * 60;
+ consensus.fPowAllowMinDifficultyBlocks = false;
+ consensus.fPowNoRetargeting = false;
+ consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016
+ consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
+ consensus.MinBIP9WarningHeight = 0;
+ consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
+
+ // Activation of Taproot (BIPs 340-342)
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
+
+ // message start is defined as the first 4 bytes of the sha256d of the block script
+ HashWriter h{};
+ h << consensus.signet_challenge;
+ uint256 hash = h.GetHash();
+ memcpy(pchMessageStart, hash.begin(), 4);
+
+ nDefaultPort = 38333;
+ nPruneAfterHeight = 1000;
+
+ genesis = CreateGenesisBlock(1598918400, 52613770, 0x1e0377ae, 1, 50 * COIN);
+ consensus.hashGenesisBlock = genesis.GetHash();
+ assert(consensus.hashGenesisBlock == uint256S("0x00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"));
+ assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
+
+ vFixedSeeds.clear();
+
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
+ base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
+ base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
+
+ bech32_hrp = "tb";
+
+ fDefaultConsistencyChecks = false;
+ fRequireStandard = true;
+ m_is_test_chain = true;
+ m_is_mockable_chain = false;
+ }
+};
+
+/**
+ * Regression test: intended for private networks only. Has minimal difficulty to ensure that
+ * blocks can be found instantly.
+ */
+class CRegTestParams : public CChainParams
+{
+public:
+ explicit CRegTestParams(const RegTestOptions& opts)
+ {
+ strNetworkID = CBaseChainParams::REGTEST;
+ consensus.signet_blocks = false;
+ consensus.signet_challenge.clear();
+ consensus.nSubsidyHalvingInterval = 150;
+ consensus.BIP34Height = 1; // Always active unless overridden
+ consensus.BIP34Hash = uint256();
+ consensus.BIP65Height = 1; // Always active unless overridden
+ consensus.BIP66Height = 1; // Always active unless overridden
+ consensus.CSVHeight = 1; // Always active unless overridden
+ consensus.SegwitHeight = 0; // Always active unless overridden
+ consensus.MinBIP9WarningHeight = 0;
+ consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ consensus.nPowTargetSpacing = 10 * 60;
+ consensus.fPowAllowMinDifficultyBlocks = true;
+ consensus.fPowNoRetargeting = true;
+ consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
+ consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
+
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
+
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
+
+ consensus.nMinimumChainWork = uint256{};
+ consensus.defaultAssumeValid = uint256{};
+
+ pchMessageStart[0] = 0xfa;
+ pchMessageStart[1] = 0xbf;
+ pchMessageStart[2] = 0xb5;
+ pchMessageStart[3] = 0xda;
+ nDefaultPort = 18444;
+ nPruneAfterHeight = opts.fastprune ? 100 : 1000;
+ m_assumed_blockchain_size = 0;
+ m_assumed_chain_state_size = 0;
+
+ for (const auto& [dep, height] : opts.activation_heights) {
+ switch (dep) {
+ case Consensus::BuriedDeployment::DEPLOYMENT_SEGWIT:
+ consensus.SegwitHeight = int{height};
+ break;
+ case Consensus::BuriedDeployment::DEPLOYMENT_HEIGHTINCB:
+ consensus.BIP34Height = int{height};
+ break;
+ case Consensus::BuriedDeployment::DEPLOYMENT_DERSIG:
+ consensus.BIP66Height = int{height};
+ break;
+ case Consensus::BuriedDeployment::DEPLOYMENT_CLTV:
+ consensus.BIP65Height = int{height};
+ break;
+ case Consensus::BuriedDeployment::DEPLOYMENT_CSV:
+ consensus.CSVHeight = int{height};
+ break;
+ }
+ }
+
+ for (const auto& [deployment_pos, version_bits_params] : opts.version_bits_parameters) {
+ consensus.vDeployments[deployment_pos].nStartTime = version_bits_params.start_time;
+ consensus.vDeployments[deployment_pos].nTimeout = version_bits_params.timeout;
+ consensus.vDeployments[deployment_pos].min_activation_height = version_bits_params.min_activation_height;
+ }
+
+ genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
+ consensus.hashGenesisBlock = genesis.GetHash();
+ assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
+ assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
+
+ vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
+ vSeeds.clear();
+ vSeeds.emplace_back("dummySeed.invalid.");
+
+ fDefaultConsistencyChecks = true;
+ fRequireStandard = true;
+ m_is_test_chain = true;
+ m_is_mockable_chain = true;
+
+ checkpointData = {
+ {
+ {0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")},
+ }
+ };
+
+ m_assumeutxo_data = MapAssumeutxo{
+ {
+ 110,
+ {AssumeutxoHash{uint256S("0x1ebbf5850204c0bdb15bf030f47c7fe91d45c44c712697e4509ba67adb01c618")}, 110},
+ },
+ {
+ 200,
+ {AssumeutxoHash{uint256S("0x51c8d11d8b5c1de51543c579736e786aa2736206d1e11e627568029ce092cf62")}, 200},
+ },
+ };
+
+ chainTxData = ChainTxData{
+ 0,
+ 0,
+ 0
+ };
+
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
+ base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
+ base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
+
+ bech32_hrp = "bcrt";
+ }
+};
+
+std::unique_ptr<const CChainParams> CChainParams::SigNet(const SigNetOptions& options)
+{
+ return std::make_unique<const SigNetParams>(options);
+}
+
+std::unique_ptr<const CChainParams> CChainParams::RegTest(const RegTestOptions& options)
+{
+ return std::make_unique<const CRegTestParams>(options);
+}
+
+std::unique_ptr<const CChainParams> CChainParams::Main()
+{
+ return std::make_unique<const CMainParams>();
+}
+
+std::unique_ptr<const CChainParams> CChainParams::TestNet()
+{
+ return std::make_unique<const CTestNetParams>();
+}
diff --git a/src/kernel/chainparams.h b/src/kernel/chainparams.h
new file mode 100644
index 0000000000..32fe618dbd
--- /dev/null
+++ b/src/kernel/chainparams.h
@@ -0,0 +1,187 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2021 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_KERNEL_CHAINPARAMS_H
+#define BITCOIN_KERNEL_CHAINPARAMS_H
+
+#include <consensus/params.h>
+#include <netaddress.h>
+#include <primitives/block.h>
+#include <protocol.h>
+#include <uint256.h>
+#include <util/hash_type.h>
+
+#include <cstdint>
+#include <iterator>
+#include <map>
+#include <memory>
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+typedef std::map<int, uint256> MapCheckpoints;
+
+struct CCheckpointData {
+ MapCheckpoints mapCheckpoints;
+
+ int GetHeight() const {
+ const auto& final_checkpoint = mapCheckpoints.rbegin();
+ return final_checkpoint->first /* height */;
+ }
+};
+
+struct AssumeutxoHash : public BaseHash<uint256> {
+ explicit AssumeutxoHash(const uint256& hash) : BaseHash(hash) {}
+};
+
+/**
+ * Holds configuration for use during UTXO snapshot load and validation. The contents
+ * here are security critical, since they dictate which UTXO snapshots are recognized
+ * as valid.
+ */
+struct AssumeutxoData {
+ //! The expected hash of the deserialized UTXO set.
+ const AssumeutxoHash hash_serialized;
+
+ //! Used to populate the nChainTx value, which is used during BlockManager::LoadBlockIndex().
+ //!
+ //! We need to hardcode the value here because this is computed cumulatively using block data,
+ //! which we do not necessarily have at the time of snapshot load.
+ const unsigned int nChainTx;
+};
+
+using MapAssumeutxo = std::map<int, const AssumeutxoData>;
+
+/**
+ * Holds various statistics on transactions within a chain. Used to estimate
+ * verification progress during chain sync.
+ *
+ * See also: CChainParams::TxData, GuessVerificationProgress.
+ */
+struct ChainTxData {
+ int64_t nTime; //!< UNIX timestamp of last known number of transactions
+ int64_t nTxCount; //!< total number of transactions between genesis and that timestamp
+ double dTxRate; //!< estimated number of transactions per second after that timestamp
+};
+
+/**
+ * CChainParams defines various tweakable parameters of a given instance of the
+ * Bitcoin system.
+ */
+class CChainParams
+{
+public:
+ enum Base58Type {
+ PUBKEY_ADDRESS,
+ SCRIPT_ADDRESS,
+ SECRET_KEY,
+ EXT_PUBLIC_KEY,
+ EXT_SECRET_KEY,
+
+ MAX_BASE58_TYPES
+ };
+
+ const Consensus::Params& GetConsensus() const { return consensus; }
+ const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
+ uint16_t GetDefaultPort() const { return nDefaultPort; }
+ uint16_t GetDefaultPort(Network net) const
+ {
+ return net == NET_I2P ? I2P_SAM31_PORT : GetDefaultPort();
+ }
+ uint16_t GetDefaultPort(const std::string& addr) const
+ {
+ CNetAddr a;
+ return a.SetSpecial(addr) ? GetDefaultPort(a.GetNetwork()) : GetDefaultPort();
+ }
+
+ const CBlock& GenesisBlock() const { return genesis; }
+ /** Default value for -checkmempool and -checkblockindex argument */
+ bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
+ /** Policy: Filter transactions that do not match well-defined patterns */
+ bool RequireStandard() const { return fRequireStandard; }
+ /** If this chain is exclusively used for testing */
+ bool IsTestChain() const { return m_is_test_chain; }
+ /** If this chain allows time to be mocked */
+ bool IsMockableChain() const { return m_is_mockable_chain; }
+ uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
+ /** Minimum free space (in GB) needed for data directory */
+ uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; }
+ /** Minimum free space (in GB) needed for data directory when pruned; Does not include prune target*/
+ uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; }
+ /** Whether it is possible to mine blocks on demand (no retargeting) */
+ bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; }
+ /** Return the network string */
+ std::string NetworkIDString() const { return strNetworkID; }
+ /** Return the list of hostnames to look up for DNS seeds */
+ const std::vector<std::string>& DNSSeeds() const { return vSeeds; }
+ const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
+ const std::string& Bech32HRP() const { return bech32_hrp; }
+ const std::vector<uint8_t>& FixedSeeds() const { return vFixedSeeds; }
+ const CCheckpointData& Checkpoints() const { return checkpointData; }
+
+ //! Get allowed assumeutxo configuration.
+ //! @see ChainstateManager
+ const MapAssumeutxo& Assumeutxo() const { return m_assumeutxo_data; }
+
+ const ChainTxData& TxData() const { return chainTxData; }
+
+ /**
+ * SigNetOptions holds configurations for creating a signet CChainParams.
+ */
+ struct SigNetOptions {
+ std::optional<std::vector<uint8_t>> challenge{};
+ std::optional<std::vector<std::string>> seeds{};
+ };
+
+ /**
+ * VersionBitsParameters holds activation parameters
+ */
+ struct VersionBitsParameters {
+ int64_t start_time;
+ int64_t timeout;
+ int min_activation_height;
+ };
+
+ /**
+ * RegTestOptions holds configurations for creating a regtest CChainParams.
+ */
+ struct RegTestOptions {
+ std::unordered_map<Consensus::DeploymentPos, VersionBitsParameters> version_bits_parameters{};
+ std::unordered_map<Consensus::BuriedDeployment, int> activation_heights{};
+ bool fastprune{false};
+ };
+
+ static std::unique_ptr<const CChainParams> RegTest(const RegTestOptions& options);
+ static std::unique_ptr<const CChainParams> SigNet(const SigNetOptions& options);
+ static std::unique_ptr<const CChainParams> Main();
+ static std::unique_ptr<const CChainParams> TestNet();
+
+protected:
+ CChainParams() {}
+
+ Consensus::Params consensus;
+ CMessageHeader::MessageStartChars pchMessageStart;
+ uint16_t nDefaultPort;
+ uint64_t nPruneAfterHeight;
+ uint64_t m_assumed_blockchain_size;
+ uint64_t m_assumed_chain_state_size;
+ std::vector<std::string> vSeeds;
+ std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
+ std::string bech32_hrp;
+ std::string strNetworkID;
+ CBlock genesis;
+ std::vector<uint8_t> vFixedSeeds;
+ bool fDefaultConsistencyChecks;
+ bool fRequireStandard;
+ bool m_is_test_chain;
+ bool m_is_mockable_chain;
+ CCheckpointData checkpointData;
+ MapAssumeutxo m_assumeutxo_data;
+ ChainTxData chainTxData;
+};
+
+#endif // BITCOIN_KERNEL_CHAINPARAMS_H
diff --git a/src/kernel/chainstatemanager_opts.h b/src/kernel/chainstatemanager_opts.h
index 520d0e8e75..2395f60164 100644
--- a/src/kernel/chainstatemanager_opts.h
+++ b/src/kernel/chainstatemanager_opts.h
@@ -5,13 +5,21 @@
#ifndef BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H
#define BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H
+#include <arith_uint256.h>
+#include <dbwrapper.h>
+#include <txdb.h>
+#include <uint256.h>
#include <util/time.h>
#include <cstdint>
#include <functional>
+#include <optional>
class CChainParams;
+static constexpr bool DEFAULT_CHECKPOINTS_ENABLED{true};
+static constexpr auto DEFAULT_MAX_TIP_AGE{24h};
+
namespace kernel {
/**
@@ -21,7 +29,19 @@ namespace kernel {
*/
struct ChainstateManagerOpts {
const CChainParams& chainparams;
+ fs::path datadir;
const std::function<NodeClock::time_point()> adjusted_time_callback{nullptr};
+ std::optional<bool> check_block_index{};
+ bool checkpoints_enabled{DEFAULT_CHECKPOINTS_ENABLED};
+ //! If set, it will override the minimum work we will assume exists on some valid chain.
+ std::optional<arith_uint256> minimum_chain_work{};
+ //! If set, it will override the block hash whose ancestors we will assume to have valid scripts without checking them.
+ std::optional<uint256> assumed_valid_block{};
+ //! If the tip is older than this, the node is considered to be in initial block download.
+ std::chrono::seconds max_tip_age{DEFAULT_MAX_TIP_AGE};
+ DBOptions block_tree_db{};
+ DBOptions coins_db{};
+ CoinsViewOptions coins_view{};
};
} // namespace kernel
diff --git a/src/kernel/coinstats.cpp b/src/kernel/coinstats.cpp
index 06a4b8c974..4b75c387a6 100644
--- a/src/kernel/coinstats.cpp
+++ b/src/kernel/coinstats.cpp
@@ -8,6 +8,7 @@
#include <coins.h>
#include <crypto/muhash.h>
#include <hash.h>
+#include <logging.h>
#include <node/blockstorage.h>
#include <primitives/transaction.h>
#include <script/script.h>
@@ -19,7 +20,6 @@
#include <uint256.h>
#include <util/check.h>
#include <util/overflow.h>
-#include <util/system.h>
#include <validation.h>
#include <version.h>
@@ -48,8 +48,9 @@ uint64_t GetBogoSize(const CScript& script_pub_key)
script_pub_key.size() /* scriptPubKey */;
}
-CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin) {
- CDataStream ss(SER_DISK, PROTOCOL_VERSION);
+DataStream TxOutSer(const COutPoint& outpoint, const Coin& coin)
+{
+ DataStream ss{};
ss << outpoint;
ss << static_cast<uint32_t>(coin.nHeight * 2 + coin.fCoinBase);
ss << coin.out;
diff --git a/src/kernel/coinstats.h b/src/kernel/coinstats.h
index b7c1328e93..54d0e4f664 100644
--- a/src/kernel/coinstats.h
+++ b/src/kernel/coinstats.h
@@ -72,7 +72,7 @@ struct CCoinsStats {
uint64_t GetBogoSize(const CScript& script_pub_key);
-CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin);
+DataStream TxOutSer(const COutPoint& outpoint, const Coin& coin);
std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, node::BlockManager& blockman, const std::function<void()>& interruption_point = {});
} // namespace kernel
diff --git a/src/kernel/context.cpp b/src/kernel/context.cpp
index 15413c1840..1205da869e 100644
--- a/src/kernel/context.cpp
+++ b/src/kernel/context.cpp
@@ -21,12 +21,10 @@ Context::Context()
LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
RandomInit();
ECC_Start();
- ecc_verify_handle.reset(new ECCVerifyHandle());
}
Context::~Context()
{
- ecc_verify_handle.reset();
ECC_Stop();
}
diff --git a/src/kernel/context.h b/src/kernel/context.h
index 9746ef994b..f11b7b54f0 100644
--- a/src/kernel/context.h
+++ b/src/kernel/context.h
@@ -7,8 +7,6 @@
#include <memory>
-class ECCVerifyHandle;
-
namespace kernel {
//! Context struct holding the kernel library's logically global state, and
//! passed to external libbitcoin_kernel functions which need access to this
@@ -18,8 +16,6 @@ namespace kernel {
//! State stored directly in this struct should be simple. More complex state
//! should be stored to std::unique_ptr members pointing to opaque types.
struct Context {
- std::unique_ptr<ECCVerifyHandle> ecc_verify_handle;
-
//! Declare default constructor and destructor that are not inline, so code
//! instantiating the kernel::Context struct doesn't need to #include class
//! definitions for all the unique_ptr members.
diff --git a/src/kernel/cs_main.cpp b/src/kernel/cs_main.cpp
new file mode 100644
index 0000000000..d27cb7caf3
--- /dev/null
+++ b/src/kernel/cs_main.cpp
@@ -0,0 +1,8 @@
+// Copyright (c) 2023 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 <kernel/cs_main.h>
+#include <sync.h>
+
+RecursiveMutex cs_main;
diff --git a/src/kernel/cs_main.h b/src/kernel/cs_main.h
new file mode 100644
index 0000000000..8d03903b8e
--- /dev/null
+++ b/src/kernel/cs_main.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2023 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_KERNEL_CS_MAIN_H
+#define BITCOIN_KERNEL_CS_MAIN_H
+
+#include <sync.h>
+
+/**
+ * Mutex to guard access to validation specific variables, such as reading
+ * or changing the chainstate.
+ *
+ * This may also need to be locked when updating the transaction pool, e.g. on
+ * AcceptToMemoryPool. See CTxMemPool::cs comment for details.
+ *
+ * The transaction pool has a separate lock to allow reading from it and the
+ * chainstate at the same time.
+ */
+extern RecursiveMutex cs_main;
+
+#endif // BITCOIN_KERNEL_CS_MAIN_H
diff --git a/src/kernel/mempool_entry.h b/src/kernel/mempool_entry.h
new file mode 100644
index 0000000000..e1ba4296ef
--- /dev/null
+++ b/src/kernel/mempool_entry.h
@@ -0,0 +1,174 @@
+// Copyright (c) 2009-2022 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_KERNEL_MEMPOOL_ENTRY_H
+#define BITCOIN_KERNEL_MEMPOOL_ENTRY_H
+
+#include <consensus/amount.h>
+#include <consensus/validation.h>
+#include <core_memusage.h>
+#include <policy/policy.h>
+#include <policy/settings.h>
+#include <primitives/transaction.h>
+#include <util/epochguard.h>
+#include <util/overflow.h>
+
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <set>
+#include <stddef.h>
+#include <stdint.h>
+
+class CBlockIndex;
+
+struct LockPoints {
+ // Will be set to the blockchain height and median time past
+ // values that would be necessary to satisfy all relative locktime
+ // constraints (BIP68) of this tx given our view of block chain history
+ int height{0};
+ int64_t time{0};
+ // As long as the current chain descends from the highest height block
+ // containing one of the inputs used in the calculation, then the cached
+ // values are still valid even after a reorg.
+ CBlockIndex* maxInputBlock{nullptr};
+};
+
+struct CompareIteratorByHash {
+ // SFINAE for T where T is either a pointer type (e.g., a txiter) or a reference_wrapper<T>
+ // (e.g. a wrapped CTxMemPoolEntry&)
+ template <typename T>
+ bool operator()(const std::reference_wrapper<T>& a, const std::reference_wrapper<T>& b) const
+ {
+ return a.get().GetTx().GetHash() < b.get().GetTx().GetHash();
+ }
+ template <typename T>
+ bool operator()(const T& a, const T& b) const
+ {
+ return a->GetTx().GetHash() < b->GetTx().GetHash();
+ }
+};
+
+/** \class CTxMemPoolEntry
+ *
+ * CTxMemPoolEntry stores data about the corresponding transaction, as well
+ * as data about all in-mempool transactions that depend on the transaction
+ * ("descendant" transactions).
+ *
+ * When a new entry is added to the mempool, we update the descendant state
+ * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for
+ * all ancestors of the newly added transaction.
+ *
+ */
+
+class CTxMemPoolEntry
+{
+public:
+ typedef std::reference_wrapper<const CTxMemPoolEntry> CTxMemPoolEntryRef;
+ // two aliases, should the types ever diverge
+ typedef std::set<CTxMemPoolEntryRef, CompareIteratorByHash> Parents;
+ typedef std::set<CTxMemPoolEntryRef, CompareIteratorByHash> Children;
+
+private:
+ const CTransactionRef tx;
+ mutable Parents m_parents;
+ mutable Children m_children;
+ const CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
+ const size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
+ const size_t nUsageSize; //!< ... and total memory usage
+ const int64_t nTime; //!< Local time when entering the mempool
+ const unsigned int entryHeight; //!< Chain height when entering the mempool
+ const bool spendsCoinbase; //!< keep track of transactions that spend a coinbase
+ const int64_t sigOpCost; //!< Total sigop cost
+ CAmount m_modified_fee; //!< Used for determining the priority of the transaction for mining in a block
+ LockPoints lockPoints; //!< Track the height and time at which tx was final
+
+ // Information about descendants of this transaction that are in the
+ // mempool; if we remove this transaction we must remove all of these
+ // descendants as well.
+ uint64_t nCountWithDescendants{1}; //!< number of descendant transactions
+ uint64_t nSizeWithDescendants; //!< ... and size
+ CAmount nModFeesWithDescendants; //!< ... and total fees (all including us)
+
+ // Analogous statistics for ancestor transactions
+ uint64_t nCountWithAncestors{1};
+ uint64_t nSizeWithAncestors;
+ CAmount nModFeesWithAncestors;
+ int64_t nSigOpCostWithAncestors;
+
+public:
+ CTxMemPoolEntry(const CTransactionRef& tx, CAmount fee,
+ int64_t time, unsigned int entry_height,
+ bool spends_coinbase,
+ int64_t sigops_cost, LockPoints lp)
+ : tx{tx},
+ nFee{fee},
+ nTxWeight(GetTransactionWeight(*tx)),
+ nUsageSize{RecursiveDynamicUsage(tx)},
+ nTime{time},
+ entryHeight{entry_height},
+ spendsCoinbase{spends_coinbase},
+ sigOpCost{sigops_cost},
+ m_modified_fee{nFee},
+ lockPoints{lp},
+ nSizeWithDescendants{GetTxSize()},
+ nModFeesWithDescendants{nFee},
+ nSizeWithAncestors{GetTxSize()},
+ nModFeesWithAncestors{nFee},
+ nSigOpCostWithAncestors{sigOpCost} {}
+
+ const CTransaction& GetTx() const { return *this->tx; }
+ CTransactionRef GetSharedTx() const { return this->tx; }
+ const CAmount& GetFee() const { return nFee; }
+ size_t GetTxSize() const
+ {
+ return GetVirtualTransactionSize(nTxWeight, sigOpCost, ::nBytesPerSigOp);
+ }
+ size_t GetTxWeight() const { return nTxWeight; }
+ std::chrono::seconds GetTime() const { return std::chrono::seconds{nTime}; }
+ unsigned int GetHeight() const { return entryHeight; }
+ int64_t GetSigOpCost() const { return sigOpCost; }
+ CAmount GetModifiedFee() const { return m_modified_fee; }
+ size_t DynamicMemoryUsage() const { return nUsageSize; }
+ const LockPoints& GetLockPoints() const { return lockPoints; }
+
+ // Adjusts the descendant state.
+ void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
+ // Adjusts the ancestor state
+ void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps);
+ // Updates the modified fees with descendants/ancestors.
+ void UpdateModifiedFee(CAmount fee_diff)
+ {
+ nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, fee_diff);
+ nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, fee_diff);
+ m_modified_fee = SaturatingAdd(m_modified_fee, fee_diff);
+ }
+
+ // Update the LockPoints after a reorg
+ void UpdateLockPoints(const LockPoints& lp)
+ {
+ lockPoints = lp;
+ }
+
+ uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
+ uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
+ CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
+
+ bool GetSpendsCoinbase() const { return spendsCoinbase; }
+
+ uint64_t GetCountWithAncestors() const { return nCountWithAncestors; }
+ uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
+ CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
+ int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; }
+
+ const Parents& GetMemPoolParentsConst() const { return m_parents; }
+ const Children& GetMemPoolChildrenConst() const { return m_children; }
+ Parents& GetMemPoolParents() const { return m_parents; }
+ Children& GetMemPoolChildren() const { return m_children; }
+
+ mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes
+ mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms
+};
+
+#endif // BITCOIN_KERNEL_MEMPOOL_ENTRY_H
diff --git a/src/kernel/mempool_limits.h b/src/kernel/mempool_limits.h
index e192e7e6cd..8d4495c3cb 100644
--- a/src/kernel/mempool_limits.h
+++ b/src/kernel/mempool_limits.h
@@ -24,6 +24,15 @@ struct MemPoolLimits {
int64_t descendant_count{DEFAULT_DESCENDANT_LIMIT};
//! The maximum allowed size in virtual bytes of an entry and its descendants within a package.
int64_t descendant_size_vbytes{DEFAULT_DESCENDANT_SIZE_LIMIT_KVB * 1'000};
+
+ /**
+ * @return MemPoolLimits with all the limits set to the maximum
+ */
+ static constexpr MemPoolLimits NoLimits()
+ {
+ int64_t no_limit{std::numeric_limits<int64_t>::max()};
+ return {no_limit, no_limit, no_limit, no_limit};
+ }
};
} // namespace kernel
diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h
index dad6f14c39..beb5fca5e9 100644
--- a/src/kernel/mempool_options.h
+++ b/src/kernel/mempool_options.h
@@ -18,6 +18,8 @@ class CBlockPolicyEstimator;
/** Default for -maxmempool, maximum megabytes of mempool memory usage */
static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE_MB{300};
+/** Default for -maxmempool when blocksonly is set */
+static constexpr unsigned int DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB{5};
/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
static constexpr unsigned int DEFAULT_MEMPOOL_EXPIRY_HOURS{336};
/** Default for -mempoolfullrbf, if the transaction replaceability signaling is ignored */
diff --git a/src/key.cpp b/src/key.cpp
index 199808505d..3a3f0b2bc2 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -233,7 +233,7 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool gr
secp256k1_pubkey pk;
ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pk, begin());
assert(ret);
- ret = secp256k1_ecdsa_verify(GetVerifyContext(), &sig, hash.begin(), &pk);
+ ret = secp256k1_ecdsa_verify(secp256k1_context_static, &sig, hash.begin(), &pk);
assert(ret);
return true;
}
@@ -245,8 +245,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
GetRandBytes(rnd);
- uint256 hash;
- CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
+ uint256 hash{Hash(str, rnd)};
std::vector<unsigned char> vchSig;
Sign(hash, vchSig);
return pubkey.Verify(hash, vchSig);
@@ -268,9 +267,9 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
secp256k1_pubkey epk, rpk;
ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &epk, begin());
assert(ret);
- ret = secp256k1_ecdsa_recover(GetVerifyContext(), &rpk, &rsig, hash.begin());
+ ret = secp256k1_ecdsa_recover(secp256k1_context_static, &rpk, &rsig, hash.begin());
assert(ret);
- ret = secp256k1_ec_pubkey_cmp(GetVerifyContext(), &epk, &rpk);
+ ret = secp256k1_ec_pubkey_cmp(secp256k1_context_static, &epk, &rpk);
assert(ret == 0);
return true;
}
@@ -286,14 +285,14 @@ bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint2
unsigned char pubkey_bytes[32];
if (!secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, pubkey_bytes, &pubkey)) return false;
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
- if (!secp256k1_keypair_xonly_tweak_add(GetVerifyContext(), &keypair, tweak.data())) return false;
+ if (!secp256k1_keypair_xonly_tweak_add(secp256k1_context_static, &keypair, tweak.data())) return false;
}
bool ret = secp256k1_schnorrsig_sign32(secp256k1_context_sign, sig.data(), hash.data(), &keypair, aux.data());
if (ret) {
// Additional verification step to prevent using a potentially corrupted signature
secp256k1_xonly_pubkey pubkey_verify;
- ret = secp256k1_keypair_xonly_pub(GetVerifyContext(), &pubkey_verify, nullptr, &keypair);
- ret &= secp256k1_schnorrsig_verify(GetVerifyContext(), sig.data(), hash.begin(), 32, &pubkey_verify);
+ ret = secp256k1_keypair_xonly_pub(secp256k1_context_static, &pubkey_verify, nullptr, &keypair);
+ ret &= secp256k1_schnorrsig_verify(secp256k1_context_static, sig.data(), hash.begin(), 32, &pubkey_verify);
}
if (!ret) memory_cleanse(sig.data(), sig.size());
memory_cleanse(&keypair, sizeof(keypair));
@@ -392,7 +391,7 @@ bool ECC_InitSanityCheck() {
void ECC_Start() {
assert(secp256k1_context_sign == nullptr);
- secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
assert(ctx != nullptr);
{
diff --git a/src/key.h b/src/key.h
index e9b78ebd44..4e092fffea 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -42,10 +42,10 @@ public:
private:
//! Whether this private key is valid. We check for correctness when modifying the key
//! data, so fValid should always correspond to the actual state.
- bool fValid;
+ bool fValid{false};
//! Whether the public key corresponding to this private key is (to be) compressed.
- bool fCompressed;
+ bool fCompressed{false};
//! The actual byte data
std::vector<unsigned char, secure_allocator<unsigned char> > keydata;
@@ -55,7 +55,7 @@ private:
public:
//! Construct an invalid private key.
- CKey() : fValid(false), fCompressed(false)
+ CKey()
{
// Important: vch must be 32 bytes in length to not break serialization
keydata.resize(32);
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 6dd6f82112..4659a59544 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -107,17 +107,17 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) ||
(data.size() >= pubkey_prefix.size() &&
std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin()))) {
- error_str = "Invalid length for Base58 address";
+ error_str = "Invalid length for Base58 address (P2PKH or P2SH)";
} else {
- error_str = "Invalid prefix for Base58-encoded address";
+ error_str = "Invalid or unsupported Base58-encoded address.";
}
return CNoDestination();
} else if (!is_bech32) {
// Try Base58 decoding without the checksum, using a much larger max length
if (!DecodeBase58(str, data, 100)) {
- error_str = "Not a valid Bech32 or Base58 encoding";
+ error_str = "Invalid or unsupported Segwit (Bech32) or Base58 encoding.";
} else {
- error_str = "Invalid checksum or length of Base58 address";
+ error_str = "Invalid checksum or length of Base58 address (P2PKH or P2SH)";
}
return CNoDestination();
}
@@ -127,7 +127,7 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
if ((dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) && dec.data.size() > 0) {
// Bech32 decoding
if (dec.hrp != params.Bech32HRP()) {
- error_str = "Invalid prefix for Bech32 address";
+ error_str = strprintf("Invalid or unsupported prefix for Segwit (Bech32) address (expected %s, got %s).", params.Bech32HRP(), dec.hrp);
return CNoDestination();
}
int version = dec.data[0]; // The first 5 bit symbol is the witness version (0-16)
diff --git a/src/logging.cpp b/src/logging.cpp
index a3f1d39be5..298ec9c013 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -180,6 +180,8 @@ const CLogCategoryDesc LogCategories[] =
#endif
{BCLog::UTIL, "util"},
{BCLog::BLOCKSTORE, "blockstorage"},
+ {BCLog::TXRECONCILIATION, "txreconciliation"},
+ {BCLog::SCAN, "scan"},
{BCLog::ALL, "1"},
{BCLog::ALL, "all"},
};
@@ -280,6 +282,10 @@ std::string LogCategoryToStr(BCLog::LogFlags category)
return "util";
case BCLog::LogFlags::BLOCKSTORE:
return "blockstorage";
+ case BCLog::LogFlags::TXRECONCILIATION:
+ return "txreconciliation";
+ case BCLog::LogFlags::SCAN:
+ return "scan";
case BCLog::LogFlags::ALL:
return "all";
}
diff --git a/src/logging.h b/src/logging.h
index fe91ee43a5..954731d214 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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,6 +66,8 @@ namespace BCLog {
#endif
UTIL = (1 << 25),
BLOCKSTORE = (1 << 26),
+ TXRECONCILIATION = (1 << 27),
+ SCAN = (1 << 28),
ALL = ~(uint32_t)0,
};
enum class Level {
@@ -255,4 +257,11 @@ static inline void LogPrintf_(const std::string& logging_function, const std::st
} \
} while (0)
+template <typename... Args>
+bool error(const char* fmt, const Args&... args)
+{
+ LogPrintf("ERROR: %s\n", tfm::format(fmt, args...));
+ return false;
+}
+
#endif // BITCOIN_LOGGING_H
diff --git a/src/logging/timer.h b/src/logging/timer.h
index d954e46301..993ba99c25 100644
--- a/src/logging/timer.h
+++ b/src/logging/timer.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,6 +12,7 @@
#include <util/types.h>
#include <chrono>
+#include <optional>
#include <string>
@@ -28,14 +29,14 @@ public:
std::string prefix,
std::string end_msg,
BCLog::LogFlags log_category = BCLog::LogFlags::ALL,
- bool msg_on_completion = true) :
- m_prefix(std::move(prefix)),
- m_title(std::move(end_msg)),
- m_log_category(log_category),
- m_message_on_completion(msg_on_completion)
+ bool msg_on_completion = true)
+ : m_prefix(std::move(prefix)),
+ m_title(std::move(end_msg)),
+ m_log_category(log_category),
+ m_message_on_completion(msg_on_completion)
{
this->Log(strprintf("%s started", m_title));
- m_start_t = GetTime<std::chrono::microseconds>();
+ m_start_t = std::chrono::steady_clock::now();
}
~Timer()
@@ -60,24 +61,25 @@ public:
std::string LogMsg(const std::string& msg)
{
- const auto end_time = GetTime<std::chrono::microseconds>() - m_start_t;
- if (m_start_t.count() <= 0) {
+ const auto end_time{std::chrono::steady_clock::now()};
+ if (!m_start_t) {
return strprintf("%s: %s", m_prefix, msg);
}
+ const auto duration{end_time - *m_start_t};
if constexpr (std::is_same<TimeType, std::chrono::microseconds>::value) {
- return strprintf("%s: %s (%iμs)", m_prefix, msg, end_time.count());
+ return strprintf("%s: %s (%iμs)", m_prefix, msg, Ticks<std::chrono::microseconds>(duration));
} else if constexpr (std::is_same<TimeType, std::chrono::milliseconds>::value) {
- return strprintf("%s: %s (%.2fms)", m_prefix, msg, end_time.count() * 0.001);
+ return strprintf("%s: %s (%.2fms)", m_prefix, msg, Ticks<MillisecondsDouble>(duration));
} else if constexpr (std::is_same<TimeType, std::chrono::seconds>::value) {
- return strprintf("%s: %s (%.2fs)", m_prefix, msg, end_time.count() * 0.000001);
+ return strprintf("%s: %s (%.2fs)", m_prefix, msg, Ticks<SecondsDouble>(duration));
} else {
static_assert(ALWAYS_FALSE<TimeType>, "Error: unexpected time type");
}
}
private:
- std::chrono::microseconds m_start_t{};
+ std::optional<std::chrono::steady_clock::time_point> m_start_t{};
//! Log prefix; usually the name of the function this was created in.
const std::string m_prefix;
diff --git a/src/mapport.cpp b/src/mapport.cpp
index 6262e51879..994fd12cf5 100644
--- a/src/mapport.cpp
+++ b/src/mapport.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,10 +13,10 @@
#include <net.h>
#include <netaddress.h>
#include <netbase.h>
-#include <threadinterrupt.h>
#include <util/syscall_sandbox.h>
#include <util/system.h>
#include <util/thread.h>
+#include <util/threadinterrupt.h>
#ifdef USE_NATPMP
#include <compat/compat.h>
@@ -27,9 +27,9 @@
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#include <miniupnpc/upnperrors.h>
-// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility
-// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages.
-static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed");
+// The minimum supported miniUPnPc API version is set to 17. This excludes
+// versions with known vulnerabilities.
+static_assert(MINIUPNPC_API_VERSION >= 17, "miniUPnPc API version >= 17 assumed");
#endif // USE_UPNP
#include <atomic>
@@ -104,7 +104,7 @@ static bool NatpmpMapping(natpmp_t* natpmp, const struct in_addr& external_ipv4_
AddLocal(external, LOCAL_MAPPED);
external_ip_discovered = true;
}
- LogPrintf("natpmp: Port mapping successful. External address = %s\n", external.ToString());
+ LogPrintf("natpmp: Port mapping successful. External address = %s\n", external.ToStringAddrPort());
return true;
} else {
LogPrintf("natpmp: Port mapping failed.\n");
@@ -159,11 +159,7 @@ static bool ProcessUpnp()
char lanaddr[64];
int error = 0;
-#if MINIUPNPC_API_VERSION < 14
- devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
-#else
devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
-#endif
struct UPNPUrls urls;
struct IGDdatas data;
@@ -181,7 +177,7 @@ static bool ProcessUpnp()
if (externalIPAddress[0]) {
CNetAddr resolved;
if (LookupHost(externalIPAddress, resolved, false)) {
- LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString());
+ LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToStringAddr());
AddLocal(resolved, LOCAL_MAPPED);
}
} else {
diff --git a/src/mapport.h b/src/mapport.h
index 279d65167f..6f55c46f6c 100644
--- a/src/mapport.h
+++ b/src/mapport.h
@@ -5,17 +5,9 @@
#ifndef BITCOIN_MAPPORT_H
#define BITCOIN_MAPPORT_H
-#ifdef USE_UPNP
-static constexpr bool DEFAULT_UPNP = USE_UPNP;
-#else
static constexpr bool DEFAULT_UPNP = false;
-#endif // USE_UPNP
-#ifdef USE_NATPMP
-static constexpr bool DEFAULT_NATPMP = USE_NATPMP;
-#else
static constexpr bool DEFAULT_NATPMP = false;
-#endif // USE_NATPMP
enum MapPortProtoFlag : unsigned int {
NONE = 0x00,
diff --git a/src/memusage.h b/src/memusage.h
index fd85a7956c..9755be0ff5 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/minisketch/configure.ac b/src/minisketch/configure.ac
index 9dc66e7fd2..83910448a2 100644
--- a/src/minisketch/configure.ac
+++ b/src/minisketch/configure.ac
@@ -124,9 +124,6 @@ if test "x$use_ccache" != "xno"; then
fi
AC_MSG_RESULT($use_ccache)
fi
-if test "x$use_ccache" = "xyes"; then
- AX_CHECK_COMPILE_FLAG([-Qunused-arguments],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Qunused-arguments"],,[[$CXXFLAG_WERROR]])
-fi
VERIFY_DEFINES=-DMINISKETCH_VERIFY
RELEASE_DEFINES=
diff --git a/src/minisketch/src/bench.cpp b/src/minisketch/src/bench.cpp
index f55944a448..dc44379fdb 100644
--- a/src/minisketch/src/bench.cpp
+++ b/src/minisketch/src/bench.cpp
@@ -62,13 +62,11 @@ int main(int argc, char** argv) {
if (!states[0]) {
printf(" -\t");
} else {
- double total = 0.0;
for (auto& state : states) {
auto start = std::chrono::steady_clock::now();
minisketch_decode(state, 2 * syndromes, roots.data());
auto stop = std::chrono::steady_clock::now();
std::chrono::duration<double> dur(stop - start);
- total += dur.count();
benches.push_back(dur.count());
}
std::sort(benches.begin(), benches.end());
@@ -98,7 +96,6 @@ int main(int argc, char** argv) {
if (!states[0]) {
printf(" -\t");
} else {
- double total = 0.0;
for (auto& state : states) {
auto start = std::chrono::steady_clock::now();
for (auto val : data) {
@@ -106,7 +103,6 @@ int main(int argc, char** argv) {
}
auto stop = std::chrono::steady_clock::now();
std::chrono::duration<double> dur(stop - start);
- total += dur.count();
benches.push_back(dur.count());
}
std::sort(benches.begin(), benches.end());
diff --git a/src/minisketch/src/int_utils.h b/src/minisketch/src/int_utils.h
index 62b2c38a29..d21ba56f33 100644
--- a/src/minisketch/src/int_utils.h
+++ b/src/minisketch/src/int_utils.h
@@ -129,17 +129,7 @@ constexpr inline I Mask() { return ((I((I(-1)) << (std::numeric_limits<I>::digit
/** Compute the smallest power of two that is larger than val. */
template<typename I>
static inline int CountBits(I val, int max) {
-#ifdef HAVE_CLZ
- (void)max;
- if (val == 0) return 0;
- if (std::numeric_limits<unsigned>::digits >= std::numeric_limits<I>::digits) {
- return std::numeric_limits<unsigned>::digits - __builtin_clz(val);
- } else if (std::numeric_limits<unsigned long>::digits >= std::numeric_limits<I>::digits) {
- return std::numeric_limits<unsigned long>::digits - __builtin_clzl(val);
- } else {
- return std::numeric_limits<unsigned long long>::digits - __builtin_clzll(val);
- }
-#elif _MSC_VER
+#ifdef _MSC_VER
(void)max;
unsigned long index;
unsigned char ret;
@@ -149,7 +139,17 @@ static inline int CountBits(I val, int max) {
ret = _BitScanReverse64(&index, val);
}
if (!ret) return 0;
- return index;
+ return index + 1;
+#elif HAVE_CLZ
+ (void)max;
+ if (val == 0) return 0;
+ if (std::numeric_limits<unsigned>::digits >= std::numeric_limits<I>::digits) {
+ return std::numeric_limits<unsigned>::digits - __builtin_clz(val);
+ } else if (std::numeric_limits<unsigned long>::digits >= std::numeric_limits<I>::digits) {
+ return std::numeric_limits<unsigned long>::digits - __builtin_clzl(val);
+ } else {
+ return std::numeric_limits<unsigned long long>::digits - __builtin_clzll(val);
+ }
#else
while (max && (val >> (max - 1) == 0)) --max;
return max;
diff --git a/src/minisketch/src/test.cpp b/src/minisketch/src/test.cpp
index 417937ea5f..85b9e9e396 100644
--- a/src/minisketch/src/test.cpp
+++ b/src/minisketch/src/test.cpp
@@ -9,6 +9,7 @@
#include <limits>
#include <random>
#include <stdexcept>
+#include <string>
#include <vector>
#include "../include/minisketch.h"
diff --git a/src/net.cpp b/src/net.cpp
index 0736f3ef1b..9b803180f9 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,12 +16,13 @@
#include <compat/compat.h>
#include <consensus/consensus.h>
#include <crypto/sha256.h>
-#include <node/eviction.h>
#include <fs.h>
#include <i2p.h>
+#include <logging.h>
#include <net_permissions.h>
#include <netaddress.h>
#include <netbase.h>
+#include <node/eviction.h>
#include <node/interface_ui.h>
#include <protocol.h>
#include <random.h>
@@ -31,6 +32,7 @@
#include <util/syscall_sandbox.h>
#include <util/system.h>
#include <util/thread.h>
+#include <util/threadinterrupt.h>
#include <util/trace.h>
#include <util/translation.h>
@@ -195,7 +197,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
s >> endpoint;
CAddress addr{endpoint, GetDesirableServiceFlags(NODE_NONE)};
addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - one_week, -one_week);
- LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToString());
+ LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToStringAddrPort());
vSeedsOut.push_back(addr);
}
return vSeedsOut;
@@ -257,7 +259,7 @@ std::optional<CService> GetLocalAddrForPeer(CNode& node)
}
if (addrLocal.IsRoutable() || gArgs.GetBoolArg("-addrmantest", false))
{
- LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToString(), node.GetId());
+ LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToStringAddrPort(), node.GetId());
return addrLocal;
}
// Address is unroutable. Don't advertise.
@@ -294,7 +296,7 @@ bool AddLocal(const CService& addr_, int nScore)
if (!IsReachable(addr))
return false;
- LogPrintf("AddLocal(%s,%i)\n", addr.ToString(), nScore);
+ LogPrintf("AddLocal(%s,%i)\n", addr.ToStringAddrPort(), nScore);
{
LOCK(g_maplocalhost_mutex);
@@ -317,7 +319,7 @@ bool AddLocal(const CNetAddr &addr, int nScore)
void RemoveLocal(const CService& addr)
{
LOCK(g_maplocalhost_mutex);
- LogPrintf("RemoveLocal(%s)\n", addr.ToString());
+ LogPrintf("RemoveLocal(%s)\n", addr.ToStringAddrPort());
mapLocalHost.erase(addr);
}
@@ -404,7 +406,7 @@ CNode* CConnman::FindNode(const CService& addr)
bool CConnman::AlreadyConnectedToAddress(const CAddress& addr)
{
- return FindNode(static_cast<CNetAddr>(addr)) || FindNode(addr.ToStringIPPort());
+ return FindNode(static_cast<CNetAddr>(addr)) || FindNode(addr.ToStringAddrPort());
}
bool CConnman::CheckIncomingNonce(uint64_t nonce)
@@ -435,6 +437,7 @@ static CAddress GetBindAddress(const Sock& sock)
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type)
{
+ AssertLockNotHeld(m_unused_i2p_sessions_mutex);
assert(conn_type != ConnectionType::INBOUND);
if (pszDest == nullptr) {
@@ -451,7 +454,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
}
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying connection %s lastseen=%.1fhrs\n",
- pszDest ? pszDest : addrConnect.ToString(),
+ pszDest ? pszDest : addrConnect.ToStringAddrPort(),
Ticks<HoursDouble>(pszDest ? 0h : Now<NodeSeconds>() - addrConnect.nTime));
// Resolve
@@ -463,7 +466,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
const CService rnd{resolved[GetRand(resolved.size())]};
addrConnect = CAddress{MaybeFlipIPv6toCJDNS(rnd), NODE_NONE};
if (!addrConnect.IsValid()) {
- LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToString(), pszDest);
+ LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToStringAddrPort(), pszDest);
return nullptr;
}
// It is possible that we already have a connection to the IP/port pszDest resolved to.
@@ -495,8 +498,23 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (m_i2p_sam_session) {
connected = m_i2p_sam_session->Connect(addrConnect, conn, proxyConnectionFailed);
} else {
- i2p_transient_session = std::make_unique<i2p::sam::Session>(proxy.proxy, &interruptNet);
+ {
+ LOCK(m_unused_i2p_sessions_mutex);
+ if (m_unused_i2p_sessions.empty()) {
+ i2p_transient_session =
+ std::make_unique<i2p::sam::Session>(proxy.proxy, &interruptNet);
+ } else {
+ i2p_transient_session.swap(m_unused_i2p_sessions.front());
+ m_unused_i2p_sessions.pop();
+ }
+ }
connected = i2p_transient_session->Connect(addrConnect, conn, proxyConnectionFailed);
+ if (!connected) {
+ LOCK(m_unused_i2p_sessions_mutex);
+ if (m_unused_i2p_sessions.size() < MAX_UNUSED_I2P_SESSIONS_SIZE) {
+ m_unused_i2p_sessions.emplace(i2p_transient_session.release());
+ }
+ }
}
if (connected) {
@@ -508,7 +526,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (!sock) {
return nullptr;
}
- connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(),
+ connected = ConnectThroughProxy(proxy, addrConnect.ToStringAddr(), addrConnect.GetPort(),
*sock, nConnectTimeout, proxyConnectionFailed);
} else {
// no proxy needed (none set for target network)
@@ -592,7 +610,7 @@ void CNode::SetAddrLocal(const CService& addrLocalIn) {
AssertLockNotHeld(m_addr_local_mutex);
LOCK(m_addr_local_mutex);
if (addrLocal.IsValid()) {
- error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToString(), addrLocalIn.ToString());
+ error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToStringAddrPort(), addrLocalIn.ToStringAddrPort());
} else {
addrLocal = addrLocalIn;
}
@@ -643,7 +661,7 @@ void CNode::CopyStats(CNodeStats& stats)
// Leave string empty if addrLocal invalid (not filled in yet)
CService addrLocalUnlocked = GetAddrLocal();
- stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : "";
+ stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToStringAddrPort() : "";
X(m_conn_type);
}
@@ -824,7 +842,13 @@ size_t CConnman::SocketSendData(CNode& node) const
if (!node.m_sock) {
break;
}
- nBytes = node.m_sock->Send(reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
+ int flags = MSG_NOSIGNAL | MSG_DONTWAIT;
+#ifdef MSG_MORE
+ if (it + 1 != node.vSendMsg.end()) {
+ flags |= MSG_MORE;
+ }
+#endif
+ nBytes = node.m_sock->Send(reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, flags);
}
if (nBytes > 0) {
node.m_last_send = GetTime<std::chrono::seconds>();
@@ -966,13 +990,12 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
}
if (!fNetworkActive) {
- LogPrint(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToString());
+ LogPrint(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToStringAddrPort());
return;
}
- if (!IsSelectableSocket(sock->Get()))
- {
- LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString());
+ if (!sock->IsSelectable()) {
+ LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToStringAddrPort());
return;
}
@@ -981,14 +1004,14 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
const int on{1};
if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) {
LogPrint(BCLog::NET, "connection from %s: unable to set TCP_NODELAY, continuing anyway\n",
- addr.ToString());
+ addr.ToStringAddrPort());
}
// Don't accept connections from banned peers.
bool banned = m_banman && m_banman->IsBanned(addr);
if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && banned)
{
- LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
+ LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToStringAddrPort());
return;
}
@@ -996,7 +1019,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
bool discouraged = m_banman && m_banman->IsDiscouraged(addr);
if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && nInbound + 1 >= nMaxInbound && discouraged)
{
- LogPrint(BCLog::NET, "connection from %s dropped (discouraged)\n", addr.ToString());
+ LogPrint(BCLog::NET, "connection from %s dropped (discouraged)\n", addr.ToStringAddrPort());
return;
}
@@ -1034,7 +1057,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
pnode->AddRef();
m_msgproc->InitializeNode(*pnode, nodeServices);
- LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
+ LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToStringAddrPort());
{
LOCK(m_nodes_mutex);
@@ -1047,6 +1070,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type)
{
+ AssertLockNotHeld(m_unused_i2p_sessions_mutex);
std::optional<int> max_connections;
switch (conn_type) {
case ConnectionType::INBOUND:
@@ -1305,15 +1329,14 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
RecordBytesRecv(nBytes);
if (notify) {
size_t nSizeAdded = 0;
- auto it(pnode->vRecvMsg.begin());
- for (; it != pnode->vRecvMsg.end(); ++it) {
+ for (const auto& msg : pnode->vRecvMsg) {
// vRecvMsg contains only completed CNetMessage
// the single possible partially deserialized message are held by TransportDeserializer
- nSizeAdded += it->m_raw_message_size;
+ nSizeAdded += msg.m_raw_message_size;
}
{
LOCK(pnode->cs_vProcessMsg);
- pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it);
+ pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg);
pnode->nProcessQueueSize += nSizeAdded;
pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize;
}
@@ -1399,7 +1422,7 @@ void CConnman::ThreadDNSAddressSeed()
if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) {
// When -forcednsseed is provided, query all.
seeds_right_now = seeds.size();
- } else if (addrman.size() == 0) {
+ } else if (addrman.Size() == 0) {
// If we have no known peers, query all.
// This will occur on the first run, or if peers.dat has been
// deleted.
@@ -1418,13 +1441,13 @@ void CConnman::ThreadDNSAddressSeed()
// * If we continue having problems, eventually query all the
// DNS seeds, and if that fails too, also try the fixed seeds.
// (done in ThreadOpenConnections)
- const std::chrono::seconds seeds_wait_time = (addrman.size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
+ const std::chrono::seconds seeds_wait_time = (addrman.Size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
for (const std::string& seed : seeds) {
if (seeds_right_now == 0) {
seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
- if (addrman.size() > 0) {
+ if (addrman.Size() > 0) {
LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());
std::chrono::seconds to_wait = seeds_wait_time;
while (to_wait.count() > 0) {
@@ -1466,6 +1489,8 @@ void CConnman::ThreadDNSAddressSeed()
}
LogPrintf("Loading addresses from DNS seed %s\n", seed);
+ // If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address
+ // for the base dns seed domain in chainparams
if (HaveNameProxy()) {
AddAddrFetch(seed);
} else {
@@ -1487,8 +1512,9 @@ void CConnman::ThreadDNSAddressSeed()
}
addrman.Add(vAdd, resolveSource);
} else {
- // We now avoid directly using results from DNS Seeds which do not support service bit filtering,
- // instead using them as a addrfetch to get nodes with our desired service bits.
+ // If the seed does not support a subdomain with our desired service bits,
+ // we make an ADDR_FETCH connection to the DNS resolved peer address for the
+ // base dns seed domain in chainparams
AddAddrFetch(seed);
}
}
@@ -1504,11 +1530,12 @@ void CConnman::DumpAddresses()
DumpPeerAddresses(::gArgs, addrman);
LogPrint(BCLog::NET, "Flushed %d addresses to peers.dat %dms\n",
- addrman.size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
+ addrman.Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
}
void CConnman::ProcessAddrFetch()
{
+ AssertLockNotHeld(m_unused_i2p_sessions_mutex);
std::string strDest;
{
LOCK(m_addr_fetches_mutex);
@@ -1575,8 +1602,22 @@ int CConnman::GetExtraBlockRelayCount() const
return std::max(block_relay_peers - m_max_outbound_block_relay, 0);
}
+std::unordered_set<Network> CConnman::GetReachableEmptyNetworks() const
+{
+ std::unordered_set<Network> networks{};
+ for (int n = 0; n < NET_MAX; n++) {
+ enum Network net = (enum Network)n;
+ if (net == NET_UNROUTABLE || net == NET_INTERNAL) continue;
+ if (IsReachable(net) && addrman.Size(net, std::nullopt) == 0) {
+ networks.insert(net);
+ }
+ }
+ return networks;
+}
+
void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
+ AssertLockNotHeld(m_unused_i2p_sessions_mutex);
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_OPEN_CONNECTION);
FastRandomContext rng;
// Connect to specific addresses
@@ -1584,7 +1625,6 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
for (int64_t nLoop = 0;; nLoop++)
{
- ProcessAddrFetch();
for (const std::string& strAddr : connect)
{
CAddress addr(CService(), NODE_NONE);
@@ -1624,7 +1664,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
if (interruptNet)
return;
- if (add_fixed_seeds && addrman.size() == 0) {
+ const std::unordered_set<Network> fixed_seed_networks{GetReachableEmptyNetworks()};
+ if (add_fixed_seeds && !fixed_seed_networks.empty()) {
// When the node starts with an empty peers.dat, there are a few other sources of peers before
// we fallback on to fixed seeds: -dnsseed, -seednode, -addnode
// If none of those are available, we fallback on to fixed seeds immediately, else we allow
@@ -1633,7 +1674,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// It is cheapest to check if enough time has passed first.
if (GetTime<std::chrono::seconds>() > start + std::chrono::minutes{1}) {
add_fixed_seeds_now = true;
- LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty\n");
+ LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty for at least one reachable network\n");
}
// Checking !dnsseed is cheaper before locking 2 mutexes.
@@ -1650,14 +1691,12 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// We will not make outgoing connections to peers that are unreachable
// (e.g. because of -onlynet configuration).
// Therefore, we do not add them to addrman in the first place.
- // Note that if you change -onlynet setting from one network to another,
- // peers.dat will contain only peers of unreachable networks and
- // manual intervention will be needed (either delete peers.dat after
- // configuration change or manually add some reachable peer using addnode),
- // see <https://github.com/bitcoin/bitcoin/issues/26035> for details.
+ // In case previously unreachable networks become reachable
+ // (e.g. in case of -onlynet changes by the user), fixed seeds will
+ // be loaded only for networks for which we have no addresses.
seed_addrs.erase(std::remove_if(seed_addrs.begin(), seed_addrs.end(),
- [](const CAddress& addr) { return !IsReachable(addr); }),
- seed_addrs.end());
+ [&fixed_seed_networks](const CAddress& addr) { return fixed_seed_networks.count(addr.GetNetwork()) == 0; }),
+ seed_addrs.end());
CNetAddr local;
local.SetInternal("fixedseeds");
addrman.Add(seed_addrs, local);
@@ -1682,19 +1721,20 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
if (pnode->IsFullOutboundConn()) nOutboundFullRelay++;
if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++;
- // Netgroups for inbound and manual peers are not excluded because our goal here
- // is to not use multiple of our limited outbound slots on a single netgroup
- // but inbound and manual peers do not use our outbound slots. Inbound peers
- // also have the added issue that they could be attacker controlled and used
- // to prevent us from connecting to particular hosts if we used them here.
+ // Make sure our persistent outbound slots belong to different netgroups.
switch (pnode->m_conn_type) {
+ // We currently don't take inbound connections into account. Since they are
+ // free to make, an attacker could make them to prevent us from connecting to
+ // certain peers.
case ConnectionType::INBOUND:
- case ConnectionType::MANUAL:
+ // Short-lived outbound connections should not affect how we select outbound
+ // peers from addrman.
+ case ConnectionType::ADDR_FETCH:
+ case ConnectionType::FEELER:
break;
+ case ConnectionType::MANUAL:
case ConnectionType::OUTBOUND_FULL_RELAY:
case ConnectionType::BLOCK_RELAY:
- case ConnectionType::ADDR_FETCH:
- case ConnectionType::FEELER:
setConnected.insert(m_netgroupman.GetGroup(pnode->addr));
} // no default case, so the compiler can warn about missing cases
}
@@ -1771,7 +1811,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
!HasAllDesirableServiceFlags(addr.nServices) ||
setConnected.count(m_netgroupman.GetGroup(addr))) continue;
addrConnect = addr;
- LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToString());
+ LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToStringAddrPort());
break;
}
@@ -1851,7 +1891,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
if (!interruptNet.sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {
return;
}
- LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
+ LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToStringAddrPort());
}
OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, conn_type);
@@ -1928,6 +1968,7 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
void CConnman::ThreadOpenAddedConnections()
{
+ AssertLockNotHeld(m_unused_i2p_sessions_mutex);
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_ADD_CONNECTION);
while (true)
{
@@ -1957,6 +1998,7 @@ void CConnman::ThreadOpenAddedConnections()
// if successful, this moves the passed grant to the constructed node
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, ConnectionType conn_type)
{
+ AssertLockNotHeld(m_unused_i2p_sessions_mutex);
assert(conn_type != ConnectionType::INBOUND);
//
@@ -2080,7 +2122,7 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
socklen_t len = sizeof(sockaddr);
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
{
- strError = strprintf(Untranslated("Bind address family for %s not supported"), addrBind.ToString());
+ strError = strprintf(Untranslated("Bind address family for %s not supported"), addrBind.ToStringAddrPort());
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
return false;
}
@@ -2120,13 +2162,13 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
if (sock->Bind(reinterpret_cast<struct sockaddr*>(&sockaddr), len) == SOCKET_ERROR) {
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
- strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), PACKAGE_NAME);
+ strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToStringAddrPort(), PACKAGE_NAME);
else
- strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
+ strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToStringAddrPort(), NetworkErrorString(nErr));
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
return false;
}
- LogPrintf("Bound to %s\n", addrBind.ToString());
+ LogPrintf("Bound to %s\n", addrBind.ToStringAddrPort());
// Listen for incoming connections
if (sock->Listen(SOMAXCONN) == SOCKET_ERROR)
@@ -2156,7 +2198,7 @@ void Discover()
for (const CNetAddr &addr : vaddr)
{
if (AddLocal(addr, LOCAL_IF))
- LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToString());
+ LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToStringAddr());
}
}
}
@@ -2176,14 +2218,14 @@ void Discover()
struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
CNetAddr addr(s4->sin_addr);
if (AddLocal(addr, LOCAL_IF))
- LogPrintf("%s: IPv4 %s: %s\n", __func__, ifa->ifa_name, addr.ToString());
+ LogPrintf("%s: IPv4 %s: %s\n", __func__, ifa->ifa_name, addr.ToStringAddr());
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
CNetAddr addr(s6->sin6_addr);
if (AddLocal(addr, LOCAL_IF))
- LogPrintf("%s: IPv6 %s: %s\n", __func__, ifa->ifa_name, addr.ToString());
+ LogPrintf("%s: IPv6 %s: %s\n", __func__, ifa->ifa_name, addr.ToStringAddr());
}
}
freeifaddrs(myaddrs);
@@ -2742,7 +2784,7 @@ CNode::CNode(NodeId idIn,
m_connected{GetTime<std::chrono::seconds>()},
addr{addrIn},
addrBind{addrBindIn},
- m_addr_name{addrNameIn.empty() ? addr.ToStringIPPort() : addrNameIn},
+ m_addr_name{addrNameIn.empty() ? addr.ToStringAddrPort() : addrNameIn},
m_inbound_onion{inbound_onion},
m_prefer_evict{node_opts.prefer_evict},
nKeyedNetGroup{nKeyedNetGroupIn},
@@ -2848,7 +2890,7 @@ void CaptureMessageToFile(const CAddress& addr,
auto now = GetTime<std::chrono::microseconds>();
// Windows folder names cannot include a colon
- std::string clean_addr = addr.ToString();
+ std::string clean_addr = addr.ToStringAddrPort();
std::replace(clean_addr.begin(), clean_addr.end(), ':', '_');
fs::path base_path = gArgs.GetDataDirNet() / "message_capture" / fs::u8path(clean_addr);
diff --git a/src/net.h b/src/net.h
index 11bfc4c9fb..2025dfdb05 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -24,10 +24,10 @@
#include <span.h>
#include <streams.h>
#include <sync.h>
-#include <threadinterrupt.h>
#include <uint256.h>
#include <util/check.h>
#include <util/sock.h>
+#include <util/threadinterrupt.h>
#include <atomic>
#include <condition_variable>
@@ -38,7 +38,9 @@
#include <map>
#include <memory>
#include <optional>
+#include <queue>
#include <thread>
+#include <unordered_set>
#include <vector>
class AddrMan;
@@ -489,10 +491,8 @@ public:
/** Whether this peer provides all services that we want. Used for eviction decisions */
std::atomic_bool m_has_all_wanted_services{false};
- /** Whether we should relay transactions to this peer (their version
- * message did not include fRelay=false and this is not a block-relay-only
- * connection). This only changes from false to true. It will never change
- * back to false. Used only in inbound eviction logic. */
+ /** Whether we should relay transactions to this peer. This only changes
+ * from false to true. It will never change back to false. */
std::atomic_bool m_relays_txs{false};
/** Whether this peer has loaded a bloom filter. Used only in inbound
@@ -745,7 +745,7 @@ public:
bool GetNetworkActive() const { return fNetworkActive; };
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
void SetNetworkActive(bool active);
- void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type);
+ void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
bool CheckIncomingNonce(uint64_t nonce);
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
@@ -821,7 +821,7 @@ public:
* - Max total outbound connection capacity filled
* - Max connection capacity for type is filled
*/
- bool AddConnection(const std::string& address, ConnectionType conn_type);
+ bool AddConnection(const std::string& address, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
size_t GetNodeCount(ConnectionDirection) const;
void GetNodeStats(std::vector<CNodeStats>& vstats) const;
@@ -887,10 +887,10 @@ private:
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
bool InitBinds(const Options& options);
- void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
+ void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_unused_i2p_sessions_mutex);
void AddAddrFetch(const std::string& strDest) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex);
- void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex);
- void ThreadOpenConnections(std::vector<std::string> connect) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex);
+ void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_unused_i2p_sessions_mutex);
+ void ThreadOpenConnections(std::vector<std::string> connect) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex);
void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
void ThreadI2PAcceptIncoming();
void AcceptConnection(const ListenSocket& hListenSocket);
@@ -957,7 +957,7 @@ private:
bool AlreadyConnectedToAddress(const CAddress& addr);
bool AttemptToEvictConnection();
- CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type);
+ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
void DeleteNode(CNode* pnode);
@@ -972,6 +972,12 @@ private:
void RecordBytesSent(uint64_t bytes) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
/**
+ Return reachable networks for which we have no addresses in addrman and therefore
+ may require loading fixed seeds.
+ */
+ std::unordered_set<Network> GetReachableEmptyNetworks() const;
+
+ /**
* Return vector of current BLOCK_RELAY peers.
*/
std::vector<CAddress> GetCurrentBlockRelayOnlyConns() const;
@@ -1129,6 +1135,26 @@ private:
std::vector<CService> m_onion_binds;
/**
+ * Mutex protecting m_i2p_sam_sessions.
+ */
+ Mutex m_unused_i2p_sessions_mutex;
+
+ /**
+ * A pool of created I2P SAM transient sessions that should be used instead
+ * of creating new ones in order to reduce the load on the I2P network.
+ * Creating a session in I2P is not cheap, thus if this is not empty, then
+ * pick an entry from it instead of creating a new session. If connecting to
+ * a host fails, then the created session is put to this pool for reuse.
+ */
+ std::queue<std::unique_ptr<i2p::sam::Session>> m_unused_i2p_sessions GUARDED_BY(m_unused_i2p_sessions_mutex);
+
+ /**
+ * Cap on the size of `m_unused_i2p_sessions`, to ensure it does not
+ * unexpectedly use too much memory.
+ */
+ static constexpr size_t MAX_UNUSED_I2P_SESSIONS_SIZE{10};
+
+ /**
* RAII helper to atomically create a copy of `m_nodes` and add a reference
* to each of the nodes. The nodes are released when this object is destroyed.
*/
diff --git a/src/net_permissions.h b/src/net_permissions.h
index 662464083c..b7f3bffe1c 100644
--- a/src/net_permissions.h
+++ b/src/net_permissions.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -35,7 +35,8 @@ enum class NetPermissionFlags : uint32_t {
// unlimited amounts of addrs.
Addr = (1U << 7),
- // True if the user did not specifically set fine grained permissions
+ // True if the user did not specifically set fine-grained permissions with
+ // the -whitebind or -whitelist configuration options.
Implicit = (1U << 31),
All = BloomFilter | ForceRelay | Relay | NoBan | Mempool | Download | Addr,
};
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index eca6263392..25c65c7090 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,10 +16,12 @@
#include <hash.h>
#include <headerssync.h>
#include <index/blockfilterindex.h>
+#include <kernel/mempool_entry.h>
#include <merkleblock.h>
#include <netbase.h>
#include <netmessagemaker.h>
#include <node/blockstorage.h>
+#include <node/txreconciliation.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/settings.h>
@@ -51,9 +53,6 @@
using node::ReadBlockFromDisk;
using node::ReadRawBlockFromDisk;
-using node::fImporting;
-using node::fPruneMode;
-using node::fReindex;
/** How long to cache transactions in mapRelay for normal relay */
static constexpr auto RELAY_TX_CACHE_TIME = 15min;
@@ -111,8 +110,11 @@ static constexpr auto GETDATA_TX_INTERVAL{60s};
static const unsigned int MAX_GETDATA_SZ = 1000;
/** Number of blocks that can be requested at any given time from a single peer. */
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;
-/** Time during which a peer must stall block download progress before being disconnected. */
-static constexpr auto BLOCK_STALLING_TIMEOUT{2s};
+/** Default time during which a peer must stall block download progress before being disconnected.
+ * the actual timeout is increased temporarily if peers are disconnected for hitting the timeout */
+static constexpr auto BLOCK_STALLING_TIMEOUT_DEFAULT{2s};
+/** Maximum timeout for stalling block download. */
+static constexpr auto BLOCK_STALLING_TIMEOUT_MAX{64s};
/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends
* less than this number, we reached its tip. Changing this value is a protocol upgrade. */
static const unsigned int MAX_HEADERS_RESULTS = 2000;
@@ -271,12 +273,7 @@ struct Peer {
struct TxRelay {
mutable RecursiveMutex m_bloom_filter_mutex;
- /** Whether the peer wishes to receive transaction announcements.
- *
- * This is initially set based on the fRelay flag in the received
- * `version` message. If initially set to false, it can only be flipped
- * to true if we have offered the peer NODE_BLOOM services and it sends
- * us a `filterload` or `filterclear` message. See BIP37. */
+ /** Whether we relay transactions to this peer. */
bool m_relay_txs GUARDED_BY(m_bloom_filter_mutex){false};
/** A bloom filter for which transactions to announce to the peer. See BIP37. */
std::unique_ptr<CBloomFilter> m_bloom_filter PT_GUARDED_BY(m_bloom_filter_mutex) GUARDED_BY(m_bloom_filter_mutex){nullptr};
@@ -298,7 +295,7 @@ struct Peer {
std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
/** The next time after which we will send an `inv` message containing
* transaction announcements to this peer. */
- std::chrono::microseconds m_next_inv_send_time GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0};
+ std::chrono::microseconds m_next_inv_send_time GUARDED_BY(m_tx_inventory_mutex){0};
/** Minimum fee rate with which to filter transaction announcements to this node. See BIP133. */
std::atomic<CAmount> m_fee_filter_received{0};
@@ -368,9 +365,6 @@ struct Peer {
/** Total number of addresses that were processed (excludes rate-limited ones). */
std::atomic<uint64_t> m_addr_processed{0};
- /** Set of txids to reconsider once their parent transactions have been accepted **/
- std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
-
/** Whether we've sent this peer a getheaders in response to an inv prior to initial-headers-sync completing */
bool m_inv_triggered_getheaders_before_sync GUARDED_BY(NetEventsInterface::g_msgproc_mutex){false};
@@ -399,9 +393,7 @@ struct Peer {
private:
Mutex m_tx_relay_mutex;
- /** Transaction relay data. Will be a nullptr if we're not relaying
- * transactions with this peer (e.g. if it's a block-relay-only peer or
- * the peer has sent us fRelay=false with bloom filters disabled). */
+ /** Transaction relay data. May be a nullptr. */
std::unique_ptr<TxRelay> m_tx_relay GUARDED_BY(m_tx_relay_mutex);
};
@@ -589,8 +581,20 @@ private:
*/
bool MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer);
- void ProcessOrphanTx(std::set<uint256>& orphan_work_set) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans)
- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
+ /**
+ * Reconsider orphan transactions after a parent has been accepted to the mempool.
+ *
+ * @peer[in] peer The peer whose orphan transactions we will reconsider. Generally only
+ * one orphan will be reconsidered on each call of this function. If an
+ * accepted orphan has orphaned children, those will need to be
+ * reconsidered, creating more work, possibly for other peers.
+ * @return True if meaningful work was done (an orphan was accepted/rejected).
+ * If no meaningful work was done, then the work set for this peer
+ * will be empty.
+ */
+ bool ProcessOrphanTx(Peer& peer)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex);
+
/** Process a single headers message from a peer.
*
* @param[in] pfrom CNode of the peer
@@ -642,9 +646,8 @@ private:
* @param[in] chain_start_header Where these headers connect in our index.
* @param[in,out] headers The headers to be processed.
*
- * @return True if chain was low work and a headers sync was
- * initiated (and headers will be empty after calling); false
- * otherwise.
+ * @return True if chain was low work (headers will be empty after
+ * calling); false otherwise.
*/
bool TryLowWorkHeadersSync(Peer& peer, CNode& pfrom,
const CBlockIndex* chain_start_header,
@@ -661,9 +664,9 @@ private:
*/
bool MaybeSendGetHeaders(CNode& pfrom, const CBlockLocator& locator, Peer& peer) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
/** Potentially fetch blocks from this peer upon receipt of a new headers tip */
- void HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex* pindexLast);
+ void HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex& last_header);
/** Update peer state based on received headers message */
- void UpdatePeerStateForReceivedHeaders(CNode& pfrom, const CBlockIndex *pindexLast, bool received_new_header, bool may_have_more_headers);
+ void UpdatePeerStateForReceivedHeaders(CNode& pfrom, const CBlockIndex& last_header, bool received_new_header, bool may_have_more_headers);
void SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlock& block, const BlockTransactionsRequest& req);
@@ -708,6 +711,7 @@ private:
ChainstateManager& m_chainman;
CTxMemPool& m_mempool;
TxRequestTracker m_txrequest GUARDED_BY(::cs_main);
+ std::unique_ptr<TxReconciliationTracker> m_txreconciliation;
/** The height of the best chain */
std::atomic<int> m_best_height{-1};
@@ -770,6 +774,9 @@ private:
/** Number of preferable block download peers. */
int m_num_preferred_download_peers GUARDED_BY(cs_main){0};
+ /** Stalling timeout for blocks in IBD */
+ std::atomic<std::chrono::seconds> m_block_stalling_timeout{BLOCK_STALLING_TIMEOUT_DEFAULT};
+
bool AlreadyHaveTx(const GenTxid& gtxid)
EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex);
@@ -924,14 +931,14 @@ private:
/** Storage for orphan information */
TxOrphanage m_orphanage;
- void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
+ void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
/** Orphan/conflicted/etc transactions that are kept for compact block reconstruction.
* The last -blockreconstructionextratxn/DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN of
* these are kept in a ring buffer */
- std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans);
+ std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_msgproc_mutex);
/** Offset into vExtraTxnForCompact to insert the next tx */
- size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0;
+ size_t vExtraTxnForCompactIt GUARDED_BY(g_msgproc_mutex) = 0;
/** Check whether the last unknown block a peer advertised is not yet known. */
void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -1294,7 +1301,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability(peer.m_id);
- if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
+ if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < m_chainman.MinimumChainWork()) {
// This peer has nothing interesting.
return;
}
@@ -1383,14 +1390,14 @@ void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer)
CService addr_you = addr.IsRoutable() && !IsProxy(addr) && addr.IsAddrV1Compatible() ? addr : CService();
uint64_t your_services{addr.nServices};
- const bool tx_relay = !m_ignore_incoming_txs && !pnode.IsBlockOnlyConn() && !pnode.IsFeelerConn();
+ const bool tx_relay{!RejectIncomingTxs(pnode)};
m_connman.PushMessage(&pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, my_services, nTime,
your_services, addr_you, // Together the pre-version-31402 serialization of CAddress "addrYou" (without nTime)
my_services, CService(), // Together the pre-version-31402 serialization of CAddress "addrMe" (without nTime)
nonce, strSubVersion, nNodeStartingHeight, tx_relay));
if (fLogIPs) {
- LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, them=%s, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addr_you.ToString(), tx_relay, nodeid);
+ LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, them=%s, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addr_you.ToStringAddrPort(), tx_relay, nodeid);
} else {
LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, tx_relay, nodeid);
}
@@ -1495,8 +1502,9 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
for (const QueuedBlock& entry : state->vBlocksInFlight) {
mapBlocksInFlight.erase(entry.pindex->GetBlockHash());
}
- WITH_LOCK(g_cs_orphans, m_orphanage.EraseForPeer(nodeid));
+ m_orphanage.EraseForPeer(nodeid);
m_txrequest.DisconnectedPeer(nodeid);
+ if (m_txreconciliation) m_txreconciliation->ForgetPeer(nodeid);
m_num_preferred_download_peers -= state->fPreferredDownload;
m_peers_downloading_from -= (state->nBlocksInFlight != 0);
assert(m_peers_downloading_from >= 0);
@@ -1728,8 +1736,7 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex)
std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBlockIndex& block_index)
{
- if (fImporting) return "Importing...";
- if (fReindex) return "Reindexing...";
+ if (m_chainman.m_blockman.LoadingBlocks()) return "Loading blocks ...";
// Ensure this peer exists and hasn't been disconnected
PeerRef peer = GetPeerRef(peer_id);
@@ -1741,6 +1748,8 @@ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl
LOCK(cs_main);
// Mark block as in-flight unless it already is (for this peer).
+ // If the peer does not send us a block, vBlocksInFlight remains non-empty,
+ // causing us to timeout and disconnect.
// If a block was already in-flight for a different peer, its BLOCKTXN
// response will be dropped.
if (!BlockRequested(peer_id, block_index)) return "Already requested from this peer";
@@ -1781,6 +1790,11 @@ PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman,
m_mempool(pool),
m_ignore_incoming_txs(ignore_incoming_txs)
{
+ // While Erlay support is incomplete, it must be enabled explicitly via -txreconciliation.
+ // This argument can go away after Erlay support is complete.
+ if (gArgs.GetBoolArg("-txreconciliation", DEFAULT_TXRECONCILIATION_ENABLE)) {
+ m_txreconciliation = std::make_unique<TxReconciliationTracker>(TXRECONCILIATION_VERSION);
+ }
}
void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler)
@@ -1800,7 +1814,8 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler)
/**
* Evict orphan txn pool entries based on a newly connected
* block, remember the recently confirmed transactions, and delete tracked
- * announcements for them. Also save the time of the last tip update.
+ * announcements for them. Also save the time of the last tip update and
+ * possibly reduce dynamic block stalling timeout.
*/
void PeerManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
{
@@ -1823,6 +1838,16 @@ void PeerManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock
m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
}
}
+
+ // In case the dynamic timeout was doubled once or more, reduce it slowly back to its default value
+ auto stalling_timeout = m_block_stalling_timeout.load();
+ Assume(stalling_timeout >= BLOCK_STALLING_TIMEOUT_DEFAULT);
+ if (stalling_timeout != BLOCK_STALLING_TIMEOUT_DEFAULT) {
+ const auto new_timeout = std::max(std::chrono::duration_cast<std::chrono::seconds>(stalling_timeout * 0.85), BLOCK_STALLING_TIMEOUT_DEFAULT);
+ if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout, new_timeout)) {
+ LogPrint(BCLog::NET, "Decreased stalling timeout to %d seconds\n", count_seconds(new_timeout));
+ }
+ }
}
void PeerManagerImpl::BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex)
@@ -2010,8 +2035,15 @@ void PeerManagerImpl::RelayTransaction(const uint256& txid, const uint256& wtxid
auto tx_relay = peer.GetTxRelay();
if (!tx_relay) continue;
- const uint256& hash{peer.m_wtxid_relay ? wtxid : txid};
LOCK(tx_relay->m_tx_inventory_mutex);
+ // Only queue transactions for announcement once the version handshake
+ // is completed. The time of arrival for these transactions is
+ // otherwise at risk of leaking to a spy, if the spy is able to
+ // distinguish transactions received during the handshake from the rest
+ // in the announcement.
+ if (tx_relay->m_next_inv_send_time == 0s) continue;
+
+ const uint256& hash{peer.m_wtxid_relay ? wtxid : txid};
if (!tx_relay->m_tx_inventory_known_filter.contains(hash)) {
tx_relay->m_tx_inventory_to_send.insert(hash);
}
@@ -2284,9 +2316,9 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
std::vector<uint256> parent_ids_to_add;
{
LOCK(m_mempool.cs);
- auto txiter = m_mempool.GetIter(tx->GetHash());
- if (txiter) {
- const CTxMemPoolEntry::Parents& parents = (*txiter)->GetMemPoolParentsConst();
+ auto tx_iter = m_mempool.GetIter(tx->GetHash());
+ if (tx_iter) {
+ const CTxMemPoolEntry::Parents& parents = (*tx_iter)->GetMemPoolParentsConst();
parent_ids_to_add.reserve(parents.size());
for (const CTxMemPoolEntry& parent : parents) {
if (parent.GetTime() > now - UNCONDITIONAL_RELAY_DELAY) {
@@ -2389,7 +2421,7 @@ arith_uint256 PeerManagerImpl::GetAntiDoSWorkThreshold()
// near our tip.
near_chaintip_work = tip->nChainWork - std::min<arith_uint256>(144*GetBlockProof(*tip), tip->nChainWork);
}
- return std::max(near_chaintip_work, arith_uint256(nMinimumChainWork));
+ return std::max(near_chaintip_work, m_chainman.MinimumChainWork());
}
/**
@@ -2560,16 +2592,20 @@ bool PeerManagerImpl::TryLowWorkHeadersSync(Peer& peer, CNode& pfrom, const CBlo
peer.m_headers_sync.reset(new HeadersSyncState(peer.m_id, m_chainparams.GetConsensus(),
chain_start_header, minimum_chain_work));
- // Now a HeadersSyncState object for tracking this synchronization is created,
- // process the headers using it as normal.
- return IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
+ // Now a HeadersSyncState object for tracking this synchronization
+ // is created, process the headers using it as normal. Failures are
+ // handled inside of IsContinuationOfLowWorkHeadersSync.
+ (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
} else {
LogPrint(BCLog::NET, "Ignoring low-work chain (height=%u) from peer=%d\n", chain_start_header->nHeight + headers.size(), pfrom.GetId());
- // Since this is a low-work headers chain, no further processing is required.
- headers = {};
- return true;
}
+
+ // The peer has not yet given us a chain that meets our work threshold,
+ // so we want to prevent further processing of the headers in any case.
+ headers = {};
+ return true;
}
+
return false;
}
@@ -2602,22 +2638,21 @@ bool PeerManagerImpl::MaybeSendGetHeaders(CNode& pfrom, const CBlockLocator& loc
}
/*
- * Given a new headers tip ending in pindexLast, potentially request blocks towards that tip.
+ * Given a new headers tip ending in last_header, potentially request blocks towards that tip.
* We require that the given tip have at least as much work as our tip, and for
* our current tip to be "close to synced" (see CanDirectFetch()).
*/
-void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex* pindexLast)
+void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex& last_header)
{
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
LOCK(cs_main);
CNodeState *nodestate = State(pfrom.GetId());
- if (CanDirectFetch() && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= pindexLast->nChainWork) {
-
+ if (CanDirectFetch() && last_header.IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= last_header.nChainWork) {
std::vector<const CBlockIndex*> vToFetch;
- const CBlockIndex *pindexWalk = pindexLast;
- // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
+ const CBlockIndex* pindexWalk{&last_header};
+ // Calculate all the blocks we'd need to switch to last_header, up to a limit.
while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
!IsBlockRequested(pindexWalk->GetBlockHash()) &&
@@ -2633,8 +2668,8 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c
// direct fetch and rely on parallel download instead.
if (!m_chainman.ActiveChain().Contains(pindexWalk)) {
LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
- pindexLast->GetBlockHash().ToString(),
- pindexLast->nHeight);
+ last_header.GetBlockHash().ToString(),
+ last_header.nHeight);
} else {
std::vector<CInv> vGetData;
// Download as much as possible, from earliest to latest.
@@ -2651,14 +2686,15 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c
}
if (vGetData.size() > 1) {
LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n",
- pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
+ last_header.GetBlockHash().ToString(),
+ last_header.nHeight);
}
if (vGetData.size() > 0) {
if (!m_ignore_incoming_txs &&
nodestate->m_provides_cmpctblocks &&
vGetData.size() == 1 &&
mapBlocksInFlight.size() == 1 &&
- pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) {
+ last_header.pprev->IsValid(BLOCK_VALID_CHAIN)) {
// In any case, we want to download using a compact block, not a regular one
vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
}
@@ -2669,12 +2705,12 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c
}
/**
- * Given receipt of headers from a peer ending in pindexLast, along with
+ * Given receipt of headers from a peer ending in last_header, along with
* whether that header was new and whether the headers message was full,
* update the state we keep for the peer.
*/
void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom,
- const CBlockIndex *pindexLast, bool received_new_header, bool may_have_more_headers)
+ const CBlockIndex& last_header, bool received_new_header, bool may_have_more_headers)
{
LOCK(cs_main);
CNodeState *nodestate = State(pfrom.GetId());
@@ -2683,14 +2719,13 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom,
}
nodestate->nUnconnectingHeaders = 0;
- assert(pindexLast);
- UpdateBlockAvailability(pfrom.GetId(), pindexLast->GetBlockHash());
+ UpdateBlockAvailability(pfrom.GetId(), last_header.GetBlockHash());
// From here, pindexBestKnownBlock should be guaranteed to be non-null,
// because it is set in UpdateBlockAvailability. Some nullptr checks
// are still present, however, as belt-and-suspenders.
- if (received_new_header && pindexLast->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
+ if (received_new_header && last_header.nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
nodestate->m_last_block_announcement = GetTime();
}
@@ -2699,14 +2734,14 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom,
if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && !may_have_more_headers) {
// If the peer has no more headers to give us, then we know we have
// their tip.
- if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
+ if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < m_chainman.MinimumChainWork()) {
// This peer has too little work on their headers chain to help
// us sync -- disconnect if it is an outbound disconnection
// candidate.
- // Note: We compare their tip to nMinimumChainWork (rather than
+ // Note: We compare their tip to the minimum chain work (rather than
// m_chainman.ActiveChain().Tip()) because we won't start block download
// until we have a headers chain that has at least
- // nMinimumChainWork, even if a peer has a chain past our tip,
+ // the minimum chain work, even if a peer has a chain past our tip,
// as an anti-DoS measure.
if (pfrom.IsOutboundOrBlockRelayConn()) {
LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom.GetId());
@@ -2856,7 +2891,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
return;
}
}
- Assume(pindexLast);
+ assert(pindexLast);
// Consider fetching more headers if we are not using our headers-sync mechanism.
if (nCount == MAX_HEADERS_RESULTS && !have_headers_sync) {
@@ -2867,54 +2902,43 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
}
}
- UpdatePeerStateForReceivedHeaders(pfrom, pindexLast, received_new_header, nCount == MAX_HEADERS_RESULTS);
+ UpdatePeerStateForReceivedHeaders(pfrom, *pindexLast, received_new_header, nCount == MAX_HEADERS_RESULTS);
// Consider immediately downloading blocks.
- HeadersDirectFetchBlocks(pfrom, peer, pindexLast);
+ HeadersDirectFetchBlocks(pfrom, peer, *pindexLast);
return;
}
-/**
- * Reconsider orphan transactions after a parent has been accepted to the mempool.
- *
- * @param[in,out] orphan_work_set The set of orphan transactions to reconsider. Generally only one
- * orphan will be reconsidered on each call of this function. This set
- * may be added to if accepting an orphan causes its children to be
- * reconsidered.
- */
-void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
+bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
{
- AssertLockHeld(cs_main);
- AssertLockHeld(g_cs_orphans);
-
- while (!orphan_work_set.empty()) {
- const uint256 orphanHash = *orphan_work_set.begin();
- orphan_work_set.erase(orphan_work_set.begin());
+ AssertLockHeld(g_msgproc_mutex);
+ LOCK(cs_main);
- const auto [porphanTx, from_peer] = m_orphanage.GetTx(orphanHash);
- if (porphanTx == nullptr) continue;
+ CTransactionRef porphanTx = nullptr;
+ while (CTransactionRef porphanTx = m_orphanage.GetTxToReconsider(peer.m_id)) {
const MempoolAcceptResult result = m_chainman.ProcessTransaction(porphanTx);
const TxValidationState& state = result.m_state;
+ const uint256& orphanHash = porphanTx->GetHash();
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanHash, porphanTx->GetWitnessHash());
- m_orphanage.AddChildrenToWorkSet(*porphanTx, orphan_work_set);
+ m_orphanage.AddChildrenToWorkSet(*porphanTx);
m_orphanage.EraseTx(orphanHash);
for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
AddToCompactExtraTransactions(removedTx);
}
- break;
+ return true;
} else if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) {
if (state.IsInvalid()) {
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s from peer=%d. %s\n",
orphanHash.ToString(),
- from_peer,
+ peer.m_id,
state.ToString());
// Maybe punish peer that gave us an invalid orphan tx
- MaybePunishNodeForTx(from_peer, state);
+ MaybePunishNodeForTx(peer.m_id, state);
}
// Has inputs but not accepted to mempool
// Probably non-standard or insufficient fee
@@ -2949,9 +2973,11 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
}
}
m_orphanage.EraseTx(orphanHash);
- break;
+ return true;
}
}
+
+ return false;
}
bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer,
@@ -3205,7 +3231,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Disconnect if we connected to ourself
if (pfrom.IsInboundConn() && !m_connman.CheckIncomingNonce(nNonce))
{
- LogPrintf("connected to self at %s, disconnecting\n", pfrom.addr.ToString());
+ LogPrintf("connected to self at %s, disconnecting\n", pfrom.addr.ToStringAddrPort());
pfrom.fDisconnect = true;
return;
}
@@ -3241,8 +3267,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::SENDADDRV2));
}
- m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::VERACK));
-
pfrom.m_has_all_wanted_services = HasAllDesirableServiceFlags(nServices);
peer->m_their_services = nServices;
pfrom.SetAddrLocal(addrMe);
@@ -3252,11 +3276,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
peer->m_starting_height = starting_height;
- // We only initialize the m_tx_relay data structure if:
- // - this isn't an outbound block-relay-only connection; and
- // - fRelay=true or we're offering NODE_BLOOM to this peer
- // (NODE_BLOOM means that the peer may turn on tx relay later)
+ // Only initialize the Peer::TxRelay m_relay_txs data structure if:
+ // - this isn't an outbound block-relay-only connection, and
+ // - this isn't an outbound feeler connection, and
+ // - fRelay=true (the peer wishes to receive transaction announcements)
+ // or we're offering NODE_BLOOM to this peer. NODE_BLOOM means that
+ // the peer may turn on transaction relay later.
if (!pfrom.IsBlockOnlyConn() &&
+ !pfrom.IsFeelerConn() &&
(fRelay || (peer->m_our_services & NODE_BLOOM))) {
auto* const tx_relay = peer->SetTxRelay();
{
@@ -3266,6 +3293,22 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (fRelay) pfrom.m_relays_txs = true;
}
+ if (greatest_common_version >= WTXID_RELAY_VERSION && m_txreconciliation) {
+ // Per BIP-330, we announce txreconciliation support if:
+ // - protocol version per the peer's VERSION message supports WTXID_RELAY;
+ // - transaction relay is supported per the peer's VERSION message (see m_relays_txs);
+ // - this is not a block-relay-only connection and not a feeler (see m_relays_txs);
+ // - this is not an addr fetch connection;
+ // - we are not in -blocksonly mode.
+ if (pfrom.m_relays_txs && !pfrom.IsAddrFetchConn() && !m_ignore_incoming_txs) {
+ const uint64_t recon_salt = m_txreconciliation->PreRegisterPeer(pfrom.GetId());
+ m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::SENDTXRCNCL,
+ TXRECONCILIATION_VERSION, recon_salt));
+ }
+ }
+
+ m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::VERACK));
+
// Potentially mark this peer as a preferred download peer.
{
LOCK(cs_main);
@@ -3274,39 +3317,20 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
m_num_preferred_download_peers += state->fPreferredDownload;
}
- // Self advertisement & GETADDR logic
- if (!pfrom.IsInboundConn() && SetupAddressRelay(pfrom, *peer)) {
- // For outbound peers, we try to relay our address (so that other
- // nodes can try to find us more quickly, as we have no guarantee
- // that an outbound peer is even aware of how to reach us) and do a
- // one-time address fetch (to help populate/update our addrman). If
- // we're starting up for the first time, our addrman may be pretty
- // empty and no one will know who we are, so these mechanisms are
- // important to help us connect to the network.
- //
+ // Attempt to initialize address relay for outbound peers and use result
+ // to decide whether to send GETADDR, so that we don't send it to
+ // inbound or outbound block-relay-only peers.
+ bool send_getaddr{false};
+ if (!pfrom.IsInboundConn()) {
+ send_getaddr = SetupAddressRelay(pfrom, *peer);
+ }
+ if (send_getaddr) {
+ // Do a one-time address fetch to help populate/update our addrman.
+ // If we're starting up for the first time, our addrman may be pretty
+ // empty, so this mechanism is important to help us connect to the network.
// We skip this for block-relay-only peers. We want to avoid
// potentially leaking addr information and we do not want to
// indicate to the peer that we will participate in addr relay.
- if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
- {
- CAddress addr{GetLocalAddress(pfrom.addr), peer->m_our_services, Now<NodeSeconds>()};
- FastRandomContext insecure_rand;
- if (addr.IsRoutable())
- {
- LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
- PushAddress(*peer, addr, insecure_rand);
- } else if (IsPeerAddrLocalGood(&pfrom)) {
- // Override just the address with whatever the peer sees us as.
- // Leave the port in addr as it was returned by GetLocalAddress()
- // above, as this is an outbound connection and the peer cannot
- // observe our listening port.
- addr.SetIP(addrMe);
- LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
- PushAddress(*peer, addr, insecure_rand);
- }
- }
-
- // Get recent addresses
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR));
peer->m_getaddr_sent = true;
// When requesting a getaddr, accept an additional MAX_ADDR_TO_SEND addresses in response
@@ -3334,11 +3358,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
std::string remoteAddr;
if (fLogIPs)
- remoteAddr = ", peeraddr=" + pfrom.addr.ToString();
+ remoteAddr = ", peeraddr=" + pfrom.addr.ToStringAddrPort();
LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s\n",
cleanSubVer, pfrom.nVersion,
- peer->m_starting_height, addrMe.ToString(), fRelay, pfrom.GetId(),
+ peer->m_starting_height, addrMe.ToStringAddrPort(), fRelay, pfrom.GetId(),
remoteAddr);
int64_t nTimeOffset = nTime - GetTime();
@@ -3351,7 +3375,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// If the peer is old enough to have the old alert system, send it the final alert.
if (greatest_common_version <= 70012) {
- CDataStream finalAlert(ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"), SER_NETWORK, PROTOCOL_VERSION);
+ DataStream finalAlert{ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50")};
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make("alert", finalAlert));
}
@@ -3381,7 +3405,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (!pfrom.IsInboundConn()) {
LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n",
pfrom.nVersion.load(), peer->m_starting_height,
- pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToString()) : ""),
+ pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToStringAddrPort()) : ""),
pfrom.ConnectionTypeAsString());
}
@@ -3393,6 +3417,30 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// they may wish to request compact blocks from us
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/false, /*version=*/CMPCTBLOCKS_VERSION));
}
+
+ if (m_txreconciliation) {
+ if (!peer->m_wtxid_relay || !m_txreconciliation->IsPeerRegistered(pfrom.GetId())) {
+ // We could have optimistically pre-registered/registered the peer. In that case,
+ // we should forget about the reconciliation state here if this wasn't followed
+ // by WTXIDRELAY (since WTXIDRELAY can't be announced later).
+ m_txreconciliation->ForgetPeer(pfrom.GetId());
+ }
+ }
+
+ if (auto tx_relay = peer->GetTxRelay()) {
+ // `TxRelay::m_tx_inventory_to_send` must be empty before the
+ // version handshake is completed as
+ // `TxRelay::m_next_inv_send_time` is first initialised in
+ // `SendMessages` after the verack is received. Any transactions
+ // received during the version handshake would otherwise
+ // immediately be advertised without random delay, potentially
+ // leaking the time of arrival to a spy.
+ Assume(WITH_LOCK(
+ tx_relay->m_tx_inventory_mutex,
+ return tx_relay->m_tx_inventory_to_send.empty() &&
+ tx_relay->m_next_inv_send_time == 0s));
+ }
+
pfrom.fSuccessfullyConnected = true;
return;
}
@@ -3456,6 +3504,61 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
+ // Received from a peer demonstrating readiness to announce transactions via reconciliations.
+ // This feature negotiation must happen between VERSION and VERACK to avoid relay problems
+ // from switching announcement protocols after the connection is up.
+ if (msg_type == NetMsgType::SENDTXRCNCL) {
+ if (!m_txreconciliation) {
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl from peer=%d ignored, as our node does not have txreconciliation enabled\n", pfrom.GetId());
+ return;
+ }
+
+ if (pfrom.fSuccessfullyConnected) {
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received after verack from peer=%d; disconnecting\n", pfrom.GetId());
+ pfrom.fDisconnect = true;
+ return;
+ }
+
+ // Peer must not offer us reconciliations if we specified no tx relay support in VERSION.
+ if (RejectIncomingTxs(pfrom)) {
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received from peer=%d to which we indicated no tx relay; disconnecting\n", pfrom.GetId());
+ pfrom.fDisconnect = true;
+ return;
+ }
+
+ // Peer must not offer us reconciliations if they specified no tx relay support in VERSION.
+ // This flag might also be false in other cases, but the RejectIncomingTxs check above
+ // eliminates them, so that this flag fully represents what we are looking for.
+ if (!pfrom.m_relays_txs) {
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received from peer=%d which indicated no tx relay to us; disconnecting\n", pfrom.GetId());
+ pfrom.fDisconnect = true;
+ return;
+ }
+
+ uint32_t peer_txreconcl_version;
+ uint64_t remote_salt;
+ vRecv >> peer_txreconcl_version >> remote_salt;
+
+ const ReconciliationRegisterResult result = m_txreconciliation->RegisterPeer(pfrom.GetId(), pfrom.IsInboundConn(),
+ peer_txreconcl_version, remote_salt);
+ switch (result) {
+ case ReconciliationRegisterResult::NOT_FOUND:
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "Ignore unexpected txreconciliation signal from peer=%d\n", pfrom.GetId());
+ break;
+ case ReconciliationRegisterResult::SUCCESS:
+ break;
+ case ReconciliationRegisterResult::ALREADY_REGISTERED:
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "txreconciliation protocol violation from peer=%d (sendtxrcncl received from already registered peer); disconnecting\n", pfrom.GetId());
+ pfrom.fDisconnect = true;
+ return;
+ case ReconciliationRegisterResult::PROTOCOL_VIOLATION:
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "txreconciliation protocol violation from peer=%d; disconnecting\n", pfrom.GetId());
+ pfrom.fDisconnect = true;
+ return;
+ }
+ return;
+ }
+
if (!pfrom.fSuccessfullyConnected) {
LogPrint(BCLog::NET, "Unsupported message \"%s\" prior to verack from peer=%d\n", SanitizeString(msg_type), pfrom.GetId());
return;
@@ -3590,7 +3693,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
UpdateBlockAvailability(pfrom.GetId(), inv.hash);
- if (!fAlreadyHave && !fImporting && !fReindex && !IsBlockRequested(inv.hash)) {
+ if (!fAlreadyHave && !m_chainman.m_blockman.LoadingBlocks() && !IsBlockRequested(inv.hash)) {
// Headers-first is the primary method of announcement on
// the network. If a node fell back to sending blocks by
// inv, it may be for a re-org, or because we haven't
@@ -3723,8 +3826,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// If pruning, don't inv blocks unless we have on disk and are likely to still have
// for some reasonable time window (1 hour) that block relay might require.
const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / m_chainparams.GetConsensus().nPowTargetSpacing;
- if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= m_chainman.ActiveChain().Tip()->nHeight - nPrunedBlocksLikelyToHave))
- {
+ if (m_chainman.m_blockman.IsPruneMode() && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= m_chainman.ActiveChain().Tip()->nHeight - nPrunedBlocksLikelyToHave)) {
LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
break;
}
@@ -3800,7 +3902,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
- if (fImporting || fReindex) {
+ if (m_chainman.m_blockman.LoadingBlocks()) {
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d while importing/reindexing\n", pfrom.GetId());
return;
}
@@ -3810,12 +3912,12 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Note that if we were to be on a chain that forks from the checkpointed
// chain, then serving those headers to a peer that has seen the
// checkpointed chain would cause that peer to disconnect us. Requiring
- // that our chainwork exceed nMinimumChainWork is a protection against
+ // that our chainwork exceed the minimum chain work is a protection against
// being fed a bogus chain when we started up for the first time and
// getting partitioned off the honest network for serving that chain to
// others.
if (m_chainman.ActiveTip() == nullptr ||
- (m_chainman.ActiveTip()->nChainWork < nMinimumChainWork && !pfrom.HasPermission(NetPermissionFlags::Download))) {
+ (m_chainman.ActiveTip()->nChainWork < m_chainman.MinimumChainWork() && !pfrom.HasPermission(NetPermissionFlags::Download))) {
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because active chain has too little work; sending empty response\n", pfrom.GetId());
// Just respond with an empty headers message, to tell the peer to
// go away but not treat us as unresponsive.
@@ -3903,7 +4005,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
AddKnownTx(*peer, txid);
}
- LOCK2(cs_main, g_cs_orphans);
+ LOCK(cs_main);
m_txrequest.ReceivedResponse(pfrom.GetId(), txid);
if (tx.HasWitness()) m_txrequest.ReceivedResponse(pfrom.GetId(), wtxid);
@@ -3944,7 +4046,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
m_txrequest.ForgetTxHash(tx.GetHash());
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
- m_orphanage.AddChildrenToWorkSet(tx, peer->m_orphan_work_set);
+ m_orphanage.AddChildrenToWorkSet(tx);
pfrom.m_last_tx_time = GetTime<std::chrono::seconds>();
@@ -3956,9 +4058,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
AddToCompactExtraTransactions(removedTx);
}
-
- // Recursively process any orphan transactions that depended on this one
- ProcessOrphanTx(peer->m_orphan_work_set);
}
else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS)
{
@@ -4082,7 +4181,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::CMPCTBLOCK)
{
// Ignore cmpctblock received while importing
- if (fImporting || fReindex) {
+ if (m_chainman.m_blockman.LoadingBlocks()) {
LogPrint(BCLog::NET, "Unexpected cmpctblock message received from peer %d\n", pfrom.GetId());
return;
}
@@ -4139,7 +4238,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
bool fBlockReconstructed = false;
{
- LOCK2(cs_main, g_cs_orphans);
+ LOCK(cs_main);
// If AcceptBlockHeader returned true, it set pindex
assert(pindex);
UpdateBlockAvailability(pfrom.GetId(), pindex->GetBlockHash());
@@ -4279,7 +4378,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// (eg disk space). Because we only try to reconstruct blocks when
// we're close to caught up (via the CanDirectFetch() requirement
// above, combined with the behavior of not requesting blocks until
- // we have a chain with at least nMinimumChainWork), and we ignore
+ // we have a chain with at least the minimum chain work), and we ignore
// compact blocks with less work than our tip, it is safe to treat
// reconstructed compact blocks as having been requested.
ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/true);
@@ -4298,7 +4397,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::BLOCKTXN)
{
// Ignore blocktxn received while importing
- if (fImporting || fReindex) {
+ if (m_chainman.m_blockman.LoadingBlocks()) {
LogPrint(BCLog::NET, "Unexpected blocktxn message received from peer %d\n", pfrom.GetId());
return;
}
@@ -4373,7 +4472,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::HEADERS)
{
// Ignore headers received while importing
- if (fImporting || fReindex) {
+ if (m_chainman.m_blockman.LoadingBlocks()) {
LogPrint(BCLog::NET, "Unexpected headers message received from peer %d\n", pfrom.GetId());
return;
}
@@ -4418,7 +4517,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::BLOCK)
{
// Ignore block received while importing
- if (fImporting || fReindex) {
+ if (m_chainman.m_blockman.LoadingBlocks()) {
LogPrint(BCLog::NET, "Unexpected block message received from peer %d\n", pfrom.GetId());
return;
}
@@ -4767,16 +4866,13 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt
}
}
- {
- LOCK2(cs_main, g_cs_orphans);
- if (!peer->m_orphan_work_set.empty()) {
- ProcessOrphanTx(peer->m_orphan_work_set);
- }
- }
+ const bool processed_orphan = ProcessOrphanTx(*peer);
if (pfrom->fDisconnect)
return false;
+ if (processed_orphan) return true;
+
// this maintains the order of responses
// and prevents m_getdata_requests to grow unbounded
{
@@ -4784,11 +4880,6 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt
if (!peer->m_getdata_requests.empty()) return true;
}
- {
- LOCK(g_cs_orphans);
- if (!peer->m_orphan_work_set.empty()) return true;
- }
-
// Don't bother if send buffer is too full to respond anyway
if (pfrom->fPauseSend) return false;
@@ -4826,6 +4917,12 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt
LOCK(peer->m_getdata_requests_mutex);
if (!peer->m_getdata_requests.empty()) fMoreWork = true;
}
+ // Does this peer has an orphan ready to reconsider?
+ // (Note: we may have provided a parent for an orphan provided
+ // by another peer that was already processed; in that case,
+ // the extra work may not be noticed, possibly resulting in an
+ // unnecessary 100ms delay)
+ if (m_orphanage.HaveTxToReconsider(peer->m_id)) fMoreWork = true;
} catch (const std::exception& e) {
LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", __func__, SanitizeString(msg.m_type), msg.m_message_size, e.what(), typeid(e).name());
} catch (...) {
@@ -5007,7 +5104,7 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers()
if (now > m_stale_tip_check_time) {
// Check whether our tip is stale, and if so, allow using an extra
// outbound peer
- if (!fImporting && !fReindex && m_connman.GetNetworkActive() && m_connman.GetUseAddrmanOutgoing() && TipMayBeStale()) {
+ if (!m_chainman.m_blockman.LoadingBlocks() && m_connman.GetNetworkActive() && m_connman.GetUseAddrmanOutgoing() && TipMayBeStale()) {
LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n",
count_seconds(now - m_last_tip_update.load()));
m_connman.SetTryNewOutboundPeer(true);
@@ -5145,7 +5242,7 @@ void PeerManagerImpl::MaybeSendSendHeaders(CNode& node, Peer& peer)
LOCK(cs_main);
CNodeState &state = *State(node.GetId());
if (state.pindexBestKnownBlock != nullptr &&
- state.pindexBestKnownBlock->nChainWork > nMinimumChainWork) {
+ state.pindexBestKnownBlock->nChainWork > m_chainman.MinimumChainWork()) {
// Tell our peer we prefer to receive headers rather than inv's
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
@@ -5224,6 +5321,7 @@ bool PeerManagerImpl::RejectIncomingTxs(const CNode& peer) const
{
// block-relay-only peers may never send txs to us
if (peer.IsBlockOnlyConn()) return true;
+ if (peer.IsFeelerConn()) return true;
// In -blocksonly mode, peers need the 'relay' permission to send txs to us
if (m_ignore_incoming_txs && !peer.HasPermission(NetPermissionFlags::Relay)) return true;
return false;
@@ -5237,8 +5335,9 @@ bool PeerManagerImpl::SetupAddressRelay(const CNode& node, Peer& peer)
if (node.IsBlockOnlyConn()) return false;
if (!peer.m_addr_relay_enabled.exchange(true)) {
- // First addr message we have received from the peer, initialize
- // m_addr_known
+ // During version message processing (non-block-relay-only outbound peers)
+ // or on first addr-related message we have received (inbound peers), initialize
+ // m_addr_known.
peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
}
@@ -5312,7 +5411,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
}
}
- if (!state.fSyncStarted && CanServeBlocks(*peer) && !fImporting && !fReindex) {
+ if (!state.fSyncStarted && CanServeBlocks(*peer) && !m_chainman.m_blockman.LoadingBlocks()) {
// Only actively request headers from a single peer, unless we're close to today.
if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) || m_chainman.m_best_header->Time() > GetAdjustedTime() - 24h) {
const CBlockIndex* pindexStart = m_chainman.m_best_header;
@@ -5626,12 +5725,19 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
// Detect whether we're stalling
- if (state.m_stalling_since.count() && state.m_stalling_since < current_time - BLOCK_STALLING_TIMEOUT) {
+ auto stalling_timeout = m_block_stalling_timeout.load();
+ if (state.m_stalling_since.count() && state.m_stalling_since < current_time - stalling_timeout) {
// Stalling only triggers when the block download window cannot move. During normal steady state,
// the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
// should only happen during initial block download.
LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->GetId());
pto->fDisconnect = true;
+ // Increase timeout for the next peer so that we don't disconnect multiple peers if our own
+ // bandwidth is insufficient.
+ const auto new_timeout = std::min(2 * stalling_timeout, BLOCK_STALLING_TIMEOUT_MAX);
+ if (stalling_timeout != new_timeout && m_block_stalling_timeout.compare_exchange_strong(stalling_timeout, new_timeout)) {
+ LogPrint(BCLog::NET, "Increased stalling timeout temporarily to %d seconds\n", count_seconds(new_timeout));
+ }
return true;
}
// In case there is a block that has been in flight from this peer for block_interval * (1 + 0.5 * N)
diff --git a/src/net_processing.h b/src/net_processing.h
index 0d0842fa8e..af9a02139b 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/net_types.cpp b/src/net_types.cpp
index 90346715f0..2cdc10d8c9 100644
--- a/src/net_types.cpp
+++ b/src/net_types.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index ca148bfa51..85ae8fab36 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -179,7 +179,7 @@ bool CNetAddr::SetInternal(const std::string &name)
}
namespace torv3 {
-// https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt#n2135
+// https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt?id=7116c9cdaba248aae07a3f1d0e15d9dd102f62c5#n2175
static constexpr size_t CHECKSUM_LEN = 2;
static const unsigned char VERSION[] = {3};
static constexpr size_t TOTAL_LEN = ADDR_TORV3_SIZE + CHECKSUM_LEN + sizeof(VERSION);
@@ -588,7 +588,7 @@ static std::string IPv6ToString(Span<const uint8_t> a, uint32_t scope_id)
return r;
}
-static std::string OnionToString(Span<const uint8_t> addr)
+std::string OnionToString(Span<const uint8_t> addr)
{
uint8_t checksum[torv3::CHECKSUM_LEN];
torv3::Checksum(addr, checksum);
@@ -599,7 +599,7 @@ static std::string OnionToString(Span<const uint8_t> addr)
return EncodeBase32(address) + ".onion";
}
-std::string CNetAddr::ToStringIP() const
+std::string CNetAddr::ToStringAddr() const
{
switch (m_net) {
case NET_IPV4:
@@ -622,11 +622,6 @@ std::string CNetAddr::ToStringIP() const
assert(false);
}
-std::string CNetAddr::ToString() const
-{
- return ToStringIP();
-}
-
bool operator==(const CNetAddr& a, const CNetAddr& b)
{
return a.m_net == b.m_net && a.m_addr == b.m_addr;
@@ -916,25 +911,17 @@ std::vector<unsigned char> CService::GetKey() const
return key;
}
-std::string CService::ToStringPort() const
+std::string CService::ToStringAddrPort() const
{
- return strprintf("%u", port);
-}
+ const auto port_str = strprintf("%u", port);
-std::string CService::ToStringIPPort() const
-{
if (IsIPv4() || IsTor() || IsI2P() || IsInternal()) {
- return ToStringIP() + ":" + ToStringPort();
+ return ToStringAddr() + ":" + port_str;
} else {
- return "[" + ToStringIP() + "]:" + ToStringPort();
+ return "[" + ToStringAddr() + "]:" + port_str;
}
}
-std::string CService::ToString() const
-{
- return ToStringIPPort();
-}
-
CSubNet::CSubNet():
valid(false)
{
@@ -1098,7 +1085,7 @@ std::string CSubNet::ToString() const
break;
}
- return network.ToString() + suffix;
+ return network.ToStringAddr() + suffix;
}
bool CSubNet::IsValid() const
@@ -1106,29 +1093,6 @@ bool CSubNet::IsValid() const
return valid;
}
-bool CSubNet::SanityCheck() const
-{
- switch (network.m_net) {
- case NET_IPV4:
- case NET_IPV6:
- break;
- case NET_ONION:
- case NET_I2P:
- case NET_CJDNS:
- return true;
- case NET_INTERNAL:
- case NET_UNROUTABLE:
- case NET_MAX:
- return false;
- }
-
- for (size_t x = 0; x < network.m_addr.size(); ++x) {
- if (network.m_addr[x] & ~netmask[x]) return false;
- }
-
- return true;
-}
-
bool operator==(const CSubNet& a, const CSubNet& b)
{
return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16);
diff --git a/src/netaddress.h b/src/netaddress.h
index e52beb783d..3d15b0b123 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -111,6 +111,8 @@ static constexpr size_t ADDR_INTERNAL_SIZE = 10;
/// SAM 3.1 and earlier do not support specifying ports and force the port to 0.
static constexpr uint16_t I2P_SAM31_PORT{0};
+std::string OnionToString(Span<const uint8_t> addr);
+
/**
* Network address.
*/
@@ -191,8 +193,7 @@ public:
bool IsAddrV1Compatible() const;
enum Network GetNetwork() const;
- std::string ToString() const;
- std::string ToStringIP() const;
+ std::string ToStringAddr() const;
bool GetInAddr(struct in_addr* pipv4Addr) const;
Network GetNetClass() const;
@@ -474,8 +475,6 @@ protected:
/// Is this value valid? (only used to signal parse errors)
bool valid;
- bool SanityCheck() const;
-
public:
/**
* Construct an invalid subnet (empty, `Match()` always returns false).
@@ -534,9 +533,7 @@ public:
friend bool operator!=(const CService& a, const CService& b) { return !(a == b); }
friend bool operator<(const CService& a, const CService& b);
std::vector<unsigned char> GetKey() const;
- std::string ToString() const;
- std::string ToStringPort() const;
- std::string ToStringIPPort() const;
+ std::string ToStringAddrPort() const;
CService(const struct in6_addr& ipv6Addr, uint16_t port);
explicit CService(const struct sockaddr_in6& addr);
diff --git a/src/netbase.cpp b/src/netbase.cpp
index a5f7bda875..f39a3635f4 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -1,17 +1,17 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <netbase.h>
#include <compat/compat.h>
+#include <logging.h>
#include <sync.h>
#include <tinyformat.h>
#include <util/sock.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/time.h>
#include <atomic>
@@ -304,8 +304,7 @@ enum class IntrRecvError {
* read.
*
* @see This function can be interrupted by calling InterruptSocks5(bool).
- * Sockets can be made non-blocking with SetSocketNonBlocking(const
- * SOCKET&).
+ * Sockets can be made non-blocking with Sock::SetNonBlocking().
*/
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& sock)
{
@@ -489,7 +488,7 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family)
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
if (!address_family.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
- LogPrintf("Cannot create socket for %s: unsupported network\n", address_family.ToString());
+ LogPrintf("Cannot create socket for %s: unsupported network\n", address_family.ToStringAddrPort());
return nullptr;
}
@@ -503,7 +502,7 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family)
// Ensure that waiting for I/O on this socket won't result in undefined
// behavior.
- if (!IsSelectableSocket(sock->Get())) {
+ if (!sock->IsSelectable()) {
LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
return nullptr;
}
@@ -525,7 +524,7 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family)
}
// Set the non-blocking option on the socket.
- if (!SetSocketNonBlocking(sock->Get())) {
+ if (!sock->SetNonBlocking()) {
LogPrintf("Error setting socket to non-blocking: %s\n", NetworkErrorString(WSAGetLastError()));
return nullptr;
}
@@ -550,11 +549,11 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
if (sock.Get() == INVALID_SOCKET) {
- LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
+ LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToStringAddrPort());
return false;
}
if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
- LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
+ LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToStringAddrPort());
return false;
}
@@ -571,11 +570,11 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT
Sock::Event occurred;
if (!sock.Wait(std::chrono::milliseconds{nTimeout}, requested, &occurred)) {
LogPrintf("wait for connect to %s failed: %s\n",
- addrConnect.ToString(),
+ addrConnect.ToStringAddrPort(),
NetworkErrorString(WSAGetLastError()));
return false;
} else if (occurred == 0) {
- LogPrint(BCLog::NET, "connection attempt to %s timed out\n", addrConnect.ToString());
+ LogPrint(BCLog::NET, "connection attempt to %s timed out\n", addrConnect.ToStringAddrPort());
return false;
}
@@ -587,13 +586,13 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT
socklen_t sockerr_len = sizeof(sockerr);
if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&sockerr, &sockerr_len) ==
SOCKET_ERROR) {
- LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
+ LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToStringAddrPort(), NetworkErrorString(WSAGetLastError()));
return false;
}
if (sockerr != 0) {
LogConnectFailure(manual_connection,
"connect() to %s failed after wait: %s",
- addrConnect.ToString(),
+ addrConnect.ToStringAddrPort(),
NetworkErrorString(sockerr));
return false;
}
@@ -604,7 +603,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT
else
#endif
{
- LogConnectFailure(manual_connection, "connect() to %s failed: %s", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
+ LogConnectFailure(manual_connection, "connect() to %s failed: %s", addrConnect.ToStringAddrPort(), NetworkErrorString(WSAGetLastError()));
return false;
}
}
@@ -717,21 +716,6 @@ bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out)
return false;
}
-bool SetSocketNonBlocking(const SOCKET& hSocket)
-{
-#ifdef WIN32
- u_long nOne = 1;
- if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
-#else
- int fFlags = fcntl(hSocket, F_GETFL, 0);
- if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
-#endif
- return false;
- }
-
- return true;
-}
-
void InterruptSocks5(bool interrupt)
{
interruptSocks5Recv = interrupt;
diff --git a/src/netbase.h b/src/netbase.h
index fadc8b418e..a43f22f240 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -221,8 +221,6 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT
*/
bool ConnectThroughProxy(const Proxy& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed);
-/** Enable non-blocking mode for a socket */
-bool SetSocketNonBlocking(const SOCKET& hSocket);
void InterruptSocks5(bool interrupt);
/**
diff --git a/src/netgroup.cpp b/src/netgroup.cpp
index 96b5e29684..87a1c4e036 100644
--- a/src/netgroup.cpp
+++ b/src/netgroup.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/node/blockmanager_args.cpp b/src/node/blockmanager_args.cpp
new file mode 100644
index 0000000000..5fb5c8beed
--- /dev/null
+++ b/src/node/blockmanager_args.cpp
@@ -0,0 +1,30 @@
+// Copyright (c) 2023 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 <node/blockmanager_args.h>
+
+#include <util/system.h>
+#include <validation.h>
+
+namespace node {
+std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Options& opts)
+{
+ // block pruning; get the amount of disk space (in MiB) to allot for block & undo files
+ int64_t nPruneArg{args.GetIntArg("-prune", opts.prune_target)};
+ if (nPruneArg < 0) {
+ return _("Prune cannot be configured with a negative value.");
+ }
+ uint64_t nPruneTarget{uint64_t(nPruneArg) * 1024 * 1024};
+ if (nPruneArg == 1) { // manual pruning: -prune=1
+ nPruneTarget = BlockManager::PRUNE_TARGET_MANUAL;
+ } else if (nPruneTarget) {
+ if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
+ return strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024);
+ }
+ }
+ opts.prune_target = nPruneTarget;
+
+ return std::nullopt;
+}
+} // namespace node
diff --git a/src/node/blockmanager_args.h b/src/node/blockmanager_args.h
new file mode 100644
index 0000000000..e657c6bb45
--- /dev/null
+++ b/src/node/blockmanager_args.h
@@ -0,0 +1,20 @@
+
+// Copyright (c) 2023 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_NODE_BLOCKMANAGER_ARGS_H
+#define BITCOIN_NODE_BLOCKMANAGER_ARGS_H
+
+#include <node/blockstorage.h>
+
+#include <optional>
+
+class ArgsManager;
+struct bilingual_str;
+
+namespace node {
+std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Options& opts);
+} // namespace node
+
+#endif // BITCOIN_NODE_BLOCKMANAGER_ARGS_H
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 57f81e6bb6..53721b807c 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -1,16 +1,17 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 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 <node/blockstorage.h>
#include <chain.h>
-#include <chainparams.h>
#include <clientversion.h>
#include <consensus/validation.h>
#include <flatfile.h>
#include <fs.h>
#include <hash.h>
+#include <logging.h>
+#include <kernel/chainparams.h>
#include <pow.h>
#include <reverse_iterator.h>
#include <shutdown.h>
@@ -25,10 +26,7 @@
#include <unordered_map>
namespace node {
-std::atomic_bool fImporting(false);
std::atomic_bool fReindex(false);
-bool fPruneMode = false;
-uint64_t nPruneTarget = 0;
bool CBlockIndexWorkComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
{
@@ -153,7 +151,7 @@ void BlockManager::PruneOneBlockFile(const int fileNumber)
void BlockManager::FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height)
{
- assert(fPruneMode && nManualPruneHeight > 0);
+ assert(IsPruneMode() && nManualPruneHeight > 0);
LOCK2(cs_main, cs_LastBlockFile);
if (chain_tip_height < 0) {
@@ -177,7 +175,7 @@ void BlockManager::FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nM
void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd)
{
LOCK2(cs_main, cs_LastBlockFile);
- if (chain_tip_height < 0 || nPruneTarget == 0) {
+ if (chain_tip_height < 0 || GetPruneTarget() == 0) {
return;
}
if ((uint64_t)chain_tip_height <= nPruneAfterHeight) {
@@ -193,14 +191,14 @@ void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPr
uint64_t nBytesToPrune;
int count = 0;
- if (nCurrentUsage + nBuffer >= nPruneTarget) {
+ if (nCurrentUsage + nBuffer >= GetPruneTarget()) {
// On a prune event, the chainstate DB is flushed.
// To avoid excessive prune events negating the benefit of high dbcache
// values, we should not prune too rapidly.
// So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
if (is_ibd) {
// Since this is only relevant during IBD, we use a fixed 10%
- nBuffer += nPruneTarget / 10;
+ nBuffer += GetPruneTarget() / 10;
}
for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) {
@@ -210,7 +208,7 @@ void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPr
continue;
}
- if (nCurrentUsage + nBuffer < nPruneTarget) { // are we below our target?
+ if (nCurrentUsage + nBuffer < GetPruneTarget()) { // are we below our target?
break;
}
@@ -228,9 +226,9 @@ void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPr
}
LogPrint(BCLog::PRUNE, "target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n",
- nPruneTarget/1024/1024, nCurrentUsage/1024/1024,
- ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024,
- nLastBlockWeCanPrune, count);
+ GetPruneTarget() / 1024 / 1024, nCurrentUsage / 1024 / 1024,
+ (int64_t(GetPruneTarget()) - int64_t(nCurrentUsage)) / 1024 / 1024,
+ nLastBlockWeCanPrune, count);
}
void BlockManager::UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) {
@@ -352,7 +350,7 @@ bool BlockManager::LoadBlockIndexDB(const Consensus::Params& consensus_params)
}
for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) {
FlatFilePos pos(*it, 0);
- if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) {
+ if (AutoFile{OpenBlockFile(pos, true)}.IsNull()) {
return false;
}
}
@@ -371,6 +369,23 @@ bool BlockManager::LoadBlockIndexDB(const Consensus::Params& consensus_params)
return true;
}
+void BlockManager::ScanAndUnlinkAlreadyPrunedFiles()
+{
+ AssertLockHeld(::cs_main);
+ if (!m_have_pruned) {
+ return;
+ }
+
+ std::set<int> block_files_to_prune;
+ for (int file_number = 0; file_number < m_last_blockfile; file_number++) {
+ if (m_blockfile_info[file_number].nSize == 0) {
+ block_files_to_prune.insert(file_number);
+ }
+ }
+
+ UnlinkPrunedFiles(block_files_to_prune);
+}
+
const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
{
const MapCheckpoints& checkpoints = data.mapCheckpoints;
@@ -454,13 +469,13 @@ CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n)
static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
- CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
+ AutoFile fileout{OpenUndoFile(pos)};
if (fileout.IsNull()) {
return error("%s: OpenUndoFile failed", __func__);
}
// Write index header
- unsigned int nSize = GetSerializeSize(blockundo, fileout.GetVersion());
+ unsigned int nSize = GetSerializeSize(blockundo, CLIENT_VERSION);
fileout << messageStart << nSize;
// Write undo data
@@ -489,14 +504,14 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex)
}
// Open history file to read
- CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
+ AutoFile filein{OpenUndoFile(pos, true)};
if (filein.IsNull()) {
return error("%s: OpenUndoFile failed", __func__);
}
// Read block
uint256 hashChecksum;
- CHashVerifier<CAutoFile> verifier(&filein); // We need a CHashVerifier as reserializing may lose data
+ HashVerifier verifier{filein}; // Use HashVerifier as reserializing may lose data, c.f. commit d342424301013ec47dc146a4beb49d5c9319d80a
try {
verifier << pindex->pprev->GetBlockHash();
verifier >> blockundo;
@@ -524,6 +539,16 @@ void BlockManager::FlushUndoFile(int block_file, bool finalize)
void BlockManager::FlushBlockFile(bool fFinalize, bool finalize_undo)
{
LOCK(cs_LastBlockFile);
+
+ if (m_blockfile_info.size() < 1) {
+ // Return if we haven't loaded any blockfiles yet. This happens during
+ // chainstate init, when we call ChainstateManager::MaybeRebalanceCaches() (which
+ // then calls FlushStateToDisk()), resulting in a call to this function before we
+ // have populated `m_blockfile_info` via LoadBlockIndexDB().
+ return;
+ }
+ assert(static_cast<int>(m_blockfile_info.size()) > m_last_blockfile);
+
FlatFilePos block_pos_old(m_last_blockfile, m_blockfile_info[m_last_blockfile].nSize);
if (!BlockFileSeq().Flush(block_pos_old, fFinalize)) {
AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error.");
@@ -546,11 +571,14 @@ uint64_t BlockManager::CalculateCurrentUsage()
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
{
+ std::error_code ec;
for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {
FlatFilePos pos(*it, 0);
- fs::remove(BlockFileSeq().FileName(pos));
- fs::remove(UndoFileSeq().FileName(pos));
- LogPrint(BCLog::BLOCKSTORE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
+ const bool removed_blockfile{fs::remove(BlockFileSeq().FileName(pos), ec)};
+ const bool removed_undofile{fs::remove(UndoFileSeq().FileName(pos), ec)};
+ if (removed_blockfile || removed_undofile) {
+ LogPrint(BCLog::BLOCKSTORE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
+ }
}
}
@@ -626,7 +654,7 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
if (out_of_space) {
return AbortNode("Disk space is too low!", _("Disk space is too low!"));
}
- if (bytes_allocated != 0 && fPruneMode) {
+ if (bytes_allocated != 0 && IsPruneMode()) {
m_check_for_pruning = true;
}
}
@@ -650,7 +678,7 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP
if (out_of_space) {
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
}
- if (bytes_allocated != 0 && fPruneMode) {
+ if (bytes_allocated != 0 && IsPruneMode()) {
m_check_for_pruning = true;
}
@@ -758,7 +786,7 @@ bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, c
{
FlatFilePos hpos = pos;
hpos.nPos -= 8; // Seek back 8 bytes for meta header
- CAutoFile filein(OpenBlockFile(hpos, true), SER_DISK, CLIENT_VERSION);
+ AutoFile filein{OpenBlockFile(hpos, true)};
if (filein.IsNull()) {
return error("%s: OpenBlockFile failed for %s", __func__, pos.ToString());
}
@@ -789,19 +817,24 @@ bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, c
return true;
}
-/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp)
{
unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION);
FlatFilePos blockPos;
- if (dbp != nullptr) {
+ const auto position_known {dbp != nullptr};
+ if (position_known) {
blockPos = *dbp;
+ } else {
+ // when known, blockPos.nPos points at the offset of the block data in the blk file. that already accounts for
+ // the serialization header present in the file (the 4 magic message start bytes + the 4 length bytes = 8 bytes = BLOCK_SERIALIZATION_HEADER_SIZE).
+ // we add BLOCK_SERIALIZATION_HEADER_SIZE only for new blocks since they will have the serialization header added when written to disk.
+ nBlockSize += static_cast<unsigned int>(BLOCK_SERIALIZATION_HEADER_SIZE);
}
- if (!FindBlockPos(blockPos, nBlockSize + 8, nHeight, active_chain, block.GetBlockTime(), dbp != nullptr)) {
+ if (!FindBlockPos(blockPos, nBlockSize, nHeight, active_chain, block.GetBlockTime(), position_known)) {
error("%s: FindBlockPos failed", __func__);
return FlatFilePos();
}
- if (dbp == nullptr) {
+ if (!position_known) {
if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) {
AbortNode("Failed to write block");
return FlatFilePos();
@@ -810,17 +843,20 @@ FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CCha
return blockPos;
}
-struct CImportingNow {
- CImportingNow()
+class ImportingNow
+{
+ std::atomic<bool>& m_importing;
+
+public:
+ ImportingNow(std::atomic<bool>& importing) : m_importing{importing}
{
- assert(fImporting == false);
- fImporting = true;
+ assert(m_importing == false);
+ m_importing = true;
}
-
- ~CImportingNow()
+ ~ImportingNow()
{
- assert(fImporting == true);
- fImporting = false;
+ assert(m_importing == true);
+ m_importing = false;
}
};
@@ -830,7 +866,7 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
ScheduleBatchPriority();
{
- CImportingNow imp;
+ ImportingNow imp{chainman.m_blockman.m_importing};
// -reindex
if (fReindex) {
@@ -896,7 +932,7 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
StartShutdown();
return;
}
- } // End scope of CImportingNow
+ } // End scope of ImportingNow
chainman.ActiveChainstate().LoadMempool(mempool_path);
}
} // namespace node
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index 37d74ed102..5ba0045b8b 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,6 +8,8 @@
#include <attributes.h>
#include <chain.h>
#include <fs.h>
+#include <kernel/blockmanager_opts.h>
+#include <kernel/cs_main.h>
#include <protocol.h>
#include <sync.h>
#include <txdb.h>
@@ -17,8 +19,6 @@
#include <unordered_map>
#include <vector>
-extern RecursiveMutex cs_main;
-
class ArgsManager;
class BlockValidationState;
class CBlock;
@@ -44,13 +44,10 @@ static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
-extern std::atomic_bool fImporting;
+/** Size of header written by WriteBlockToDisk before a serialized CBlock */
+static constexpr size_t BLOCK_SERIALIZATION_HEADER_SIZE = CMessageHeader::MESSAGE_START_SIZE + sizeof(unsigned int);
+
extern std::atomic_bool fReindex;
-/** Pruning-related variables and constants */
-/** True if we're running in -prune mode. */
-extern bool fPruneMode;
-/** Number of bytes of block files that we're trying to stay below. */
-extern uint64_t nPruneTarget;
// Because validation code takes pointers to the map's CBlockIndex objects, if
// we ever switch to another associative container, we need to either use a
@@ -125,6 +122,8 @@ private:
*/
bool m_check_for_pruning = false;
+ const bool m_prune_mode;
+
/** Dirty block index entries. */
std::set<CBlockIndex*> m_dirty_blockindex;
@@ -139,7 +138,17 @@ private:
*/
std::unordered_map<std::string, PruneLockInfo> m_prune_locks GUARDED_BY(::cs_main);
+ const kernel::BlockManagerOpts m_opts;
+
public:
+ using Options = kernel::BlockManagerOpts;
+
+ explicit BlockManager(Options opts)
+ : m_prune_mode{opts.prune_target > 0},
+ m_opts{std::move(opts)} {};
+
+ std::atomic<bool> m_importing{false};
+
BlockMap m_block_index GUARDED_BY(cs_main);
std::vector<CBlockIndex*> GetAllBlockIndices() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
@@ -155,6 +164,13 @@ public:
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
bool LoadBlockIndexDB(const Consensus::Params& consensus_params) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ /**
+ * Remove any pruned block & undo files that are still on disk.
+ * This could happen on some systems if the file was still being read while unlinked,
+ * or if we crash before unlinking.
+ */
+ void ScanAndUnlinkAlreadyPrunedFiles() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Create a new block index entry for a given block hash */
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -171,8 +187,18 @@ public:
bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ /** Store block on disk. If dbp is not nullptr, then it provides the known position of the block within a block file on disk. */
FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp);
+ /** Whether running in -prune mode. */
+ [[nodiscard]] bool IsPruneMode() const { return m_prune_mode; }
+
+ /** Attempt to stay below this number of bytes of block files. */
+ [[nodiscard]] uint64_t GetPruneTarget() const { return m_opts.prune_target; }
+ static constexpr auto PRUNE_TARGET_MANUAL{std::numeric_limits<uint64_t>::max()};
+
+ [[nodiscard]] bool LoadingBlocks() const { return m_importing || fReindex; }
+
/** Calculate the amount of disk space the block & undo files currently use */
uint64_t CalculateCurrentUsage();
diff --git a/src/node/caches.cpp b/src/node/caches.cpp
index a39ad7aeb6..7622a03e19 100644
--- a/src/node/caches.cpp
+++ b/src/node/caches.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index 3f1d6dd743..cfd3472592 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -1,12 +1,14 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 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 <node/chainstate.h>
+#include <arith_uint256.h>
#include <chain.h>
#include <coins.h>
#include <consensus/params.h>
+#include <logging.h>
#include <node/blockstorage.h>
#include <node/caches.h>
#include <sync.h>
@@ -21,42 +23,28 @@
#include <algorithm>
#include <atomic>
#include <cassert>
+#include <limits>
#include <memory>
#include <vector>
namespace node {
-ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,
- const ChainstateLoadOptions& options)
+// Complete initialization of chainstates after the initial call has been made
+// to ChainstateManager::InitializeChainstate().
+static ChainstateLoadResult CompleteChainstateInitialization(
+ ChainstateManager& chainman,
+ const CacheSizes& cache_sizes,
+ const ChainstateLoadOptions& options) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
- auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
- return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
- };
-
- if (!hashAssumeValid.IsNull()) {
- LogPrintf("Assuming ancestors of block %s have valid signatures.\n", hashAssumeValid.GetHex());
- } else {
- LogPrintf("Validating signatures for all blocks.\n");
- }
- LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex());
- if (nMinimumChainWork < UintToArith256(chainman.GetConsensus().nMinimumChainWork)) {
- LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainman.GetConsensus().nMinimumChainWork.GetHex());
- }
- if (nPruneTarget == std::numeric_limits<uint64_t>::max()) {
- LogPrintf("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.\n");
- } else if (nPruneTarget) {
- LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
- }
-
- LOCK(cs_main);
- chainman.InitializeChainstate(options.mempool);
- chainman.m_total_coinstip_cache = cache_sizes.coins;
- chainman.m_total_coinsdb_cache = cache_sizes.coins_db;
-
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
pblocktree.reset();
- pblocktree.reset(new CBlockTreeDB(cache_sizes.block_tree_db, options.block_tree_db_in_memory, options.reindex));
+ pblocktree = std::make_unique<CBlockTreeDB>(DBParams{
+ .path = chainman.m_options.datadir / "blocks" / "index",
+ .cache_bytes = static_cast<size_t>(cache_sizes.block_tree_db),
+ .memory_only = options.block_tree_db_in_memory,
+ .wipe_data = options.reindex,
+ .options = chainman.m_options.block_tree_db});
if (options.reindex) {
pblocktree->WriteReindexing(true);
@@ -98,12 +86,27 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")};
}
+ auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
+ return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
+ };
+
+ assert(chainman.m_total_coinstip_cache > 0);
+ assert(chainman.m_total_coinsdb_cache > 0);
+
+ // Conservative value which is arbitrarily chosen, as it will ultimately be changed
+ // by a call to `chainman.MaybeRebalanceCaches()`. We just need to make sure
+ // that the sum of the two caches (40%) does not exceed the allowable amount
+ // during this temporary initialization state.
+ double init_cache_fraction = 0.2;
+
// At this point we're either in reindex or we've loaded a useful
// block tree into BlockIndex()!
for (Chainstate* chainstate : chainman.GetAll()) {
+ LogPrintf("Initializing chainstate %s\n", chainstate->ToString());
+
chainstate->InitCoinsDB(
- /*cache_size_bytes=*/cache_sizes.coins_db,
+ /*cache_size_bytes=*/chainman.m_total_coinsdb_cache * init_cache_fraction,
/*in_memory=*/options.coins_db_in_memory,
/*should_wipe=*/options.reindex || options.reindex_chainstate);
@@ -125,7 +128,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
}
// The on-disk coinsdb is now in a good state, create the cache
- chainstate->InitCoinsCache(cache_sizes.coins);
+ chainstate->InitCoinsCache(chainman.m_total_coinstip_cache * init_cache_fraction);
assert(chainstate->CanFlushToDisk());
if (!is_coinsview_empty(chainstate)) {
@@ -146,6 +149,89 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
};
}
+ // Now that chainstates are loaded and we're able to flush to
+ // disk, rebalance the coins caches to desired levels based
+ // on the condition of each chainstate.
+ chainman.MaybeRebalanceCaches();
+
+ return {ChainstateLoadStatus::SUCCESS, {}};
+}
+
+ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,
+ const ChainstateLoadOptions& options)
+{
+ if (!chainman.AssumedValidBlock().IsNull()) {
+ LogPrintf("Assuming ancestors of block %s have valid signatures.\n", chainman.AssumedValidBlock().GetHex());
+ } else {
+ LogPrintf("Validating signatures for all blocks.\n");
+ }
+ LogPrintf("Setting nMinimumChainWork=%s\n", chainman.MinimumChainWork().GetHex());
+ if (chainman.MinimumChainWork() < UintToArith256(chainman.GetConsensus().nMinimumChainWork)) {
+ LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainman.GetConsensus().nMinimumChainWork.GetHex());
+ }
+ if (chainman.m_blockman.GetPruneTarget() == BlockManager::PRUNE_TARGET_MANUAL) {
+ LogPrintf("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.\n");
+ } else if (chainman.m_blockman.GetPruneTarget()) {
+ LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", chainman.m_blockman.GetPruneTarget() / 1024 / 1024);
+ }
+
+ LOCK(cs_main);
+
+ chainman.m_total_coinstip_cache = cache_sizes.coins;
+ chainman.m_total_coinsdb_cache = cache_sizes.coins_db;
+
+ // Load the fully validated chainstate.
+ chainman.InitializeChainstate(options.mempool);
+
+ // Load a chain created from a UTXO snapshot, if any exist.
+ chainman.DetectSnapshotChainstate(options.mempool);
+
+ auto [init_status, init_error] = CompleteChainstateInitialization(chainman, cache_sizes, options);
+ if (init_status != ChainstateLoadStatus::SUCCESS) {
+ return {init_status, init_error};
+ }
+
+ // If a snapshot chainstate was fully validated by a background chainstate during
+ // the last run, detect it here and clean up the now-unneeded background
+ // chainstate.
+ //
+ // Why is this cleanup done here (on subsequent restart) and not just when the
+ // snapshot is actually validated? Because this entails unusual
+ // filesystem operations to move leveldb data directories around, and that seems
+ // too risky to do in the middle of normal runtime.
+ auto snapshot_completion = chainman.MaybeCompleteSnapshotValidation();
+
+ if (snapshot_completion == SnapshotCompletionResult::SKIPPED) {
+ // do nothing; expected case
+ } else if (snapshot_completion == SnapshotCompletionResult::SUCCESS) {
+ LogPrintf("[snapshot] cleaning up unneeded background chainstate, then reinitializing\n");
+ if (!chainman.ValidatedSnapshotCleanup()) {
+ AbortNode("Background chainstate cleanup failed unexpectedly.");
+ }
+
+ // Because ValidatedSnapshotCleanup() has torn down chainstates with
+ // ChainstateManager::ResetChainstates(), reinitialize them here without
+ // duplicating the blockindex work above.
+ assert(chainman.GetAll().empty());
+ assert(!chainman.IsSnapshotActive());
+ assert(!chainman.IsSnapshotValidated());
+
+ chainman.InitializeChainstate(options.mempool);
+
+ // A reload of the block index is required to recompute setBlockIndexCandidates
+ // for the fully validated chainstate.
+ chainman.ActiveChainstate().UnloadBlockIndex();
+
+ auto [init_status, init_error] = CompleteChainstateInitialization(chainman, cache_sizes, options);
+ if (init_status != ChainstateLoadStatus::SUCCESS) {
+ return {init_status, init_error};
+ }
+ } else {
+ return {ChainstateLoadStatus::FAILURE, _(
+ "UTXO snapshot failed to validate. "
+ "Restart to resume normal initial block download, or try loading a different snapshot.")};
+ }
+
return {ChainstateLoadStatus::SUCCESS, {}};
}
@@ -166,12 +252,24 @@ ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const C
"Only rebuild the block database if you are sure that your computer's date and time are correct")};
}
- if (!CVerifyDB().VerifyDB(
- *chainstate, chainman.GetConsensus(), chainstate->CoinsDB(),
- options.check_level,
- options.check_blocks)) {
+ VerifyDBResult result = CVerifyDB().VerifyDB(
+ *chainstate, chainman.GetConsensus(), chainstate->CoinsDB(),
+ options.check_level,
+ options.check_blocks);
+ switch (result) {
+ case VerifyDBResult::SUCCESS:
+ case VerifyDBResult::SKIPPED_MISSING_BLOCKS:
+ break;
+ case VerifyDBResult::INTERRUPTED:
+ return {ChainstateLoadStatus::INTERRUPTED, _("Block verification was interrupted")};
+ case VerifyDBResult::CORRUPTED_BLOCK_DB:
return {ChainstateLoadStatus::FAILURE, _("Corrupted block database detected")};
- }
+ case VerifyDBResult::SKIPPED_L3_CHECKS:
+ if (options.require_full_verification) {
+ return {ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE, _("Insufficient dbcache for block verification")};
+ }
+ break;
+ } // no default case, so the compiler can warn about missing cases
}
}
diff --git a/src/node/chainstate.h b/src/node/chainstate.h
index 2289310ece..77240cafe9 100644
--- a/src/node/chainstate.h
+++ b/src/node/chainstate.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -25,6 +25,11 @@ struct ChainstateLoadOptions {
bool reindex{false};
bool reindex_chainstate{false};
bool prune{false};
+ //! Setting require_full_verification to true will require all checks at
+ //! check_level (below) to succeed for loading to succeed. Setting it to
+ //! false will skip checks if cache is not big enough to run them, so may be
+ //! helpful for running with a small cache.
+ bool require_full_verification{true};
int64_t check_blocks{DEFAULT_CHECKBLOCKS};
int64_t check_level{DEFAULT_CHECKLEVEL};
std::function<bool()> check_interrupt;
@@ -35,7 +40,13 @@ struct ChainstateLoadOptions {
//! case, and treat other cases as errors. More complex applications may want to
//! try reindexing in the generic failure case, and pass an interrupt callback
//! and exit cleanly in the interrupted case.
-enum class ChainstateLoadStatus { SUCCESS, FAILURE, FAILURE_INCOMPATIBLE_DB, INTERRUPTED };
+enum class ChainstateLoadStatus {
+ SUCCESS,
+ FAILURE,
+ FAILURE_INCOMPATIBLE_DB,
+ FAILURE_INSUFFICIENT_DBCACHE,
+ INTERRUPTED,
+};
//! Chainstate load status code and optional error string.
using ChainstateLoadResult = std::tuple<ChainstateLoadStatus, bilingual_str>;
diff --git a/src/node/chainstatemanager_args.cpp b/src/node/chainstatemanager_args.cpp
new file mode 100644
index 0000000000..9801e6e959
--- /dev/null
+++ b/src/node/chainstatemanager_args.cpp
@@ -0,0 +1,46 @@
+// Copyright (c) 2022 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 <node/chainstatemanager_args.h>
+
+#include <arith_uint256.h>
+#include <kernel/chainstatemanager_opts.h>
+#include <node/coins_view_args.h>
+#include <node/database_args.h>
+#include <tinyformat.h>
+#include <uint256.h>
+#include <util/strencodings.h>
+#include <util/system.h>
+#include <util/translation.h>
+#include <validation.h>
+
+#include <chrono>
+#include <optional>
+#include <string>
+
+namespace node {
+std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts)
+{
+ if (auto value{args.GetBoolArg("-checkblockindex")}) opts.check_block_index = *value;
+
+ if (auto value{args.GetBoolArg("-checkpoints")}) opts.checkpoints_enabled = *value;
+
+ if (auto value{args.GetArg("-minimumchainwork")}) {
+ if (!IsHexNumber(*value)) {
+ return strprintf(Untranslated("Invalid non-hex (%s) minimum chain work value specified"), *value);
+ }
+ opts.minimum_chain_work = UintToArith256(uint256S(*value));
+ }
+
+ if (auto value{args.GetArg("-assumevalid")}) opts.assumed_valid_block = uint256S(*value);
+
+ if (auto value{args.GetIntArg("-maxtipage")}) opts.max_tip_age = std::chrono::seconds{*value};
+
+ ReadDatabaseArgs(args, opts.block_tree_db);
+ ReadDatabaseArgs(args, opts.coins_db);
+ ReadCoinsViewArgs(args, opts.coins_view);
+
+ return std::nullopt;
+}
+} // namespace node
diff --git a/src/node/chainstatemanager_args.h b/src/node/chainstatemanager_args.h
new file mode 100644
index 0000000000..6c46b998f2
--- /dev/null
+++ b/src/node/chainstatemanager_args.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2022 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_NODE_CHAINSTATEMANAGER_ARGS_H
+#define BITCOIN_NODE_CHAINSTATEMANAGER_ARGS_H
+
+#include <validation.h>
+
+#include <optional>
+
+class ArgsManager;
+struct bilingual_str;
+
+namespace node {
+std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts);
+} // namespace node
+
+#endif // BITCOIN_NODE_CHAINSTATEMANAGER_ARGS_H
diff --git a/src/node/coin.h b/src/node/coin.h
index 3d534463e8..b32e410e1c 100644
--- a/src/node/coin.h
+++ b/src/node/coin.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/node/coins_view_args.cpp b/src/node/coins_view_args.cpp
new file mode 100644
index 0000000000..67c9b8dbac
--- /dev/null
+++ b/src/node/coins_view_args.cpp
@@ -0,0 +1,16 @@
+// Copyright (c) 2022 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 <node/coins_view_args.h>
+
+#include <txdb.h>
+#include <util/system.h>
+
+namespace node {
+void ReadCoinsViewArgs(const ArgsManager& args, CoinsViewOptions& options)
+{
+ if (auto value = args.GetIntArg("-dbbatchsize")) options.batch_write_bytes = *value;
+ if (auto value = args.GetIntArg("-dbcrashratio")) options.simulate_crash_ratio = *value;
+}
+} // namespace node
diff --git a/src/node/coins_view_args.h b/src/node/coins_view_args.h
new file mode 100644
index 0000000000..71a7a671fd
--- /dev/null
+++ b/src/node/coins_view_args.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2022 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_NODE_COINS_VIEW_ARGS_H
+#define BITCOIN_NODE_COINS_VIEW_ARGS_H
+
+class ArgsManager;
+struct CoinsViewOptions;
+
+namespace node {
+void ReadCoinsViewArgs(const ArgsManager& args, CoinsViewOptions& options);
+} // namespace node
+
+#endif // BITCOIN_NODE_COINS_VIEW_ARGS_H
diff --git a/src/node/context.cpp b/src/node/context.cpp
index d80b8ca7a7..af59ab932b 100644
--- a/src/node/context.cpp
+++ b/src/node/context.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/node/context.h b/src/node/context.h
index 31be308787..84f4053c84 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/node/database_args.cpp b/src/node/database_args.cpp
new file mode 100644
index 0000000000..2c53b4b47e
--- /dev/null
+++ b/src/node/database_args.cpp
@@ -0,0 +1,18 @@
+// Copyright (c) 2022 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 <node/database_args.h>
+
+#include <dbwrapper.h>
+#include <util/system.h>
+
+namespace node {
+void ReadDatabaseArgs(const ArgsManager& args, DBOptions& options)
+{
+ // Settings here apply to all databases (chainstate, blocks, and index
+ // databases), but it'd be easy to parse database-specific options by adding
+ // a database_type string or enum parameter to this function.
+ if (auto value = args.GetBoolArg("-forcecompactdb")) options.force_compact = *value;
+}
+} // namespace node
diff --git a/src/node/database_args.h b/src/node/database_args.h
new file mode 100644
index 0000000000..001976f219
--- /dev/null
+++ b/src/node/database_args.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2022 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_NODE_DATABASE_ARGS_H
+#define BITCOIN_NODE_DATABASE_ARGS_H
+
+class ArgsManager;
+struct DBOptions;
+
+namespace node {
+void ReadDatabaseArgs(const ArgsManager& args, DBOptions& options);
+} // namespace node
+
+#endif // BITCOIN_NODE_DATABASE_ARGS_H
diff --git a/src/node/interface_ui.cpp b/src/node/interface_ui.cpp
index fa90d6fda7..9dd1e7d9cf 100644
--- a/src/node/interface_ui.cpp
+++ b/src/node/interface_ui.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2010-2021 The Bitcoin Core developers
+// Copyright (c) 2010-2022 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 <node/interface_ui.h>
+#include <util/string.h>
#include <util/translation.h>
#include <boost/signals2/optional_last_value.hpp>
@@ -62,6 +63,18 @@ bool InitError(const bilingual_str& str)
return false;
}
+bool InitError(const bilingual_str& str, const std::vector<std::string>& details)
+{
+ // For now just flatten the list of error details into a string to pass to
+ // the base InitError overload. In the future, if more init code provides
+ // error details, the details could be passed separately from the main
+ // message for rich display in the GUI. But currently the only init
+ // functions which provide error details are ones that run during early init
+ // before the GUI uiInterface is registered, so there's no point passing
+ // main messages and details separately to uiInterface yet.
+ return InitError(details.empty() ? str : strprintf(Untranslated("%s:\n%s"), str, MakeUnorderedList(details)));
+}
+
void InitWarning(const bilingual_str& str)
{
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING);
diff --git a/src/node/interface_ui.h b/src/node/interface_ui.h
index 316d75167e..22c241cb78 100644
--- a/src/node/interface_ui.h
+++ b/src/node/interface_ui.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -116,7 +116,7 @@ void InitWarning(const bilingual_str& str);
/** Show error message **/
bool InitError(const bilingual_str& str);
-constexpr auto AbortError = InitError;
+bool InitError(const bilingual_str& str, const std::vector<std::string>& details);
extern CClientUIInterface uiInterface;
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index aa7ddec770..b397661df4 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -1,29 +1,32 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 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 <addrdb.h>
#include <banman.h>
+#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
#include <deploymentstatus.h>
#include <external_signer.h>
+#include <index/blockfilterindex.h>
#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
+#include <kernel/chain.h>
+#include <kernel/mempool_entry.h>
#include <mapport.h>
#include <net.h>
#include <net_processing.h>
#include <netaddress.h>
#include <netbase.h>
#include <node/blockstorage.h>
-#include <kernel/chain.h>
#include <node/coin.h>
#include <node/context.h>
-#include <node/transaction.h>
#include <node/interface_ui.h>
+#include <node/transaction.h>
#include <policy/feerate.h>
#include <policy/fees.h>
#include <policy/policy.h>
@@ -61,7 +64,7 @@ using interfaces::BlockTip;
using interfaces::Chain;
using interfaces::FoundBlock;
using interfaces::Handler;
-using interfaces::MakeHandler;
+using interfaces::MakeSignalHandler;
using interfaces::Node;
using interfaces::WalletLoader;
@@ -83,14 +86,14 @@ class NodeImpl : public Node
{
public:
explicit NodeImpl(NodeContext& context) { setContext(&context); }
- void initLogging() override { InitLogging(*Assert(m_context->args)); }
- void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); }
+ void initLogging() override { InitLogging(args()); }
+ void initParameterInteraction() override { InitParameterInteraction(args()); }
bilingual_str getWarnings() override { return GetWarnings(true); }
uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
bool baseInitialize() override
{
- if (!AppInitBasicSetup(gArgs)) return false;
- if (!AppInitParameterInteraction(gArgs, /*use_syscall_sandbox=*/false)) return false;
+ if (!AppInitBasicSetup(args())) return false;
+ if (!AppInitParameterInteraction(args(), /*use_syscall_sandbox=*/false)) return false;
m_context->kernel = std::make_unique<kernel::Context>();
if (!AppInitSanityChecks(*m_context->kernel)) return false;
@@ -113,7 +116,7 @@ public:
{
StartShutdown();
// Stop RPC for clean shutdown if any of waitfor* commands is executed.
- if (gArgs.GetBoolArg("-server", false)) {
+ if (args().GetBoolArg("-server", false)) {
InterruptRPC();
StopRPC();
}
@@ -122,28 +125,28 @@ public:
bool isSettingIgnored(const std::string& name) override
{
bool ignored = false;
- gArgs.LockSettings([&](util::Settings& settings) {
+ args().LockSettings([&](util::Settings& settings) {
if (auto* options = util::FindKey(settings.command_line_options, name)) {
ignored = !options->empty();
}
});
return ignored;
}
- util::SettingsValue getPersistentSetting(const std::string& name) override { return gArgs.GetPersistentSetting(name); }
+ util::SettingsValue getPersistentSetting(const std::string& name) override { return args().GetPersistentSetting(name); }
void updateRwSetting(const std::string& name, const util::SettingsValue& value) override
{
- gArgs.LockSettings([&](util::Settings& settings) {
+ args().LockSettings([&](util::Settings& settings) {
if (value.isNull()) {
settings.rw_settings.erase(name);
} else {
settings.rw_settings[name] = value;
}
});
- gArgs.WriteSettingsFile();
+ args().WriteSettingsFile();
}
void forceSetting(const std::string& name, const util::SettingsValue& value) override
{
- gArgs.LockSettings([&](util::Settings& settings) {
+ args().LockSettings([&](util::Settings& settings) {
if (value.isNull()) {
settings.forced_settings.erase(name);
} else {
@@ -153,11 +156,11 @@ public:
}
void resetSettings() override
{
- gArgs.WriteSettingsFile(/*errors=*/nullptr, /*backup=*/true);
- gArgs.LockSettings([&](util::Settings& settings) {
+ args().WriteSettingsFile(/*errors=*/nullptr, /*backup=*/true);
+ args().LockSettings([&](util::Settings& settings) {
settings.rw_settings.clear();
});
- gArgs.WriteSettingsFile();
+ args().WriteSettingsFile();
}
void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); }
bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); }
@@ -234,7 +237,7 @@ public:
{
#ifdef ENABLE_EXTERNAL_SIGNER
std::vector<ExternalSigner> signers = {};
- const std::string command = gArgs.GetArg("-signer", "");
+ const std::string command = args().GetArg("-signer", "");
if (command == "") return {};
ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
std::vector<std::unique_ptr<interfaces::ExternalSigner>> result;
@@ -292,8 +295,7 @@ public:
bool isInitialBlockDownload() override {
return chainman().ActiveChainstate().IsInitialBlockDownload();
}
- bool getReindex() override { return node::fReindex; }
- bool getImporting() override { return node::fImporting; }
+ bool isLoadingBlocks() override { return chainman().m_blockman.LoadingBlocks(); }
void setNetworkActive(bool active) override
{
if (m_context->connman) {
@@ -333,50 +335,50 @@ public:
}
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
{
- return MakeHandler(::uiInterface.InitMessage_connect(fn));
+ return MakeSignalHandler(::uiInterface.InitMessage_connect(fn));
}
std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override
{
- return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn));
+ return MakeSignalHandler(::uiInterface.ThreadSafeMessageBox_connect(fn));
}
std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override
{
- return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn));
+ return MakeSignalHandler(::uiInterface.ThreadSafeQuestion_connect(fn));
}
std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
{
- return MakeHandler(::uiInterface.ShowProgress_connect(fn));
+ return MakeSignalHandler(::uiInterface.ShowProgress_connect(fn));
}
std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) override
{
- return MakeHandler(::uiInterface.InitWallet_connect(fn));
+ return MakeSignalHandler(::uiInterface.InitWallet_connect(fn));
}
std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override
{
- return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn));
+ return MakeSignalHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn));
}
std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override
{
- return MakeHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn));
+ return MakeSignalHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn));
}
std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override
{
- return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn));
+ return MakeSignalHandler(::uiInterface.NotifyAlertChanged_connect(fn));
}
std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override
{
- return MakeHandler(::uiInterface.BannedListChanged_connect(fn));
+ return MakeSignalHandler(::uiInterface.BannedListChanged_connect(fn));
}
std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
{
- return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
+ return MakeSignalHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
GuessVerificationProgress(Params().TxData(), block));
}));
}
std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
{
- return MakeHandler(
+ return MakeSignalHandler(
::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, int64_t height, int64_t timestamp, bool presync) {
fn(sync_state, BlockTip{(int)height, timestamp, uint256{}}, presync);
}));
@@ -386,6 +388,7 @@ public:
{
m_context = context;
}
+ ArgsManager& args() { return *Assert(Assert(m_context)->args); }
ChainstateManager& chainman() { return *Assert(m_context->chainman); }
NodeContext* m_context{nullptr};
};
@@ -417,11 +420,11 @@ public:
virtual ~NotificationsProxy() = default;
void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override
{
- m_notifications->transactionAddedToMempool(tx, mempool_sequence);
+ m_notifications->transactionAddedToMempool(tx);
}
void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override
{
- m_notifications->transactionRemovedFromMempool(tx, reason, mempool_sequence);
+ m_notifications->transactionRemovedFromMempool(tx, reason);
}
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
{
@@ -536,6 +539,20 @@ public:
}
return std::nullopt;
}
+ bool hasBlockFilterIndex(BlockFilterType filter_type) override
+ {
+ return GetBlockFilterIndex(filter_type) != nullptr;
+ }
+ std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const GCSFilter::ElementSet& filter_set) override
+ {
+ const BlockFilterIndex* block_filter_index{GetBlockFilterIndex(filter_type)};
+ if (!block_filter_index) return std::nullopt;
+
+ BlockFilter filter;
+ const CBlockIndex* index{WITH_LOCK(::cs_main, return chainman().m_blockman.LookupBlockIndex(block_hash))};
+ if (index == nullptr || !block_filter_index->LookupFilter(index, filter)) return std::nullopt;
+ return filter.GetFilter().MatchAny(filter_set);
+ }
bool findBlock(const uint256& hash, const FoundBlock& block) override
{
WAIT_LOCK(cs_main, lock);
@@ -655,13 +672,9 @@ public:
if (!m_node.mempool) return true;
LockPoints lp;
CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
- CTxMemPool::setEntries ancestors;
const CTxMemPool::Limits& limits{m_node.mempool->m_limits};
- std::string unused_error_string;
LOCK(m_node.mempool->cs);
- return m_node.mempool->CalculateMemPoolAncestors(
- entry, ancestors, limits.ancestor_count, limits.ancestor_size_vbytes,
- limits.descendant_count, limits.descendant_size_vbytes, unused_error_string);
+ return m_node.mempool->CalculateMemPoolAncestors(entry, limits).has_value();
}
CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
{
@@ -698,8 +711,9 @@ public:
LOCK(::cs_main);
return chainman().m_blockman.m_have_pruned;
}
- bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
- bool isInitialBlockDownload() override {
+ bool isReadyToBroadcast() override { return !chainman().m_blockman.LoadingBlocks() && !isInitialBlockDownload(); }
+ bool isInitialBlockDownload() override
+ {
return chainman().ActiveChainstate().IsInitialBlockDownload();
}
bool shutdownRequested() override { return ShutdownRequested(); }
@@ -731,16 +745,16 @@ public:
int rpcSerializationFlags() override { return RPCSerializationFlags(); }
util::SettingsValue getSetting(const std::string& name) override
{
- return gArgs.GetSetting(name);
+ return args().GetSetting(name);
}
std::vector<util::SettingsValue> getSettingsList(const std::string& name) override
{
- return gArgs.GetSettingsList(name);
+ return args().GetSettingsList(name);
}
util::SettingsValue getRwSetting(const std::string& name) override
{
util::SettingsValue result;
- gArgs.LockSettings([&](const util::Settings& settings) {
+ args().LockSettings([&](const util::Settings& settings) {
if (const util::SettingsValue* value = util::FindKey(settings.rw_settings, name)) {
result = *value;
}
@@ -749,21 +763,21 @@ public:
}
bool updateRwSetting(const std::string& name, const util::SettingsValue& value, bool write) override
{
- gArgs.LockSettings([&](util::Settings& settings) {
+ args().LockSettings([&](util::Settings& settings) {
if (value.isNull()) {
settings.rw_settings.erase(name);
} else {
settings.rw_settings[name] = value;
}
});
- return !write || gArgs.WriteSettingsFile();
+ return !write || args().WriteSettingsFile();
}
void requestMempoolTransactions(Notifications& notifications) override
{
if (!m_node.mempool) return;
LOCK2(::cs_main, m_node.mempool->cs);
for (const CTxMemPoolEntry& entry : m_node.mempool->mapTx) {
- notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */);
+ notifications.transactionAddedToMempool(entry.GetSharedTx());
}
}
bool hasAssumedValidChain() override
@@ -772,6 +786,7 @@ public:
}
NodeContext* context() override { return &m_node; }
+ ArgsManager& args() { return *Assert(m_node.args); }
ChainstateManager& chainman() { return *Assert(m_node.chainman); }
NodeContext& m_node;
};
diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp
index 8c929e5e0d..a0a2e43107 100644
--- a/src/node/mempool_args.cpp
+++ b/src/node/mempool_args.cpp
@@ -7,8 +7,8 @@
#include <kernel/mempool_limits.h>
#include <kernel/mempool_options.h>
-#include <chainparams.h>
#include <consensus/amount.h>
+#include <kernel/chainparams.h>
#include <logging.h>
#include <policy/feerate.h>
#include <policy/policy.h>
diff --git a/src/node/miner.cpp b/src/node/miner.cpp
index 4536507cd5..c7bc9a9a3d 100644
--- a/src/node/miner.cpp
+++ b/src/node/miner.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -56,39 +56,38 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman)
block.hashMerkleRoot = BlockMerkleRoot(block);
}
-BlockAssembler::Options::Options()
+static BlockAssembler::Options ClampOptions(BlockAssembler::Options options)
{
- blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
- nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
+ // Limit weight to between 4K and DEFAULT_BLOCK_MAX_WEIGHT for sanity:
+ options.nBlockMaxWeight = std::clamp<size_t>(options.nBlockMaxWeight, 4000, DEFAULT_BLOCK_MAX_WEIGHT);
+ return options;
}
BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options)
: chainparams{chainstate.m_chainman.GetParams()},
- m_mempool(mempool),
- m_chainstate(chainstate)
+ m_mempool{mempool},
+ m_chainstate{chainstate},
+ m_options{ClampOptions(options)}
{
- blockMinFeeRate = options.blockMinFeeRate;
- // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
- nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight));
}
-static BlockAssembler::Options DefaultOptions()
+void ApplyArgsManOptions(const ArgsManager& args, BlockAssembler::Options& options)
{
// Block resource limits
- // If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT
- BlockAssembler::Options options;
- options.nBlockMaxWeight = gArgs.GetIntArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
- if (gArgs.IsArgSet("-blockmintxfee")) {
- std::optional<CAmount> parsed = ParseMoney(gArgs.GetArg("-blockmintxfee", ""));
- options.blockMinFeeRate = CFeeRate{parsed.value_or(DEFAULT_BLOCK_MIN_TX_FEE)};
- } else {
- options.blockMinFeeRate = CFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
+ options.nBlockMaxWeight = args.GetIntArg("-blockmaxweight", options.nBlockMaxWeight);
+ if (const auto blockmintxfee{args.GetArg("-blockmintxfee")}) {
+ if (const auto parsed{ParseMoney(*blockmintxfee)}) options.blockMinFeeRate = CFeeRate{*parsed};
}
+}
+static BlockAssembler::Options ConfiguredOptions()
+{
+ BlockAssembler::Options options;
+ ApplyArgsManOptions(gArgs, options);
return options;
}
BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool)
- : BlockAssembler(chainstate, mempool, DefaultOptions()) {}
+ : BlockAssembler(chainstate, mempool, ConfiguredOptions()) {}
void BlockAssembler::resetBlock()
{
@@ -105,7 +104,7 @@ void BlockAssembler::resetBlock()
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
{
- int64_t nTimeStart = GetTimeMicros();
+ const auto time_start{SteadyClock::now()};
resetBlock();
@@ -143,7 +142,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
addPackageTxs(*m_mempool, nPackagesSelected, nDescendantsUpdated);
}
- int64_t nTime1 = GetTimeMicros();
+ const auto time_1{SteadyClock::now()};
m_last_block_num_txs = nBlockTx;
m_last_block_weight = nBlockWeight;
@@ -170,12 +169,16 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
BlockValidationState state;
- if (!TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, GetAdjustedTime, false, false)) {
+ if (m_options.test_block_validity && !TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev,
+ GetAdjustedTime, /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
}
- int64_t nTime2 = GetTimeMicros();
+ const auto time_2{SteadyClock::now()};
- LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart));
+ LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n",
+ Ticks<MillisecondsDouble>(time_1 - time_start), nPackagesSelected, nDescendantsUpdated,
+ Ticks<MillisecondsDouble>(time_2 - time_1),
+ Ticks<MillisecondsDouble>(time_2 - time_start));
return std::move(pblocktemplate);
}
@@ -195,7 +198,7 @@ void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)
bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const
{
// TODO: switch to weight-based accounting for packages instead of vsize-based accounting.
- if (nBlockWeight + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxWeight) {
+ if (nBlockWeight + WITNESS_SCALE_FACTOR * packageSize >= m_options.nBlockMaxWeight) {
return false;
}
if (nBlockSigOpsCost + packageSigOpsCost >= MAX_BLOCK_SIGOPS_COST) {
@@ -367,7 +370,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
packageSigOpsCost = modit->nSigOpCostWithAncestors;
}
- if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
+ if (packageFees < m_options.blockMinFeeRate.GetFee(packageSize)) {
// Everything else we might consider has a lower fee rate
return;
}
@@ -384,17 +387,14 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
++nConsecutiveFailed;
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight >
- nBlockMaxWeight - 4000) {
+ m_options.nBlockMaxWeight - 4000) {
// Give up if we're close to full and haven't succeeded in a while
break;
}
continue;
}
- CTxMemPool::setEntries ancestors;
- uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
- std::string dummy;
- mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
+ auto ancestors{mempool.AssumeCalculateMemPoolAncestors(__func__, *iter, CTxMemPool::Limits::NoLimits(), /*fSearchForParents=*/false)};
onlyUnconfirmed(ancestors);
ancestors.insert(iter);
diff --git a/src/node/miner.h b/src/node/miner.h
index 7269ce1186..f1ccffff55 100644
--- a/src/node/miner.h
+++ b/src/node/miner.h
@@ -1,11 +1,12 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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_NODE_MINER_H
#define BITCOIN_NODE_MINER_H
+#include <policy/policy.h>
#include <primitives/block.h>
#include <txmempool.h>
@@ -16,6 +17,7 @@
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index_container.hpp>
+class ArgsManager;
class ChainstateManager;
class CBlockIndex;
class CChainParams;
@@ -131,10 +133,6 @@ private:
// The constructed block template
std::unique_ptr<CBlockTemplate> pblocktemplate;
- // Configuration parameters for the block size
- unsigned int nBlockMaxWeight;
- CFeeRate blockMinFeeRate;
-
// Information on the current status of the block
uint64_t nBlockWeight;
uint64_t nBlockTx;
@@ -152,9 +150,11 @@ private:
public:
struct Options {
- Options();
- size_t nBlockMaxWeight;
- CFeeRate blockMinFeeRate;
+ // Configuration parameters for the block size
+ size_t nBlockMaxWeight{DEFAULT_BLOCK_MAX_WEIGHT};
+ CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
+ // Whether to call TestBlockValidity() at the end of CreateNewBlock().
+ bool test_block_validity{true};
};
explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool);
@@ -167,6 +167,8 @@ public:
inline static std::optional<int64_t> m_last_block_weight{};
private:
+ const Options m_options;
+
// utility functions
/** Clear the block's state and prepare for assembling a new block */
void resetBlock();
@@ -197,6 +199,9 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);
+
+/** Apply -blockmintxfee and -blockmaxweight options from ArgsManager to BlockAssembler options. */
+void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options);
} // namespace node
#endif // BITCOIN_NODE_MINER_H
diff --git a/src/node/minisketchwrapper.cpp b/src/node/minisketchwrapper.cpp
index 67e823cb68..96707f7a0a 100644
--- a/src/node/minisketchwrapper.cpp
+++ b/src/node/minisketchwrapper.cpp
@@ -23,17 +23,17 @@ static constexpr uint32_t BITS = 32;
uint32_t FindBestImplementation()
{
- std::optional<std::pair<int64_t, uint32_t>> best;
+ std::optional<std::pair<SteadyClock::duration, uint32_t>> best;
uint32_t max_impl = Minisketch::MaxImplementation();
for (uint32_t impl = 0; impl <= max_impl; ++impl) {
- std::vector<int64_t> benches;
+ std::vector<SteadyClock::duration> benches;
uint64_t offset = 0;
/* Run a little benchmark with capacity 32, adding 184 entries, and decoding 11 of them once. */
for (int b = 0; b < 11; ++b) {
if (!Minisketch::ImplementationSupported(BITS, impl)) break;
Minisketch sketch(BITS, impl, 32);
- auto start = GetTimeMicros();
+ auto start = SteadyClock::now();
for (uint64_t e = 0; e < 100; ++e) {
sketch.Add(e*1337 + b*13337 + offset);
}
@@ -41,7 +41,7 @@ uint32_t FindBestImplementation()
sketch.Add(e*1337 + b*13337 + offset);
}
offset += (*sketch.Decode(32))[0];
- auto stop = GetTimeMicros();
+ auto stop = SteadyClock::now();
benches.push_back(stop - start);
}
/* Remember which implementation has the best median benchmark time. */
diff --git a/src/node/psbt.cpp b/src/node/psbt.cpp
index 57162cd679..51e252bffc 100644
--- a/src/node/psbt.cpp
+++ b/src/node/psbt.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -59,7 +59,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
}
// Check if it is final
- if (!utxo.IsNull() && !PSBTInputSigned(input)) {
+ if (!PSBTInputSignedAndVerified(psbtx, i, &txdata)) {
input_analysis.is_final = false;
// Figure out what is missing
diff --git a/src/node/transaction.h b/src/node/transaction.h
index 0604754a46..45f174f13c 100644
--- a/src/node/transaction.h
+++ b/src/node/transaction.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/node/txreconciliation.cpp b/src/node/txreconciliation.cpp
new file mode 100644
index 0000000000..ed04a78cec
--- /dev/null
+++ b/src/node/txreconciliation.cpp
@@ -0,0 +1,169 @@
+// Copyright (c) 2022 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 <node/txreconciliation.h>
+
+#include <util/check.h>
+#include <util/system.h>
+
+#include <unordered_map>
+#include <variant>
+
+
+namespace {
+
+/** Static salt component used to compute short txids for sketch construction, see BIP-330. */
+const std::string RECON_STATIC_SALT = "Tx Relay Salting";
+const HashWriter RECON_SALT_HASHER = TaggedHash(RECON_STATIC_SALT);
+
+/**
+ * Salt (specified by BIP-330) constructed from contributions from both peers. It is used
+ * to compute transaction short IDs, which are then used to construct a sketch representing a set
+ * of transactions we want to announce to the peer.
+ */
+uint256 ComputeSalt(uint64_t salt1, uint64_t salt2)
+{
+ // According to BIP-330, salts should be combined in ascending order.
+ return (HashWriter(RECON_SALT_HASHER) << std::min(salt1, salt2) << std::max(salt1, salt2)).GetSHA256();
+}
+
+/**
+ * Keeps track of txreconciliation-related per-peer state.
+ */
+class TxReconciliationState
+{
+public:
+ /**
+ * TODO: This field is public to ignore -Wunused-private-field. Make private once used in
+ * the following commits.
+ *
+ * Reconciliation protocol assumes using one role consistently: either a reconciliation
+ * initiator (requesting sketches), or responder (sending sketches). This defines our role,
+ * based on the direction of the p2p connection.
+ *
+ */
+ bool m_we_initiate;
+
+ /**
+ * TODO: These fields are public to ignore -Wunused-private-field. Make private once used in
+ * the following commits.
+ *
+ * These values are used to salt short IDs, which is necessary for transaction reconciliations.
+ */
+ uint64_t m_k0, m_k1;
+
+ TxReconciliationState(bool we_initiate, uint64_t k0, uint64_t k1) : m_we_initiate(we_initiate), m_k0(k0), m_k1(k1) {}
+};
+
+} // namespace
+
+/** Actual implementation for TxReconciliationTracker's data structure. */
+class TxReconciliationTracker::Impl
+{
+private:
+ mutable Mutex m_txreconciliation_mutex;
+
+ // Local protocol version
+ uint32_t m_recon_version;
+
+ /**
+ * Keeps track of txreconciliation states of eligible peers.
+ * For pre-registered peers, the locally generated salt is stored.
+ * For registered peers, the locally generated salt is forgotten, and the state (including
+ * "full" salt) is stored instead.
+ */
+ std::unordered_map<NodeId, std::variant<uint64_t, TxReconciliationState>> m_states GUARDED_BY(m_txreconciliation_mutex);
+
+public:
+ explicit Impl(uint32_t recon_version) : m_recon_version(recon_version) {}
+
+ uint64_t PreRegisterPeer(NodeId peer_id) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
+ {
+ AssertLockNotHeld(m_txreconciliation_mutex);
+ LOCK(m_txreconciliation_mutex);
+
+ LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Pre-register peer=%d\n", peer_id);
+ const uint64_t local_salt{GetRand(UINT64_MAX)};
+
+ // We do this exactly once per peer (which are unique by NodeId, see GetNewNodeId) so it's
+ // safe to assume we don't have this record yet.
+ Assume(m_states.emplace(peer_id, local_salt).second);
+ return local_salt;
+ }
+
+ ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, uint32_t peer_recon_version,
+ uint64_t remote_salt) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
+ {
+ AssertLockNotHeld(m_txreconciliation_mutex);
+ LOCK(m_txreconciliation_mutex);
+ auto recon_state = m_states.find(peer_id);
+
+ if (recon_state == m_states.end()) return ReconciliationRegisterResult::NOT_FOUND;
+
+ if (std::holds_alternative<TxReconciliationState>(recon_state->second)) {
+ return ReconciliationRegisterResult::ALREADY_REGISTERED;
+ }
+
+ uint64_t local_salt = *std::get_if<uint64_t>(&recon_state->second);
+
+ // If the peer supports the version which is lower than ours, we downgrade to the version
+ // it supports. For now, this only guarantees that nodes with future reconciliation
+ // versions have the choice of reconciling with this current version. However, they also
+ // have the choice to refuse supporting reconciliations if the common version is not
+ // satisfactory (e.g. too low).
+ const uint32_t recon_version{std::min(peer_recon_version, m_recon_version)};
+ // v1 is the lowest version, so suggesting something below must be a protocol violation.
+ if (recon_version < 1) return ReconciliationRegisterResult::PROTOCOL_VIOLATION;
+
+ LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Register peer=%d (inbound=%i)\n",
+ peer_id, is_peer_inbound);
+
+ const uint256 full_salt{ComputeSalt(local_salt, remote_salt)};
+ recon_state->second = TxReconciliationState(!is_peer_inbound, full_salt.GetUint64(0), full_salt.GetUint64(1));
+ return ReconciliationRegisterResult::SUCCESS;
+ }
+
+ void ForgetPeer(NodeId peer_id) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
+ {
+ AssertLockNotHeld(m_txreconciliation_mutex);
+ LOCK(m_txreconciliation_mutex);
+ if (m_states.erase(peer_id)) {
+ LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Forget txreconciliation state of peer=%d\n", peer_id);
+ }
+ }
+
+ bool IsPeerRegistered(NodeId peer_id) const EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
+ {
+ AssertLockNotHeld(m_txreconciliation_mutex);
+ LOCK(m_txreconciliation_mutex);
+ auto recon_state = m_states.find(peer_id);
+ return (recon_state != m_states.end() &&
+ std::holds_alternative<TxReconciliationState>(recon_state->second));
+ }
+};
+
+TxReconciliationTracker::TxReconciliationTracker(uint32_t recon_version) : m_impl{std::make_unique<TxReconciliationTracker::Impl>(recon_version)} {}
+
+TxReconciliationTracker::~TxReconciliationTracker() = default;
+
+uint64_t TxReconciliationTracker::PreRegisterPeer(NodeId peer_id)
+{
+ return m_impl->PreRegisterPeer(peer_id);
+}
+
+ReconciliationRegisterResult TxReconciliationTracker::RegisterPeer(NodeId peer_id, bool is_peer_inbound,
+ uint32_t peer_recon_version, uint64_t remote_salt)
+{
+ return m_impl->RegisterPeer(peer_id, is_peer_inbound, peer_recon_version, remote_salt);
+}
+
+void TxReconciliationTracker::ForgetPeer(NodeId peer_id)
+{
+ m_impl->ForgetPeer(peer_id);
+}
+
+bool TxReconciliationTracker::IsPeerRegistered(NodeId peer_id) const
+{
+ return m_impl->IsPeerRegistered(peer_id);
+}
diff --git a/src/node/txreconciliation.h b/src/node/txreconciliation.h
new file mode 100644
index 0000000000..4591dd5df7
--- /dev/null
+++ b/src/node/txreconciliation.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2022 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_NODE_TXRECONCILIATION_H
+#define BITCOIN_NODE_TXRECONCILIATION_H
+
+#include <net.h>
+#include <sync.h>
+
+#include <memory>
+#include <tuple>
+
+/** Whether transaction reconciliation protocol should be enabled by default. */
+static constexpr bool DEFAULT_TXRECONCILIATION_ENABLE{false};
+/** Supported transaction reconciliation protocol version */
+static constexpr uint32_t TXRECONCILIATION_VERSION{1};
+
+enum class ReconciliationRegisterResult {
+ NOT_FOUND,
+ SUCCESS,
+ ALREADY_REGISTERED,
+ PROTOCOL_VIOLATION,
+};
+
+/**
+ * Transaction reconciliation is a way for nodes to efficiently announce transactions.
+ * This object keeps track of all txreconciliation-related communications with the peers.
+ * The high-level protocol is:
+ * 0. Txreconciliation protocol handshake.
+ * 1. Once we receive a new transaction, add it to the set instead of announcing immediately.
+ * 2. At regular intervals, a txreconciliation initiator requests a sketch from a peer, where a
+ * sketch is a compressed representation of short form IDs of the transactions in their set.
+ * 3. Once the initiator received a sketch from the peer, the initiator computes a local sketch,
+ * and combines the two sketches to attempt finding the difference in *sets*.
+ * 4a. If the difference was not larger than estimated, see SUCCESS below.
+ * 4b. If the difference was larger than estimated, initial txreconciliation fails. The initiator
+ * requests a larger sketch via an extension round (allowed only once).
+ * - If extension succeeds (a larger sketch is sufficient), see SUCCESS below.
+ * - If extension fails (a larger sketch is insufficient), see FAILURE below.
+ *
+ * SUCCESS. The initiator knows full symmetrical difference and can request what the initiator is
+ * missing and announce to the peer what the peer is missing.
+ *
+ * FAILURE. The initiator notifies the peer about the failure and announces all transactions from
+ * the corresponding set. Once the peer received the failure notification, the peer
+ * announces all transactions from their set.
+
+ * This is a modification of the Erlay protocol (https://arxiv.org/abs/1905.10518) with two
+ * changes (sketch extensions instead of bisections, and an extra INV exchange round), both
+ * are motivated in BIP-330.
+ */
+class TxReconciliationTracker
+{
+private:
+ class Impl;
+ const std::unique_ptr<Impl> m_impl;
+
+public:
+ explicit TxReconciliationTracker(uint32_t recon_version);
+ ~TxReconciliationTracker();
+
+ /**
+ * Step 0. Generates initial part of the state (salt) required to reconcile txs with the peer.
+ * The salt is used for short ID computation required for txreconciliation.
+ * The function returns the salt.
+ * A peer can't participate in future txreconciliations without this call.
+ * This function must be called only once per peer.
+ */
+ uint64_t PreRegisterPeer(NodeId peer_id);
+
+ /**
+ * Step 0. Once the peer agreed to reconcile txs with us, generate the state required to track
+ * ongoing reconciliations. Must be called only after pre-registering the peer and only once.
+ */
+ ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound,
+ uint32_t peer_recon_version, uint64_t remote_salt);
+
+ /**
+ * Attempts to forget txreconciliation-related state of the peer (if we previously stored any).
+ * After this, we won't be able to reconcile transactions with the peer.
+ */
+ void ForgetPeer(NodeId peer_id);
+
+ /**
+ * Check if a peer is registered to reconcile transactions with us.
+ */
+ bool IsPeerRegistered(NodeId peer_id) const;
+};
+
+#endif // BITCOIN_NODE_TXRECONCILIATION_H
diff --git a/src/node/utxo_snapshot.cpp b/src/node/utxo_snapshot.cpp
new file mode 100644
index 0000000000..cccf95e552
--- /dev/null
+++ b/src/node/utxo_snapshot.cpp
@@ -0,0 +1,96 @@
+// Copyright (c) 2022 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 <node/utxo_snapshot.h>
+
+#include <fs.h>
+#include <logging.h>
+#include <streams.h>
+#include <sync.h>
+#include <tinyformat.h>
+#include <txdb.h>
+#include <uint256.h>
+#include <util/system.h>
+#include <validation.h>
+
+#include <cassert>
+#include <cstdio>
+#include <optional>
+#include <string>
+
+namespace node {
+
+bool WriteSnapshotBaseBlockhash(Chainstate& snapshot_chainstate)
+{
+ AssertLockHeld(::cs_main);
+ assert(snapshot_chainstate.m_from_snapshot_blockhash);
+
+ const std::optional<fs::path> chaindir = snapshot_chainstate.CoinsDB().StoragePath();
+ assert(chaindir); // Sanity check that chainstate isn't in-memory.
+ const fs::path write_to = *chaindir / node::SNAPSHOT_BLOCKHASH_FILENAME;
+
+ FILE* file{fsbridge::fopen(write_to, "wb")};
+ AutoFile afile{file};
+ if (afile.IsNull()) {
+ LogPrintf("[snapshot] failed to open base blockhash file for writing: %s\n",
+ fs::PathToString(write_to));
+ return false;
+ }
+ afile << *snapshot_chainstate.m_from_snapshot_blockhash;
+
+ if (afile.fclose() != 0) {
+ LogPrintf("[snapshot] failed to close base blockhash file %s after writing\n",
+ fs::PathToString(write_to));
+ return false;
+ }
+ return true;
+}
+
+std::optional<uint256> ReadSnapshotBaseBlockhash(fs::path chaindir)
+{
+ if (!fs::exists(chaindir)) {
+ LogPrintf("[snapshot] cannot read base blockhash: no chainstate dir " /* Continued */
+ "exists at path %s\n", fs::PathToString(chaindir));
+ return std::nullopt;
+ }
+ const fs::path read_from = chaindir / node::SNAPSHOT_BLOCKHASH_FILENAME;
+ const std::string read_from_str = fs::PathToString(read_from);
+
+ if (!fs::exists(read_from)) {
+ LogPrintf("[snapshot] snapshot chainstate dir is malformed! no base blockhash file " /* Continued */
+ "exists at path %s. Try deleting %s and calling loadtxoutset again?\n",
+ fs::PathToString(chaindir), read_from_str);
+ return std::nullopt;
+ }
+
+ uint256 base_blockhash;
+ FILE* file{fsbridge::fopen(read_from, "rb")};
+ AutoFile afile{file};
+ if (afile.IsNull()) {
+ LogPrintf("[snapshot] failed to open base blockhash file for reading: %s\n",
+ read_from_str);
+ return std::nullopt;
+ }
+ afile >> base_blockhash;
+
+ if (std::fgetc(afile.Get()) != EOF) {
+ LogPrintf("[snapshot] warning: unexpected trailing data in %s\n", read_from_str);
+ } else if (std::ferror(afile.Get())) {
+ LogPrintf("[snapshot] warning: i/o error reading %s\n", read_from_str);
+ }
+ return base_blockhash;
+}
+
+std::optional<fs::path> FindSnapshotChainstateDir()
+{
+ fs::path possible_dir =
+ gArgs.GetDataDirNet() / fs::u8path(strprintf("chainstate%s", SNAPSHOT_CHAINSTATE_SUFFIX));
+
+ if (fs::exists(possible_dir)) {
+ return possible_dir;
+ }
+ return std::nullopt;
+}
+
+} // namespace node
diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h
index 9dd6f06997..c5c018c9e8 100644
--- a/src/node/utxo_snapshot.h
+++ b/src/node/utxo_snapshot.h
@@ -1,13 +1,22 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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_NODE_UTXO_SNAPSHOT_H
#define BITCOIN_NODE_UTXO_SNAPSHOT_H
-#include <uint256.h>
+#include <fs.h>
+#include <kernel/cs_main.h>
#include <serialize.h>
+#include <sync.h>
+#include <uint256.h>
+
+#include <cstdint>
+#include <optional>
+#include <string_view>
+
+class Chainstate;
namespace node {
//! Metadata describing a serialized version of a UTXO set from which an
@@ -33,6 +42,33 @@ public:
SERIALIZE_METHODS(SnapshotMetadata, obj) { READWRITE(obj.m_base_blockhash, obj.m_coins_count); }
};
+
+//! The file in the snapshot chainstate dir which stores the base blockhash. This is
+//! needed to reconstruct snapshot chainstates on init.
+//!
+//! Because we only allow loading a single snapshot at a time, there will only be one
+//! chainstate directory with this filename present within it.
+const fs::path SNAPSHOT_BLOCKHASH_FILENAME{"base_blockhash"};
+
+//! Write out the blockhash of the snapshot base block that was used to construct
+//! this chainstate. This value is read in during subsequent initializations and
+//! used to reconstruct snapshot-based chainstates.
+bool WriteSnapshotBaseBlockhash(Chainstate& snapshot_chainstate)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
+//! Read the blockhash of the snapshot base block that was used to construct the
+//! chainstate.
+std::optional<uint256> ReadSnapshotBaseBlockhash(fs::path chaindir)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
+//! Suffix appended to the chainstate (leveldb) dir when created based upon
+//! a snapshot.
+constexpr std::string_view SNAPSHOT_CHAINSTATE_SUFFIX = "_snapshot";
+
+
+//! Return a path to the snapshot-based chainstate dir, if one exists.
+std::optional<fs::path> FindSnapshotChainstateDir();
+
} // namespace node
#endif // BITCOIN_NODE_UTXO_SNAPSHOT_H
diff --git a/src/noui.cpp b/src/noui.cpp
index 54cb5f3cbf..af5a180ce3 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/outputtype.cpp b/src/outputtype.cpp
index 9ab2902256..270212dca5 100644
--- a/src/outputtype.cpp
+++ b/src/outputtype.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/outputtype.h b/src/outputtype.h
index c59262591b..7c50f445fc 100644
--- a/src/outputtype.h
+++ b/src/outputtype.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp
index 82b767793d..eb0cba5c67 100644
--- a/src/policy/feerate.cpp
+++ b/src/policy/feerate.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index a8d4d2fc63..6f859e2d0d 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 2b940be07e..d244de1bb2 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,6 +8,7 @@
#include <clientversion.h>
#include <consensus/amount.h>
#include <fs.h>
+#include <kernel/mempool_entry.h>
#include <logging.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
@@ -16,7 +17,6 @@
#include <streams.h>
#include <sync.h>
#include <tinyformat.h>
-#include <txmempool.h>
#include <uint256.h>
#include <util/serfloat.h>
#include <util/system.h>
@@ -528,7 +528,7 @@ bool CBlockPolicyEstimator::_removeTx(const uint256& hash, bool inBlock)
}
CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath)
- : m_estimation_filepath{estimation_filepath}, nBestSeenHeight{0}, firstRecordedHeight{0}, historicalFirst{0}, historicalBest{0}, trackedTxs{0}, untrackedTxs{0}
+ : m_estimation_filepath{estimation_filepath}
{
static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
size_t bucketIndex = 0;
@@ -997,8 +997,9 @@ bool CBlockPolicyEstimator::Read(AutoFile& filein)
return true;
}
-void CBlockPolicyEstimator::FlushUnconfirmed() {
- int64_t startclear = GetTimeMicros();
+void CBlockPolicyEstimator::FlushUnconfirmed()
+{
+ const auto startclear{SteadyClock::now()};
LOCK(m_cs_fee_estimator);
size_t num_entries = mapMemPoolTxs.size();
// Remove every entry in mapMemPoolTxs
@@ -1006,24 +1007,41 @@ void CBlockPolicyEstimator::FlushUnconfirmed() {
auto mi = mapMemPoolTxs.begin();
_removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
}
- int64_t endclear = GetTimeMicros();
- LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
+ const auto endclear{SteadyClock::now()};
+ LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
}
-FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
+static std::set<double> MakeFeeSet(const CFeeRate& min_incremental_fee,
+ double max_filter_fee_rate,
+ double fee_filter_spacing)
{
- CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2);
- feeset.insert(0);
- for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FILTER_FEERATE; bucketBoundary *= FEE_FILTER_SPACING) {
- feeset.insert(bucketBoundary);
+ std::set<double> fee_set;
+
+ const CAmount min_fee_limit{std::max(CAmount(1), min_incremental_fee.GetFeePerK() / 2)};
+ fee_set.insert(0);
+ for (double bucket_boundary = min_fee_limit;
+ bucket_boundary <= max_filter_fee_rate;
+ bucket_boundary *= fee_filter_spacing) {
+
+ fee_set.insert(bucket_boundary);
}
+
+ return fee_set;
+}
+
+FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
+ : m_fee_set{MakeFeeSet(minIncrementalFee, MAX_FILTER_FEERATE, FEE_FILTER_SPACING)}
+{
}
CAmount FeeFilterRounder::round(CAmount currentMinFee)
{
- std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
- if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
- it--;
+ AssertLockNotHeld(m_insecure_rand_mutex);
+ std::set<double>::iterator it = m_fee_set.lower_bound(currentMinFee);
+ if (it == m_fee_set.end() ||
+ (it != m_fee_set.begin() &&
+ WITH_LOCK(m_insecure_rand_mutex, return insecure_rand.rand32()) % 3 != 0)) {
+ --it;
}
return static_cast<CAmount>(*it);
}
diff --git a/src/policy/fees.h b/src/policy/fees.h
index e4628bf853..1c24b8c7c3 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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_POLICY_FEES_H
@@ -242,16 +242,16 @@ public:
private:
mutable Mutex m_cs_fee_estimator;
- unsigned int nBestSeenHeight GUARDED_BY(m_cs_fee_estimator);
- unsigned int firstRecordedHeight GUARDED_BY(m_cs_fee_estimator);
- unsigned int historicalFirst GUARDED_BY(m_cs_fee_estimator);
- unsigned int historicalBest GUARDED_BY(m_cs_fee_estimator);
+ unsigned int nBestSeenHeight GUARDED_BY(m_cs_fee_estimator){0};
+ unsigned int firstRecordedHeight GUARDED_BY(m_cs_fee_estimator){0};
+ unsigned int historicalFirst GUARDED_BY(m_cs_fee_estimator){0};
+ unsigned int historicalBest GUARDED_BY(m_cs_fee_estimator){0};
struct TxStatsInfo
{
- unsigned int blockHeight;
- unsigned int bucketIndex;
- TxStatsInfo() : blockHeight(0), bucketIndex(0) {}
+ unsigned int blockHeight{0};
+ unsigned int bucketIndex{0};
+ TxStatsInfo() {}
};
// map of txids to information about that transaction
@@ -262,8 +262,8 @@ private:
std::unique_ptr<TxConfirmStats> shortStats PT_GUARDED_BY(m_cs_fee_estimator);
std::unique_ptr<TxConfirmStats> longStats PT_GUARDED_BY(m_cs_fee_estimator);
- unsigned int trackedTxs GUARDED_BY(m_cs_fee_estimator);
- unsigned int untrackedTxs GUARDED_BY(m_cs_fee_estimator);
+ unsigned int trackedTxs GUARDED_BY(m_cs_fee_estimator){0};
+ unsigned int untrackedTxs GUARDED_BY(m_cs_fee_estimator){0};
std::vector<double> buckets GUARDED_BY(m_cs_fee_estimator); // The upper-bound of the range for the bucket (inclusive)
std::map<double, unsigned int> bucketMap GUARDED_BY(m_cs_fee_estimator); // Map of bucket upper-bound to index into all vectors by bucket
@@ -299,14 +299,15 @@ private:
public:
/** Create new FeeFilterRounder */
- explicit FeeFilterRounder(const CFeeRate& minIncrementalFee);
+ explicit FeeFilterRounder(const CFeeRate& min_incremental_fee);
- /** Quantize a minimum fee for privacy purpose before broadcast. Not thread-safe due to use of FastRandomContext */
- CAmount round(CAmount currentMinFee);
+ /** Quantize a minimum fee for privacy purpose before broadcast. */
+ CAmount round(CAmount currentMinFee) EXCLUSIVE_LOCKS_REQUIRED(!m_insecure_rand_mutex);
private:
- std::set<double> feeset;
- FastRandomContext insecure_rand;
+ const std::set<double> m_fee_set;
+ Mutex m_insecure_rand_mutex;
+ FastRandomContext insecure_rand GUARDED_BY(m_insecure_rand_mutex);
};
#endif // BITCOIN_POLICY_FEES_H
diff --git a/src/policy/fees_args.cpp b/src/policy/fees_args.cpp
index a3531153b5..1aeb2ab983 100644
--- a/src/policy/fees_args.cpp
+++ b/src/policy/fees_args.cpp
@@ -1,3 +1,7 @@
+// Copyright (c) 2021 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 <policy/fees_args.h>
#include <util/system.h>
diff --git a/src/policy/packages.cpp b/src/policy/packages.cpp
index 67918c9dec..6e70a94088 100644
--- a/src/policy/packages.cpp
+++ b/src/policy/packages.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/packages.h b/src/policy/packages.h
index 36c70e9e66..0a0e7cf6bb 100644
--- a/src/policy/packages.h
+++ b/src/policy/packages.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 5086542865..41b5b2d0f1 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 29764ea2d9..394fb34230 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -25,8 +25,8 @@ static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{MAX_BLOCK_WEIGHT - 4000};
static constexpr unsigned int DEFAULT_BLOCK_MIN_TX_FEE{1000};
/** The maximum weight for transactions we're willing to relay/mine */
static constexpr unsigned int MAX_STANDARD_TX_WEIGHT{400000};
-/** The minimum non-witness size for transactions we're willing to relay/mine (1 segwit input + 1 P2WPKH output = 82 bytes) */
-static constexpr unsigned int MIN_STANDARD_TX_NONWITNESS_SIZE{82};
+/** The minimum non-witness size for transactions we're willing to relay/mine: one larger than 64 */
+static constexpr unsigned int MIN_STANDARD_TX_NONWITNESS_SIZE{65};
/** Maximum number of signature check operations in an IsStandard() P2SH script */
static constexpr unsigned int MAX_P2SH_SIGOPS{15};
/** The maximum number of sigops we're willing to relay/mine in a single tx */
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 6098caced9..d032b74008 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 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 <policy/rbf.h>
#include <consensus/amount.h>
+#include <kernel/mempool_entry.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <sync.h>
@@ -21,8 +22,6 @@ RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
{
AssertLockHeld(pool.cs);
- CTxMemPool::setEntries ancestors;
-
// First check the transaction itself.
if (SignalsOptInRBF(tx)) {
return RBFTransactionState::REPLACEABLE_BIP125;
@@ -36,10 +35,9 @@ RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
// If all the inputs have nSequence >= maxint-1, it still might be
// signaled for RBF if any unconfirmed parents have signaled.
- uint64_t noLimit = std::numeric_limits<uint64_t>::max();
- std::string dummy;
- CTxMemPoolEntry entry = *pool.mapTx.find(tx.GetHash());
- pool.CalculateMemPoolAncestors(entry, ancestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
+ const CTxMemPoolEntry entry{*pool.mapTx.find(tx.GetHash())};
+ auto ancestors{pool.AssumeCalculateMemPoolAncestors(__func__, entry, CTxMemPool::Limits::NoLimits(),
+ /*fSearchForParents=*/false)};
for (CTxMemPool::txiter it : ancestors) {
if (SignalsOptInRBF(it->GetTx())) {
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index 28c4e4bf9b..fff9828482 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/settings.cpp b/src/policy/settings.cpp
index 39e00f1111..722b12acf5 100644
--- a/src/policy/settings.cpp
+++ b/src/policy/settings.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/settings.h b/src/policy/settings.h
index f0d6f779ae..145454b0dd 100644
--- a/src/policy/settings.h
+++ b/src/policy/settings.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/pow.cpp b/src/pow.cpp
index c0449cac74..1e8d53de8b 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/pow.h b/src/pow.h
index 44b9d673ef..ec03f318a4 100644
--- a/src/pow.h
+++ b/src/pow.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/prevector.h b/src/prevector.h
index 7df5a067a2..f36cfe4ff6 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 2e26e6c426..bd11279a6e 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index ec48194ee9..3060746909 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index f496ea022e..bd7eb16bec 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,6 +17,7 @@
#include <ios>
#include <limits>
#include <memory>
+#include <numeric>
#include <string>
#include <tuple>
#include <utility>
@@ -280,6 +281,12 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
s << tx.nLockTime;
}
+template<typename TxType>
+inline CAmount CalculateOutputValue(const TxType& tx)
+{
+ return std::accumulate(tx.vout.cbegin(), tx.vout.cend(), CAmount{0}, [](CAmount sum, const auto& txout) { return sum + txout.nValue; });
+}
+
/** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
diff --git a/src/protocol.cpp b/src/protocol.cpp
index bdd1cc2aff..aa59bae6ff 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -44,6 +44,7 @@ const char *CFHEADERS="cfheaders";
const char *GETCFCHECKPT="getcfcheckpt";
const char *CFCHECKPT="cfcheckpt";
const char *WTXIDRELAY="wtxidrelay";
+const char *SENDTXRCNCL="sendtxrcncl";
} // namespace NetMsgType
/** All known message types. Keep this in the same order as the list of
@@ -84,6 +85,7 @@ const static std::string allNetMessageTypes[] = {
NetMsgType::GETCFCHECKPT,
NetMsgType::CFCHECKPT,
NetMsgType::WTXIDRELAY,
+ NetMsgType::SENDTXRCNCL,
};
const static std::vector<std::string> allNetMessageTypesVec(std::begin(allNetMessageTypes), std::end(allNetMessageTypes));
diff --git a/src/protocol.h b/src/protocol.h
index b85dc0d820..cbcd400fef 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -258,6 +258,12 @@ extern const char* CFCHECKPT;
* @since protocol version 70016 as described by BIP 339.
*/
extern const char* WTXIDRELAY;
+/**
+ * Contains a 4-byte version number and an 8-byte salt.
+ * The salt is used to compute short txids needed for efficient
+ * txreconciliation, as described by BIP 330.
+ */
+extern const char* SENDTXRCNCL;
}; // namespace NetMsgType
/* Get a vector of all valid message types (see above) */
diff --git a/src/psbt.cpp b/src/psbt.cpp
index 36fec74bc9..fe45f2318c 100644
--- a/src/psbt.cpp
+++ b/src/psbt.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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 <psbt.h>
+#include <policy/policy.h>
#include <util/check.h>
#include <util/strencodings.h>
@@ -131,6 +132,18 @@ void PSBTInput::FillSignatureData(SignatureData& sigdata) const
for (const auto& [pubkey, leaf_origin] : m_tap_bip32_paths) {
sigdata.taproot_misc_pubkeys.emplace(pubkey, leaf_origin);
}
+ for (const auto& [hash, preimage] : ripemd160_preimages) {
+ sigdata.ripemd160_preimages.emplace(std::vector<unsigned char>(hash.begin(), hash.end()), preimage);
+ }
+ for (const auto& [hash, preimage] : sha256_preimages) {
+ sigdata.sha256_preimages.emplace(std::vector<unsigned char>(hash.begin(), hash.end()), preimage);
+ }
+ for (const auto& [hash, preimage] : hash160_preimages) {
+ sigdata.hash160_preimages.emplace(std::vector<unsigned char>(hash.begin(), hash.end()), preimage);
+ }
+ for (const auto& [hash, preimage] : hash256_preimages) {
+ sigdata.hash256_preimages.emplace(std::vector<unsigned char>(hash.begin(), hash.end()), preimage);
+ }
}
void PSBTInput::FromSignatureData(const SignatureData& sigdata)
@@ -218,8 +231,14 @@ void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
for (const auto& key_pair : hd_keypaths) {
sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
}
- if (m_tap_tree.has_value() && m_tap_internal_key.IsFullyValid()) {
- TaprootSpendData spenddata = m_tap_tree->GetSpendData();
+ if (!m_tap_tree.empty() && m_tap_internal_key.IsFullyValid()) {
+ TaprootBuilder builder;
+ for (const auto& [depth, leaf_ver, script] : m_tap_tree) {
+ builder.Add((int)depth, script, (int)leaf_ver, /*track=*/true);
+ }
+ assert(builder.IsComplete());
+ builder.Finalize(m_tap_internal_key);
+ TaprootSpendData spenddata = builder.GetSpendData();
sigdata.tr_spenddata.internal_key = m_tap_internal_key;
sigdata.tr_spenddata.Merge(spenddata);
@@ -243,8 +262,8 @@ void PSBTOutput::FromSignatureData(const SignatureData& sigdata)
if (!sigdata.tr_spenddata.internal_key.IsNull()) {
m_tap_internal_key = sigdata.tr_spenddata.internal_key;
}
- if (sigdata.tr_builder.has_value()) {
- m_tap_tree = sigdata.tr_builder;
+ if (sigdata.tr_builder.has_value() && sigdata.tr_builder->HasScripts()) {
+ m_tap_tree = sigdata.tr_builder->GetTreeTuples();
}
for (const auto& [pubkey, leaf_origin] : sigdata.taproot_misc_pubkeys) {
m_tap_bip32_paths.emplace(pubkey, leaf_origin);
@@ -265,13 +284,43 @@ void PSBTOutput::Merge(const PSBTOutput& output)
if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
if (m_tap_internal_key.IsNull() && !output.m_tap_internal_key.IsNull()) m_tap_internal_key = output.m_tap_internal_key;
- if (m_tap_tree.has_value() && !output.m_tap_tree.has_value()) m_tap_tree = output.m_tap_tree;
+ if (m_tap_tree.empty() && !output.m_tap_tree.empty()) m_tap_tree = output.m_tap_tree;
}
+
bool PSBTInputSigned(const PSBTInput& input)
{
return !input.final_script_sig.empty() || !input.final_script_witness.IsNull();
}
+bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned int input_index, const PrecomputedTransactionData* txdata)
+{
+ CTxOut utxo;
+ assert(psbt.inputs.size() >= input_index);
+ const PSBTInput& input = psbt.inputs[input_index];
+
+ if (input.non_witness_utxo) {
+ // If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
+ COutPoint prevout = psbt.tx->vin[input_index].prevout;
+ if (prevout.n >= input.non_witness_utxo->vout.size()) {
+ return false;
+ }
+ if (input.non_witness_utxo->GetHash() != prevout.hash) {
+ return false;
+ }
+ utxo = input.non_witness_utxo->vout[prevout.n];
+ } else if (!input.witness_utxo.IsNull()) {
+ utxo = input.witness_utxo;
+ } else {
+ return false;
+ }
+
+ if (txdata) {
+ return VerifyScript(input.final_script_sig, utxo.scriptPubKey, &input.final_script_witness, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker{&(*psbt.tx), input_index, utxo.nValue, *txdata, MissingDataBehavior::FAIL});
+ } else {
+ return VerifyScript(input.final_script_sig, utxo.scriptPubKey, &input.final_script_witness, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker{&(*psbt.tx), input_index, utxo.nValue, MissingDataBehavior::FAIL});
+ }
+}
+
size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt) {
size_t count = 0;
for (const auto& input : psbt.inputs) {
@@ -325,7 +374,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
PSBTInput& input = psbt.inputs.at(index);
const CMutableTransaction& tx = *psbt.tx;
- if (PSBTInputSigned(input)) {
+ if (PSBTInputSignedAndVerified(psbt, index, txdata)) {
return true;
}
diff --git a/src/psbt.h b/src/psbt.h
index d5c67802c7..c497584f36 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -178,7 +178,7 @@ void SerializeHDKeypath(Stream& s, KeyOriginInfo hd_keypath)
template<typename Stream>
void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, CompactSizeWriter type)
{
- for (auto keypath_pair : hd_keypaths) {
+ for (const auto& keypath_pair : hd_keypaths) {
if (!keypath_pair.first.IsValid()) {
throw std::ios_base::failure("Invalid CPubKey being serialized");
}
@@ -206,7 +206,7 @@ struct PSBTInput
// Taproot fields
std::vector<unsigned char> m_tap_key_sig;
std::map<std::pair<XOnlyPubKey, uint256>, std::vector<unsigned char>> m_tap_script_sigs;
- std::map<std::pair<CScript, int>, std::set<std::vector<unsigned char>, ShortestVectorFirstComparator>> m_tap_scripts;
+ std::map<std::pair<std::vector<unsigned char>, int>, std::set<std::vector<unsigned char>, ShortestVectorFirstComparator>> m_tap_scripts;
std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> m_tap_bip32_paths;
XOnlyPubKey m_tap_internal_key;
uint256 m_tap_merkle_root;
@@ -621,7 +621,7 @@ struct PSBTInput
}
uint8_t leaf_ver = script_v.back();
script_v.pop_back();
- const auto leaf_script = std::make_pair(CScript(script_v.begin(), script_v.end()), (int)leaf_ver);
+ const auto leaf_script = std::make_pair(script_v, (int)leaf_ver);
m_tap_scripts[leaf_script].insert(std::vector<unsigned char>(key.begin() + 1, key.end()));
break;
}
@@ -713,7 +713,7 @@ struct PSBTOutput
CScript witness_script;
std::map<CPubKey, KeyOriginInfo> hd_keypaths;
XOnlyPubKey m_tap_internal_key;
- std::optional<TaprootBuilder> m_tap_tree;
+ std::vector<std::tuple<uint8_t, uint8_t, std::vector<unsigned char>>> m_tap_tree;
std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> m_tap_bip32_paths;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
std::set<PSBTProprietary> m_proprietary;
@@ -754,15 +754,11 @@ struct PSBTOutput
}
// Write taproot tree
- if (m_tap_tree.has_value()) {
+ if (!m_tap_tree.empty()) {
SerializeToVector(s, PSBT_OUT_TAP_TREE);
std::vector<unsigned char> value;
CVectorWriter s_value(s.GetType(), s.GetVersion(), value, 0);
- const auto& tuples = m_tap_tree->GetTreeTuples();
- for (const auto& tuple : tuples) {
- uint8_t depth = std::get<0>(tuple);
- uint8_t leaf_ver = std::get<1>(tuple);
- CScript script = std::get<2>(tuple);
+ for (const auto& [depth, leaf_ver, script] : m_tap_tree) {
s_value << depth;
s_value << leaf_ver;
s_value << script;
@@ -858,14 +854,17 @@ struct PSBTOutput
} else if (key.size() != 1) {
throw std::ios_base::failure("Output Taproot tree key is more than one byte type");
}
- m_tap_tree.emplace();
std::vector<unsigned char> tree_v;
s >> tree_v;
SpanReader s_tree(s.GetType(), s.GetVersion(), tree_v);
+ if (s_tree.empty()) {
+ throw std::ios_base::failure("Output Taproot tree must not be empty");
+ }
+ TaprootBuilder builder;
while (!s_tree.empty()) {
uint8_t depth;
uint8_t leaf_ver;
- CScript script;
+ std::vector<unsigned char> script;
s_tree >> depth;
s_tree >> leaf_ver;
s_tree >> script;
@@ -875,9 +874,10 @@ struct PSBTOutput
if ((leaf_ver & ~TAPROOT_LEAF_MASK) != 0) {
throw std::ios_base::failure("Output Taproot tree has a leaf with an invalid leaf version");
}
- m_tap_tree->Add((int)depth, script, (int)leaf_ver, true /* track */);
+ m_tap_tree.push_back(std::make_tuple(depth, leaf_ver, script));
+ builder.Add((int)depth, script, (int)leaf_ver, /*track=*/true);
}
- if (!m_tap_tree->IsComplete()) {
+ if (!builder.IsComplete()) {
throw std::ios_base::failure("Output Taproot tree is malformed");
}
break;
@@ -889,7 +889,7 @@ struct PSBTOutput
} else if (key.size() != 33) {
throw std::ios_base::failure("Output Taproot BIP32 keypath key is not at 33 bytes");
}
- XOnlyPubKey xonly(uint256({key.begin() + 1, key.begin() + 33}));
+ XOnlyPubKey xonly(uint256(Span<uint8_t>(key).last(32)));
std::set<uint256> leaf_hashes;
uint64_t value_len = ReadCompactSize(s);
size_t before_hashes = s.size();
@@ -931,11 +931,6 @@ struct PSBTOutput
}
}
- // Finalize m_tap_tree so that all of the computed things are computed
- if (m_tap_tree.has_value() && m_tap_tree->IsComplete() && m_tap_internal_key.IsFullyValid()) {
- m_tap_tree->Finalize(m_tap_internal_key);
- }
-
if (!found_sep) {
throw std::ios_base::failure("Separator is missing at the end of an output map");
}
@@ -1169,7 +1164,7 @@ struct PartiallySignedTransaction
// Make sure that we got an unsigned tx
if (!tx) {
- throw std::ios_base::failure("No unsigned transcation was provided");
+ throw std::ios_base::failure("No unsigned transaction was provided");
}
// Read input data
@@ -1223,9 +1218,12 @@ std::string PSBTRoleName(PSBTRole role);
/** Compute a PrecomputedTransactionData object from a psbt. */
PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction& psbt);
-/** Checks whether a PSBTInput is already signed. */
+/** Checks whether a PSBTInput is already signed by checking for non-null finalized fields. */
bool PSBTInputSigned(const PSBTInput& input);
+/** Checks whether a PSBTInput is already signed by doing script verification using final fields. */
+bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned int input_index, const PrecomputedTransactionData* txdata);
+
/** Signs a PSBTInput, verifying that all provided data matches what is being signed.
*
* txdata should be the output of PrecomputePSBTData (which can be shared across
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 2e37e16690..ae5dccfb5a 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,10 +16,16 @@
#include <algorithm>
#include <cassert>
-namespace
+namespace {
+
+struct Secp256k1SelfTester
{
-/* Global secp256k1_context object used for verification. */
-secp256k1_context* secp256k1_context_verify = nullptr;
+ Secp256k1SelfTester() {
+ /* Run libsecp256k1 self-test before using the secp256k1_context_static. */
+ secp256k1_selftest();
+ }
+} SECP256K1_SELFTESTER;
+
} // namespace
/** This function is taken from the libsecp256k1 distribution and implements
@@ -32,7 +38,7 @@ secp256k1_context* secp256k1_context_verify = nullptr;
* strict DER before being passed to this module, and we know it supports all
* violations present in the blockchain before that point.
*/
-int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
+int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
size_t rpos, rlen, spos, slen;
size_t pos = 0;
size_t lenbyte;
@@ -40,7 +46,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
int overflow = 0;
/* Hack to initialize sig with a correctly-parsed but invalid signature. */
- secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
+ secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig);
/* Sequence tag byte */
if (pos == inputlen || input[pos] != 0x30) {
@@ -163,13 +169,13 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
}
if (!overflow) {
- overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
+ overflow = !secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig);
}
if (overflow) {
/* Overwrite the result again with a correctly-parsed but invalid
signature if parsing failed. */
memset(tmpsig, 0, 64);
- secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
+ secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig);
}
return 1;
}
@@ -200,15 +206,15 @@ std::vector<CKeyID> XOnlyPubKey::GetKeyIDs() const
bool XOnlyPubKey::IsFullyValid() const
{
secp256k1_xonly_pubkey pubkey;
- return secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data());
+ return secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data());
}
bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const
{
assert(sigbytes.size() == 64);
secp256k1_xonly_pubkey pubkey;
- if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data())) return false;
- return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), 32, &pubkey);
+ if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data())) return false;
+ return secp256k1_schnorrsig_verify(secp256k1_context_static, sigbytes.data(), msg.begin(), 32, &pubkey);
}
static const HashWriter HASHER_TAPTWEAK{TaggedHash("TapTweak")};
@@ -227,23 +233,23 @@ uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const
bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const
{
secp256k1_xonly_pubkey internal_key;
- if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &internal_key, internal.data())) return false;
+ if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &internal_key, internal.data())) return false;
uint256 tweak = internal.ComputeTapTweakHash(&merkle_root);
- return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &internal_key, tweak.begin());
+ return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_static, m_keydata.begin(), parity, &internal_key, tweak.begin());
}
std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const
{
secp256k1_xonly_pubkey base_point;
- if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt;
+ if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &base_point, data())) return std::nullopt;
secp256k1_pubkey out;
uint256 tweak = ComputeTapTweakHash(merkle_root);
- if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_verify, &out, &base_point, tweak.data())) return std::nullopt;
+ if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_static, &out, &base_point, tweak.data())) return std::nullopt;
int parity = -1;
std::pair<XOnlyPubKey, bool> ret;
secp256k1_xonly_pubkey out_xonly;
- if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_verify, &out_xonly, &parity, &out)) return std::nullopt;
- secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, ret.first.begin(), &out_xonly);
+ if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_static, &out_xonly, &parity, &out)) return std::nullopt;
+ secp256k1_xonly_pubkey_serialize(secp256k1_context_static, ret.first.begin(), &out_xonly);
assert(parity == 0 || parity == 1);
ret.second = parity;
return ret;
@@ -255,17 +261,16 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchS
return false;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
- assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
- if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
+ if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
return false;
}
- if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) {
+ if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) {
return false;
}
/* libsecp256k1's ECDSA verification requires lower-S signatures, which have
* not historically been enforced in Bitcoin, so normalize them first. */
- secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig);
- return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey);
+ secp256k1_ecdsa_signature_normalize(secp256k1_context_static, &sig, &sig);
+ return secp256k1_ecdsa_verify(secp256k1_context_static, &sig, hash.begin(), &pubkey);
}
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
@@ -275,16 +280,15 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned cha
bool fComp = ((vchSig[0] - 27) & 4) != 0;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_recoverable_signature sig;
- assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
- if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) {
+ if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_static, &sig, &vchSig[1], recid)) {
return false;
}
- if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
+ if (!secp256k1_ecdsa_recover(secp256k1_context_static, &pubkey, &sig, hash.begin())) {
return false;
}
unsigned char pub[SIZE];
size_t publen = SIZE;
- secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
+ secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
}
@@ -293,21 +297,19 @@ bool CPubKey::IsFullyValid() const {
if (!IsValid())
return false;
secp256k1_pubkey pubkey;
- assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
- return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size());
+ return secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size());
}
bool CPubKey::Decompress() {
if (!IsValid())
return false;
secp256k1_pubkey pubkey;
- assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
- if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
+ if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
return false;
}
unsigned char pub[SIZE];
size_t publen = SIZE;
- secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
+ secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
}
@@ -320,16 +322,15 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild.begin(), out+32, 32);
secp256k1_pubkey pubkey;
- assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
- if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
+ if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
return false;
}
- if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {
+ if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_static, &pubkey, out)) {
return false;
}
unsigned char pub[COMPRESSED_SIZE];
size_t publen = COMPRESSED_SIZE;
- secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
+ secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
pubkeyChild.Set(pub, pub + publen);
return true;
}
@@ -375,35 +376,8 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
secp256k1_ecdsa_signature sig;
- assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
- if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) {
+ if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) {
return false;
}
- return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, nullptr, &sig));
-}
-
-/* static */ int ECCVerifyHandle::refcount = 0;
-
-ECCVerifyHandle::ECCVerifyHandle()
-{
- if (refcount == 0) {
- assert(secp256k1_context_verify == nullptr);
- secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
- assert(secp256k1_context_verify != nullptr);
- }
- refcount++;
-}
-
-ECCVerifyHandle::~ECCVerifyHandle()
-{
- refcount--;
- if (refcount == 0) {
- assert(secp256k1_context_verify != nullptr);
- secp256k1_context_destroy(secp256k1_context_verify);
- secp256k1_context_verify = nullptr;
- }
-}
-
-const secp256k1_context* GetVerifyContext() {
- return secp256k1_context_verify;
+ return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_static, nullptr, &sig));
}
diff --git a/src/pubkey.h b/src/pubkey.h
index 0485a38f72..b3edafea7f 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -330,21 +330,4 @@ struct CExtPubKey {
[[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild) const;
};
-/** Users of this module must hold an ECCVerifyHandle. The constructor and
- * destructor of these are not allowed to run in parallel, though. */
-class ECCVerifyHandle
-{
- static int refcount;
-
-public:
- ECCVerifyHandle();
- ~ECCVerifyHandle();
-};
-
-typedef struct secp256k1_context_struct secp256k1_context;
-
-/** Access to the internal secp256k1 context used for verification. Only intended to be used
- * by key.cpp. */
-const secp256k1_context* GetVerifyContext();
-
#endif // BITCOIN_PUBKEY_H
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index a82bd5f73e..b888fc43e2 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -64,7 +64,6 @@ protected:
AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) :
QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::AddressBookPage),
- model(nullptr),
mode(_mode),
tab(_tab)
{
diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h
index 144990f419..283209d00c 100644
--- a/src/qt/addressbookpage.h
+++ b/src/qt/addressbookpage.h
@@ -49,7 +49,7 @@ public Q_SLOTS:
private:
Ui::AddressBookPage *ui;
- AddressTableModel *model;
+ AddressTableModel* model{nullptr};
Mode mode;
Tabs tab;
QString returnValue;
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 8b5da7f9f0..e402c51ac4 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index f16700bfd9..0a96be038b 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -23,8 +23,6 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureStri
QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::AskPassphraseDialog),
mode(_mode),
- model(nullptr),
- fCapsLock(false),
m_passphrase_out(passphrase_out)
{
ui->setupUi(this);
@@ -91,11 +89,10 @@ void AskPassphraseDialog::accept()
oldpass.reserve(MAX_PASSPHRASE_SIZE);
newpass1.reserve(MAX_PASSPHRASE_SIZE);
newpass2.reserve(MAX_PASSPHRASE_SIZE);
- // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make this input mlock()'d to begin with.
- oldpass.assign(ui->passEdit1->text().toStdString().c_str());
- newpass1.assign(ui->passEdit2->text().toStdString().c_str());
- newpass2.assign(ui->passEdit3->text().toStdString().c_str());
+
+ oldpass.assign(std::string_view{ui->passEdit1->text().toStdString()});
+ newpass1.assign(std::string_view{ui->passEdit2->text().toStdString()});
+ newpass2.assign(std::string_view{ui->passEdit3->text().toStdString()});
secureClearPassFields();
@@ -156,8 +153,19 @@ void AskPassphraseDialog::accept()
case Unlock:
try {
if (!model->setWalletLocked(false, oldpass)) {
- QMessageBox::critical(this, tr("Wallet unlock failed"),
- tr("The passphrase entered for the wallet decryption was incorrect."));
+ // Check if the passphrase has a null character (see #27067 for details)
+ if (oldpass.find('\0') == std::string::npos) {
+ QMessageBox::critical(this, tr("Wallet unlock failed"),
+ tr("The passphrase entered for the wallet decryption was incorrect."));
+ } else {
+ QMessageBox::critical(this, tr("Wallet unlock failed"),
+ tr("The passphrase entered for the wallet decryption is incorrect. "
+ "It contains a null character (ie - a zero byte). "
+ "If the passphrase was set with a version of this software prior to 25.0, "
+ "please try again with only the characters up to — but not including — "
+ "the first null character. If this is successful, please set a new "
+ "passphrase to avoid this issue in the future."));
+ }
} else {
QDialog::accept(); // Success
}
@@ -176,8 +184,18 @@ void AskPassphraseDialog::accept()
}
else
{
- QMessageBox::critical(this, tr("Wallet encryption failed"),
- tr("The passphrase entered for the wallet decryption was incorrect."));
+ // Check if the old passphrase had a null character (see #27067 for details)
+ if (oldpass.find('\0') == std::string::npos) {
+ QMessageBox::critical(this, tr("Passphrase change failed"),
+ tr("The passphrase entered for the wallet decryption was incorrect."));
+ } else {
+ QMessageBox::critical(this, tr("Passphrase change failed"),
+ tr("The old passphrase entered for the wallet decryption is incorrect. "
+ "It contains a null character (ie - a zero byte). "
+ "If the passphrase was set with a version of this software prior to 25.0, "
+ "please try again with only the characters up to — but not including — "
+ "the first null character."));
+ }
}
}
else
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index 66031b08d3..370ea1de7e 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -38,8 +38,8 @@ public:
private:
Ui::AskPassphraseDialog *ui;
Mode mode;
- WalletModel *model;
- bool fCapsLock;
+ WalletModel* model{nullptr};
+ bool fCapsLock{false};
SecureString* m_passphrase_out;
private Q_SLOTS:
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 3d0be69302..4592d29abc 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -43,7 +43,7 @@ public:
/** Order (ascending or descending) to sort nodes by */
Qt::SortOrder sortOrder;
- /** Pull a full list of banned nodes from CNode into our cache */
+ /** Pull a full list of banned nodes from interfaces::Node into our cache */
void refreshBanlist(interfaces::Node& node)
{
banmap_t banMap;
@@ -178,3 +178,9 @@ bool BanTableModel::shouldShow()
{
return priv->size() > 0;
}
+
+bool BanTableModel::unban(const QModelIndex& index)
+{
+ CCombinedBan* ban{static_cast<CCombinedBan*>(index.internalPointer())};
+ return ban != nullptr && m_node.unban(ban->subnet);
+}
diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h
index 0a30905172..adb97ad1c0 100644
--- a/src/qt/bantablemodel.h
+++ b/src/qt/bantablemodel.h
@@ -37,7 +37,7 @@ private:
};
/**
- Qt model providing information about connected peers, similar to the
+ Qt model providing information about banned peers, similar to the
"getpeerinfo" RPC call. Used by the rpc console UI.
*/
class BanTableModel : public QAbstractTableModel
@@ -68,6 +68,8 @@ public:
bool shouldShow();
+ bool unban(const QModelIndex& index);
+
public Q_SLOTS:
void refresh();
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index cc01e4d54a..2c413e8b43 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,6 +9,7 @@
#include <qt/bitcoin.h>
#include <chainparams.h>
+#include <common/init.h>
#include <init.h>
#include <interfaces/handler.h>
#include <interfaces/init.h>
@@ -28,6 +29,7 @@
#include <qt/utilitydialog.h>
#include <qt/winshutdownmonitor.h>
#include <uint256.h>
+#include <util/exception.h>
#include <util/string.h>
#include <util/system.h>
#include <util/threadnames.h>
@@ -165,53 +167,36 @@ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTrans
}
}
-static bool InitSettings()
+static bool ErrorSettingsRead(const bilingual_str& error, const std::vector<std::string>& details)
{
- if (!gArgs.GetSettingsPath()) {
- return true; // Do nothing if settings file disabled.
- }
-
- std::vector<std::string> errors;
- if (!gArgs.ReadSettingsFile(&errors)) {
- std::string error = QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be read");
- std::string error_translated = QCoreApplication::translate("bitcoin-core", error.c_str()).toStdString();
- InitError(Untranslated(strprintf("%s:\n%s\n", error, MakeUnorderedList(errors))));
-
- QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error_translated)), QMessageBox::Reset | QMessageBox::Abort);
- /*: Explanatory text shown on startup when the settings file cannot be read.
- Prompts user to make a choice between resetting or aborting. */
- messagebox.setInformativeText(QObject::tr("Do you want to reset settings to default values, or to abort without making changes?"));
- messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(errors)));
- messagebox.setTextFormat(Qt::PlainText);
- messagebox.setDefaultButton(QMessageBox::Reset);
- switch (messagebox.exec()) {
- case QMessageBox::Reset:
- break;
- case QMessageBox::Abort:
- return false;
- default:
- assert(false);
- }
- }
-
- errors.clear();
- if (!gArgs.WriteSettingsFile(&errors)) {
- std::string error = QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be written");
- std::string error_translated = QCoreApplication::translate("bitcoin-core", error.c_str()).toStdString();
- InitError(Untranslated(strprintf("%s:\n%s\n", error, MakeUnorderedList(errors))));
-
- QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error_translated)), QMessageBox::Ok);
- /*: Explanatory text shown on startup when the settings file could not be written.
- Prompts user to check that we have the ability to write to the file.
- Explains that the user has the option of running without a settings file.*/
- messagebox.setInformativeText(QObject::tr("A fatal error occurred. Check that settings file is writable, or try running with -nosettings."));
- messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(errors)));
- messagebox.setTextFormat(Qt::PlainText);
- messagebox.setDefaultButton(QMessageBox::Ok);
- messagebox.exec();
+ QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Reset | QMessageBox::Abort);
+ /*: Explanatory text shown on startup when the settings file cannot be read.
+ Prompts user to make a choice between resetting or aborting. */
+ messagebox.setInformativeText(QObject::tr("Do you want to reset settings to default values, or to abort without making changes?"));
+ messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(details)));
+ messagebox.setTextFormat(Qt::PlainText);
+ messagebox.setDefaultButton(QMessageBox::Reset);
+ switch (messagebox.exec()) {
+ case QMessageBox::Reset:
return false;
+ case QMessageBox::Abort:
+ return true;
+ default:
+ assert(false);
}
- return true;
+}
+
+static void ErrorSettingsWrite(const bilingual_str& error, const std::vector<std::string>& details)
+{
+ QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Ok);
+ /*: Explanatory text shown on startup when the settings file could not be written.
+ Prompts user to check that we have the ability to write to the file.
+ Explains that the user has the option of running without a settings file.*/
+ messagebox.setInformativeText(QObject::tr("A fatal error occurred. Check that settings file is writable, or try running with -nosettings."));
+ messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(details)));
+ messagebox.setTextFormat(Qt::PlainText);
+ messagebox.setDefaultButton(QMessageBox::Ok);
+ messagebox.exec();
}
/* qDebug() message handler --> debug.log */
@@ -228,14 +213,8 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
static int qt_argc = 1;
static const char* qt_argv = "bitcoin-qt";
-BitcoinApplication::BitcoinApplication():
- QApplication(qt_argc, const_cast<char **>(&qt_argv)),
- optionsModel(nullptr),
- clientModel(nullptr),
- window(nullptr),
- pollShutdownTimer(nullptr),
- returnValue(0),
- platformStyle(nullptr)
+BitcoinApplication::BitcoinApplication()
+ : QApplication(qt_argc, const_cast<char**>(&qt_argv))
{
// Qt runs setlocale(LC_ALL, "") on initialization.
RegisterMetaTypes();
@@ -311,11 +290,7 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
{
assert(!m_splash);
m_splash = new SplashScreen(networkStyle);
- // We don't hold a direct pointer to the splash screen after creation, but the splash
- // screen will take care of deleting itself when finish() happens.
m_splash->show();
- connect(this, &BitcoinApplication::splashFinished, m_splash, &SplashScreen::finish);
- connect(this, &BitcoinApplication::requestedShutdown, m_splash, &QWidget::close);
}
void BitcoinApplication::createNode(interfaces::Init& init)
@@ -373,6 +348,9 @@ void BitcoinApplication::requestShutdown()
w->hide();
}
+ delete m_splash;
+ m_splash = nullptr;
+
// Show a simple window indicating shutdown status
// Do this first as some of the steps may take some time below,
// for example the RPC console may still be executing a command.
@@ -412,10 +390,13 @@ void BitcoinApplication::requestShutdown()
void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info)
{
qDebug() << __func__ << ": Initialization result: " << success;
+
// Set exit result.
returnValue = success ? EXIT_SUCCESS : EXIT_FAILURE;
- if(success)
- {
+ if(success) {
+ delete m_splash;
+ m_splash = nullptr;
+
// Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
qInfo() << "Platform customization:" << platformStyle->getName();
clientModel = new ClientModel(node(), optionsModel);
@@ -438,7 +419,6 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead
} else {
window->showMinimized();
}
- Q_EMIT splashFinished();
Q_EMIT windowShown(window);
#ifdef ENABLE_WALLET
@@ -455,7 +435,6 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead
#endif
pollShutdownTimer->start(SHUTDOWN_POLLING_DELAY);
} else {
- Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown
requestShutdown();
}
}
@@ -551,7 +530,7 @@ int GuiMain(int argc, char* argv[])
SetupUIArgs(gArgs);
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
- InitError(strprintf(Untranslated("Error parsing command line arguments: %s\n"), error));
+ InitError(strprintf(Untranslated("Error parsing command line arguments: %s"), error));
// Create a message box, because the gui has neither been created nor has subscribed to core signals
QMessageBox::critical(nullptr, PACKAGE_NAME,
// message cannot be translated because translations have not been initialized
@@ -592,33 +571,23 @@ int GuiMain(int argc, char* argv[])
// Gracefully exit if the user cancels
if (!Intro::showIfNeeded(did_show_intro, prune_MiB)) return EXIT_SUCCESS;
- /// 6. Determine availability of data directory and parse bitcoin.conf
- /// - Do not call gArgs.GetDataDirNet() before this step finishes
- if (!CheckDataDirOption()) {
- InitError(strprintf(Untranslated("Specified data directory \"%s\" does not exist.\n"), gArgs.GetArg("-datadir", "")));
- QMessageBox::critical(nullptr, PACKAGE_NAME,
- QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
- return EXIT_FAILURE;
- }
- if (!gArgs.ReadConfigFiles(error, true)) {
- InitError(strprintf(Untranslated("Error reading configuration file: %s\n"), error));
- QMessageBox::critical(nullptr, PACKAGE_NAME,
- QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error)));
- return EXIT_FAILURE;
- }
-
- /// 7. Determine network (and switch to network specific options)
+ /// 6-7. Parse bitcoin.conf, determine network, switch to network specific
+ /// options, and create datadir and settings.json.
+ // - Do not call gArgs.GetDataDirNet() before this step finishes
// - Do not call Params() before this step
- // - Do this after parsing the configuration file, as the network can be switched there
// - QSettings() will use the new application name after this, resulting in network-specific settings
// - Needs to be done before createOptionsModel
-
- // Check for chain settings (Params() calls are only valid after this clause)
- try {
- SelectParams(gArgs.GetChainName());
- } catch(std::exception &e) {
- InitError(Untranslated(strprintf("%s\n", e.what())));
- QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what()));
+ if (auto error = common::InitConfig(gArgs, ErrorSettingsRead)) {
+ InitError(error->message, error->details);
+ if (error->status == common::ConfigStatus::FAILED_WRITE) {
+ // Show a custom error message to provide more information in the
+ // case of a datadir write error.
+ ErrorSettingsWrite(error->message, error->details);
+ } else if (error->status != common::ConfigStatus::ABORTED) {
+ // Show a generic message in other cases, and no additional error
+ // message in the case of a read error if the user decided to abort.
+ QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(QString::fromStdString(error->message.translated)));
+ }
return EXIT_FAILURE;
}
#ifdef ENABLE_WALLET
@@ -626,10 +595,6 @@ int GuiMain(int argc, char* argv[])
PaymentServer::ipcParseCommandLine(argc, argv);
#endif
- if (!InitSettings()) {
- return EXIT_FAILURE;
- }
-
QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(Params().NetworkIDString()));
assert(!networkStyle.isNull());
// Allow for separate UI settings for testnets
diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h
index 9ad37ca6c9..9174e23de6 100644
--- a/src/qt/bitcoin.h
+++ b/src/qt/bitcoin.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -89,7 +89,6 @@ public Q_SLOTS:
Q_SIGNALS:
void requestedInitialize();
void requestedShutdown();
- void splashFinished();
void windowShown(BitcoinGUI* window);
protected:
@@ -97,16 +96,16 @@ protected:
private:
std::optional<InitExecutor> m_executor;
- OptionsModel *optionsModel;
- ClientModel *clientModel;
- BitcoinGUI *window;
- QTimer *pollShutdownTimer;
+ OptionsModel* optionsModel{nullptr};
+ ClientModel* clientModel{nullptr};
+ BitcoinGUI* window{nullptr};
+ QTimer* pollShutdownTimer{nullptr};
#ifdef ENABLE_WALLET
PaymentServer* paymentServer{nullptr};
WalletController* m_wallet_controller{nullptr};
#endif
- int returnValue;
- const PlatformStyle *platformStyle;
+ int returnValue{0};
+ const PlatformStyle* platformStyle{nullptr};
std::unique_ptr<QWidget> shutdownWindow;
SplashScreen* m_splash = nullptr;
std::unique_ptr<interfaces::Node> m_node;
diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc
index b6dca18be3..e90155b7a7 100644
--- a/src/qt/bitcoin_locale.qrc
+++ b/src/qt/bitcoin_locale.qrc
@@ -32,6 +32,7 @@
<file alias="gl">locale/bitcoin_gl.qm</file>
<file alias="gl_ES">locale/bitcoin_gl_ES.qm</file>
<file alias="gu">locale/bitcoin_gu.qm</file>
+ <file alias="ha">locale/bitcoin_ha.qm</file>
<file alias="he">locale/bitcoin_he.qm</file>
<file alias="hr">locale/bitcoin_hr.qm</file>
<file alias="hu">locale/bitcoin_hu.qm</file>
@@ -44,6 +45,7 @@
<file alias="kl">locale/bitcoin_kl.qm</file>
<file alias="km">locale/bitcoin_km.qm</file>
<file alias="ko">locale/bitcoin_ko.qm</file>
+ <file alias="ku">locale/bitcoin_ku.qm</file>
<file alias="ku_IQ">locale/bitcoin_ku_IQ.qm</file>
<file alias="ky">locale/bitcoin_ky.qm</file>
<file alias="la">locale/bitcoin_la.qm</file>
@@ -59,6 +61,7 @@
<file alias="ne">locale/bitcoin_ne.qm</file>
<file alias="nl">locale/bitcoin_nl.qm</file>
<file alias="no">locale/bitcoin_no.qm</file>
+ <file alias="pa">locale/bitcoin_pa.qm</file>
<file alias="pam">locale/bitcoin_pam.qm</file>
<file alias="pl">locale/bitcoin_pl.qm</file>
<file alias="pt">locale/bitcoin_pt.qm</file>
@@ -79,10 +82,13 @@
<file alias="ta">locale/bitcoin_ta.qm</file>
<file alias="te">locale/bitcoin_te.qm</file>
<file alias="th">locale/bitcoin_th.qm</file>
+ <file alias="tk">locale/bitcoin_tk.qm</file>
+ <file alias="tl">locale/bitcoin_tl.qm</file>
<file alias="tr">locale/bitcoin_tr.qm</file>
<file alias="ug">locale/bitcoin_ug.qm</file>
<file alias="uk">locale/bitcoin_uk.qm</file>
<file alias="ur">locale/bitcoin_ur.qm</file>
+ <file alias="uz">locale/bitcoin_uz.qm</file>
<file alias="uz@Cyrl">locale/bitcoin_uz@Cyrl.qm</file>
<file alias="uz@Latn">locale/bitcoin_uz@Latn.qm</file>
<file alias="vi">locale/bitcoin_vi.qm</file>
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index c92aecd095..a7e2d22488 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -217,9 +217,8 @@ Q_SIGNALS:
#include <qt/bitcoinamountfield.moc>
-BitcoinAmountField::BitcoinAmountField(QWidget *parent) :
- QWidget(parent),
- amount(nullptr)
+BitcoinAmountField::BitcoinAmountField(QWidget* parent)
+ : QWidget(parent)
{
amount = new AmountSpinBox(this);
amount->setLocale(QLocale::c());
diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
index a40cd38332..f710915a49 100644
--- a/src/qt/bitcoinamountfield.h
+++ b/src/qt/bitcoinamountfield.h
@@ -74,7 +74,7 @@ protected:
bool eventFilter(QObject *object, QEvent *event) override;
private:
- AmountSpinBox *amount;
+ AmountSpinBox* amount{nullptr};
QValueComboBox *unit;
private Q_SLOTS:
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 894a401e56..0eae7d3e79 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -410,7 +410,7 @@ void BitcoinGUI::createActions()
connect(action, &QAction::triggered, [this, path] {
auto activity = new OpenWalletActivity(m_wallet_controller, this);
- connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet);
+ connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet, Qt::QueuedConnection);
activity->open(path);
});
}
@@ -456,6 +456,7 @@ void BitcoinGUI::createActions()
m_wallet_controller->closeAllWallets(this);
});
connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::setPrivacy);
+ connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::enableHistoryAction);
}
#endif // ENABLE_WALLET
@@ -512,7 +513,7 @@ void BitcoinGUI::createMenuBar()
connect(minimize_action, &QAction::triggered, [] {
QApplication::activeWindow()->showMinimized();
});
- connect(qApp, &QApplication::focusWindowChanged, [minimize_action] (QWindow* window) {
+ connect(qApp, &QApplication::focusWindowChanged, this, [minimize_action] (QWindow* window) {
minimize_action->setEnabled(window != nullptr && (window->flags() & Qt::Dialog) != Qt::Dialog && window->windowState() != Qt::WindowMinimized);
});
@@ -527,7 +528,7 @@ void BitcoinGUI::createMenuBar()
}
});
- connect(qApp, &QApplication::focusWindowChanged, [zoom_action] (QWindow* window) {
+ connect(qApp, &QApplication::focusWindowChanged, this, [zoom_action] (QWindow* window) {
zoom_action->setEnabled(window != nullptr);
});
#endif
@@ -647,6 +648,8 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH
// initialize the disable state of the tray icon with the current value in the model.
trayIcon->setVisible(optionsModel->getShowTrayIcon());
}
+
+ m_mask_values_action->setChecked(_clientModel->getOptionsModel()->getOption(OptionsModel::OptionID::MaskValues).toBool());
} else {
if(trayIconMenu)
{
@@ -666,6 +669,12 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH
}
#ifdef ENABLE_WALLET
+void BitcoinGUI::enableHistoryAction(bool privacy)
+{
+ historyAction->setEnabled(!privacy);
+ if (historyAction->isChecked()) gotoOverviewPage();
+}
+
void BitcoinGUI::setWalletController(WalletController* wallet_controller)
{
assert(!m_wallet_controller);
@@ -714,7 +723,9 @@ void BitcoinGUI::addWallet(WalletModel* walletModel)
connect(wallet_view, &WalletView::encryptionStatusChanged, this, &BitcoinGUI::updateWalletStatus);
connect(wallet_view, &WalletView::incomingTransaction, this, &BitcoinGUI::incomingTransaction);
connect(this, &BitcoinGUI::setPrivacy, wallet_view, &WalletView::setPrivacy);
- wallet_view->setPrivacy(isPrivacyModeActivated());
+ const bool privacy = isPrivacyModeActivated();
+ wallet_view->setPrivacy(privacy);
+ enableHistoryAction(privacy);
const QString display_name = walletModel->getDisplayName();
m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel));
}
@@ -1071,7 +1082,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
statusBar()->clearMessage();
// Acquire current block source
- enum BlockSource blockSource = clientModel->getBlockSource();
+ BlockSource blockSource{clientModel->getBlockSource()};
switch (blockSource) {
case BlockSource::NETWORK:
if (synctype == SyncType::HEADER_PRESYNC) {
@@ -1091,9 +1102,6 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
progressBarLabel->setText(tr("Processing blocks on disk…"));
}
break;
- case BlockSource::REINDEX:
- progressBarLabel->setText(tr("Reindexing blocks on disk…"));
- break;
case BlockSource::NONE:
if (synctype != SyncType::BLOCK_SYNC) {
return;
@@ -1541,10 +1549,8 @@ bool BitcoinGUI::isPrivacyModeActivated() const
return m_mask_values_action->isChecked();
}
-UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle)
- : optionsModel(nullptr),
- menu(nullptr),
- m_platform_style{platformStyle}
+UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle* platformStyle)
+ : m_platform_style{platformStyle}
{
createContextMenu();
setToolTip(tr("Unit to show amounts in. Click to select another unit."));
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 912e9b95aa..92b889263b 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -288,6 +288,8 @@ public Q_SLOTS:
void gotoVerifyMessageTab(QString addr = "");
/** Load Partially Signed Bitcoin Transaction from file or clipboard */
void gotoLoadPSBT(bool from_clipboard = false);
+ /** Enable history action when privacy is changed */
+ void enableHistoryAction(bool privacy);
/** Show open dialog */
void openClicked();
@@ -333,8 +335,8 @@ protected:
void changeEvent(QEvent* e) override;
private:
- OptionsModel *optionsModel;
- QMenu* menu;
+ OptionsModel* optionsModel{nullptr};
+ QMenu* menu{nullptr};
const PlatformStyle* m_platform_style;
/** Shows context menu with Display Unit options by the mouse coordinates */
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 3df4d4d921..27aa39a024 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -15,8 +15,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"a backup."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"%s request to listen on port %u. This port is considered \"bad\" and thus it "
-"is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports."
-"md for details and a full list."),
+"is unlikely that any peer will connect to it. See doc/p2p-bad-ports.md for "
+"details and a full list."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"-maxtxfee is set very high! Fees this large could be paid on a single "
"transaction."),
@@ -33,9 +33,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"temporarily disable txindex while using -reindex-chainstate, or replace -"
"reindex-chainstate with -reindex to fully rebuild all indexes."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Assumed-valid: last wallet synchronisation goes beyond available block data. "
-"You need to wait for the background validation chain to download more blocks."),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot downgrade wallet from version %i to version %i. Wallet version "
"unchanged."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -48,12 +45,20 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"upgrading to support pre-split keypool. Please use version %i or no version "
"specified."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Disk space for %s may not accommodate the block files. Approximately %u GB "
+"of data will be stored in this directory."),
+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: External signer wallet being loaded without external "
"signer support compiled"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Error loading wallet. Wallet requires blocks to be downloaded, and software "
+"does not currently support loading wallets while blocks are being downloaded "
+"out of order when using assumeutxo snapshots. Wallet should be able to load "
+"successfully after node sync reaches height %s"),
+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", ""
@@ -79,8 +84,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: Transaction %s in wallet cannot be identified to belong to migrated "
"wallets"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Error: Unable to produce descriptors for this legacy wallet. Make sure the "
-"wallet is unlocked first"),
+"Error: Unable to produce descriptors for this legacy wallet. Make sure to "
+"provide the wallet's passphrase if it is encrypted."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Failed to rename invalid peers.dat file. Please move or delete it and try "
"again."),
@@ -112,6 +117,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"No wallet file format provided. To use createfromdump, -format=<format> must "
"be provided."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Outbound connections restricted to CJDNS (-onlynet=cjdns) but -"
+"cjdnsreachable is not provided"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
"reaching the Tor network is explicitly forbidden: -onion=0"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -119,6 +127,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"reaching the Tor network is not provided: none of -proxy, -onion or -"
"listenonion is given"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not "
+"provided"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Please check that your computer's date and time are correct! If your clock "
"is wrong, %s will not work properly."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -148,6 +159,13 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"space, run a full -reindex, otherwise ignore this error. This error message "
"will not be displayed again."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"The inputs size exceeds the maximum weight. Please try sending a smaller "
+"amount or manually consolidating your wallet's UTXOs"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"The preselected coins total amount does not cover the transaction target. "
+"Please allow other inputs to be automatically selected or include more coins "
+"manually"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"The transaction amount is too small to send after the fee has been deducted"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"This error could occur if this wallet was not shutdown cleanly and was last "
@@ -171,6 +189,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to replay blocks. You will need to rebuild the database using -"
"reindex-chainstate."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n"
+"\n"
+"The wallet might have been tampered with or created with malicious intent.\n"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unknown wallet file format \"%s\" provided. Please provide one of \"bdb\" or "
"\"sqlite\"."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -235,6 +257,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading next record from wallet database"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Cannot extract destination from the generated scriptpubkey"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Could not add watchonly tx to watchonly wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Could not delete watchonly transactions"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Couldn't create cursor into database"),
@@ -264,6 +287,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Importing…"),
QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"),
QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Input not found or already spent"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient dbcache for block verification"),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -i2psam address or hostname: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"),
@@ -274,6 +298,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -discardfee=<amount>: '%s'
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -fallbackfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid port specified in %s: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid pre-selected input %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listening for incoming connections failed (listen returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading P2P addresses…"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist…"),
@@ -284,6 +310,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Missing solving data for estimating transacti
QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "No addresses available"),
QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Not found pre-selected input %s"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Not solvable pre-selected input %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune cannot be configured with a negative value."),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -txindex."),
QT_TRANSLATE_NOOP("bitcoin-core", "Pruning blockstore…"),
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 092ffe7e5b..8411ec4696 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -34,8 +34,6 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO
QObject(parent),
m_node(node),
optionsModel(_optionsModel),
- peerTableModel(nullptr),
- banTableModel(nullptr),
m_thread(new QThread(this))
{
cachedBestHeaderHeight = -1;
@@ -148,15 +146,10 @@ uint256 ClientModel::getBestBlockHash()
return m_cached_tip_blocks;
}
-enum BlockSource ClientModel::getBlockSource() const
+BlockSource ClientModel::getBlockSource() const
{
- if (m_node.getReindex())
- return BlockSource::REINDEX;
- else if (m_node.getImporting())
- return BlockSource::DISK;
- else if (getNumConnections() > 0)
- return BlockSource::NETWORK;
-
+ if (m_node.isLoadingBlocks()) return BlockSource::DISK;
+ if (getNumConnections() > 0) return BlockSource::NETWORK;
return BlockSource::NONE;
}
@@ -287,7 +280,7 @@ bool ClientModel::getProxyInfo(std::string& ip_port) const
{
Proxy ipv4, ipv6;
if (m_node.getProxy((Network) 1, ipv4) && m_node.getProxy((Network) 2, ipv6)) {
- ip_port = ipv4.proxy.ToStringIPPort();
+ ip_port = ipv4.proxy.ToStringAddrPort();
return true;
}
return false;
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 4a6abd6a76..493e18a07d 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -32,9 +32,8 @@ QT_END_NAMESPACE
enum class BlockSource {
NONE,
- REINDEX,
DISK,
- NETWORK
+ NETWORK,
};
enum class SyncType {
@@ -72,8 +71,8 @@ public:
int getHeaderTipHeight() const;
int64_t getHeaderTipTime() const;
- //! Returns enum BlockSource of the current importing/syncing state
- enum BlockSource getBlockSource() const;
+ //! Returns the block source of the current importing/syncing state
+ BlockSource getBlockSource() const;
//! Return warnings to be displayed in status bar
QString getStatusBarWarnings() const;
@@ -104,9 +103,9 @@ private:
std::unique_ptr<interfaces::Handler> m_handler_notify_block_tip;
std::unique_ptr<interfaces::Handler> m_handler_notify_header_tip;
OptionsModel *optionsModel;
- PeerTableModel *peerTableModel;
+ PeerTableModel* peerTableModel{nullptr};
PeerTableSortProxy* m_peer_table_sort_proxy{nullptr};
- BanTableModel *banTableModel;
+ BanTableModel* banTableModel{nullptr};
//! A thread to interact with m_node asynchronously
QThread* const m_thread;
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index bd9a90a890..e1b1ae12e9 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -477,7 +477,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *
nBytes -= 34;
// Fee
- nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, nullptr /* returned_target */, nullptr /* reason */);
+ nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, /*returned_target=*/nullptr, /*reason=*/nullptr);
if (nPayAmount > 0)
{
diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp
index 656afb6e87..445ea41475 100644
--- a/src/qt/csvmodelwriter.cpp
+++ b/src/qt/csvmodelwriter.cpp
@@ -8,9 +8,9 @@
#include <QFile>
#include <QTextStream>
-CSVModelWriter::CSVModelWriter(const QString &_filename, QObject *parent) :
- QObject(parent),
- filename(_filename), model(nullptr)
+CSVModelWriter::CSVModelWriter(const QString& _filename, QObject* parent)
+ : QObject(parent),
+ filename(_filename)
{
}
diff --git a/src/qt/csvmodelwriter.h b/src/qt/csvmodelwriter.h
index ad247b6859..a1e77826a8 100644
--- a/src/qt/csvmodelwriter.h
+++ b/src/qt/csvmodelwriter.h
@@ -32,7 +32,7 @@ public:
private:
QString filename;
- const QAbstractItemModel *model;
+ const QAbstractItemModel* model{nullptr};
struct Column
{
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index fa27635981..9b3319415d 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -12,12 +12,10 @@
#include <QMessageBox>
-EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) :
- QDialog(parent, GUIUtil::dialog_flags),
- ui(new Ui::EditAddressDialog),
- mapper(nullptr),
- mode(_mode),
- model(nullptr)
+EditAddressDialog::EditAddressDialog(Mode _mode, QWidget* parent)
+ : QDialog(parent, GUIUtil::dialog_flags),
+ ui(new Ui::EditAddressDialog),
+ mode(_mode)
{
ui->setupUi(this);
diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h
index f7ad80bb2d..7bfadcfbcc 100644
--- a/src/qt/editaddressdialog.h
+++ b/src/qt/editaddressdialog.h
@@ -49,9 +49,9 @@ private:
QString getDuplicateAddressWarning() const;
Ui::EditAddressDialog *ui;
- QDataWidgetMapper *mapper;
+ QDataWidgetMapper* mapper{nullptr};
Mode mode;
- AddressTableModel *model;
+ AddressTableModel* model{nullptr};
QString address;
};
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index ead977296a..f1b66341d1 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -1185,10 +1185,10 @@
<item row="6" column="0">
<widget class="QLabel" name="peerRelayTxesLabel">
<property name="toolTip">
- <string>Whether the peer requested us to relay transactions.</string>
+ <string>Whether we relay transactions to this peer.</string>
</property>
<property name="text">
- <string>Wants Tx Relay</string>
+ <string>Transaction Relay</string>
</property>
</widget>
</item>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 582f02132a..6be47e94fe 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -286,7 +286,7 @@
<item>
<widget class="QLineEdit" name="externalSignerPath">
<property name="toolTip">
- <string>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</string>
+ <string>Full path to a %1 compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</string>
</property>
</widget>
</item>
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index fcdf6056c9..0f76770772 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index b9f0be41e3..83c78d5c18 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,6 +20,7 @@
#include <protocol.h>
#include <script/script.h>
#include <script/standard.h>
+#include <util/exception.h>
#include <util/system.h>
#include <util/time.h>
@@ -428,7 +429,7 @@ void openDebugLogfile()
bool openBitcoinConf()
{
- fs::path pathConfig = GetConfigFile(gArgs.GetPathArg("-conf", BITCOIN_CONF_FILENAME));
+ fs::path pathConfig = gArgs.GetConfigFilePath();
/* Create the file */
std::ofstream configFile{pathConfig, std::ios_base::app};
@@ -615,9 +616,10 @@ bool SetStartOnSystemStartup(bool fAutoStart)
else
{
char pszExePath[MAX_PATH+1];
- ssize_t r = readlink("/proc/self/exe", pszExePath, sizeof(pszExePath) - 1);
- if (r == -1)
+ ssize_t r = readlink("/proc/self/exe", pszExePath, sizeof(pszExePath));
+ if (r == -1 || r > MAX_PATH) {
return false;
+ }
pszExePath[r] = '\0';
fs::create_directories(GetAutostartDir());
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index acbe415a91..87a323bde9 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/initexecutor.cpp b/src/qt/initexecutor.cpp
index d269dfec71..bb3f970b55 100644
--- a/src/qt/initexecutor.cpp
+++ b/src/qt/initexecutor.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2014-2021 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <qt/initexecutor.h>
#include <interfaces/node.h>
-#include <util/system.h>
+#include <util/exception.h>
#include <util/threadnames.h>
#include <exception>
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 4c8b33bf28..12aa02340a 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -122,8 +122,6 @@ int GetPruneTargetGB()
Intro::Intro(QWidget *parent, int64_t blockchain_size_gb, int64_t chain_state_size_gb) :
QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::Intro),
- thread(nullptr),
- signalled(false),
m_blockchain_size_gb(blockchain_size_gb),
m_chain_state_size_gb(chain_state_size_gb),
m_prune_target_gb{GetPruneTargetGB()}
diff --git a/src/qt/intro.h b/src/qt/intro.h
index d9c45007e1..900c657b27 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -64,9 +64,9 @@ private Q_SLOTS:
private:
Ui::Intro *ui;
- QThread *thread;
+ QThread* thread{nullptr};
QMutex mutex;
- bool signalled;
+ bool signalled{false};
QString pathToCheck;
const int64_t m_blockchain_size_gb;
const int64_t m_chain_state_size_gb;
diff --git a/src/qt/locale/bitcoin_am.ts b/src/qt/locale/bitcoin_am.ts
index 09462a2703..b836bd7dfd 100644
--- a/src/qt/locale/bitcoin_am.ts
+++ b/src/qt/locale/bitcoin_am.ts
@@ -359,6 +359,11 @@
<translation type="unfinished">መደበኛ ዋሌት</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">ዋሌት ስáˆ</translation>
+ </message>
+ <message>
<source>Zoom</source>
<translation type="unfinished">እሳድáŒ</translation>
</message>
@@ -484,6 +489,27 @@
<translation type="unfinished">ቢትኮይን</translation>
</message>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts
index 1b4b088647..f29b889398 100644
--- a/src/qt/locale/bitcoin_ar.ts
+++ b/src/qt/locale/bitcoin_ar.ts
@@ -3,140 +3,145 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">أنقر بزر الماوس الأيمن لتحرير العنوان أو التصنيÙ</translation>
+ <translation type="unfinished">انقر بزر الÙأرة الأيمن لتحرير العنوان أو المذكرة</translation>
</message>
<message>
<source>Create a new address</source>
- <translation type="unfinished">إنشاء عنوان جديد</translation>
+ <translation type="unfinished">أنشئ عنوان جديد</translation>
</message>
<message>
<source>&amp;New</source>
- <translation type="unfinished">جديد</translation>
+ <translation type="unfinished">&amp;جديد</translation>
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation type="unfinished">نسخ العنوان المحدد حاليًا إلى حاÙظة النظام</translation>
+ <translation type="unfinished">‫انسخ العنوان المحدد للحاÙظة‬</translation>
</message>
<message>
<source>&amp;Copy</source>
- <translation type="unfinished">نسخ</translation>
+ <translation type="unfinished">&amp;نسخ</translation>
</message>
<message>
<source>C&amp;lose</source>
- <translation type="unfinished">غلق</translation>
+ <translation type="unfinished">ا&amp;غلاق</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation type="unfinished">احذ٠العنوان المحدد حاليًا من القائمة</translation>
+ <translation type="unfinished">احذ٠العنوان المحدد من القائمة</translation>
</message>
<message>
<source>Enter address or label to search</source>
- <translation type="unfinished">أدخل العنوان أو التصني٠للبحث</translation>
+ <translation type="unfinished">أدخل عنوانا أو مذكرة للبحث</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation type="unfinished">استخراج البيانات ÙÙŠ علامة التبويب الحالية إلى ملÙ</translation>
+ <translation type="unfinished">صدّر البيانات ÙÙŠ التبويب الحالي الى ملÙ</translation>
</message>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">استخراج</translation>
+ <translation type="unfinished">&amp;تصدير</translation>
</message>
<message>
<source>&amp;Delete</source>
- <translation type="unfinished">حذÙ</translation>
+ <translation type="unfinished">&amp;حذÙ</translation>
</message>
<message>
<source>Choose the address to send coins to</source>
- <translation type="unfinished">إختر العنوان الرقمي اللذي تريد الإرسال له</translation>
+ <translation type="unfinished">اختر العنوان الذي ترغب بارسال بتكوين اليه</translation>
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation type="unfinished">إختر العنوان الرقمي اللذي سيحصل على العملات</translation>
+ <translation type="unfinished">اختر العنوان الذي ترغب باستلام بتكوين اليه</translation>
</message>
<message>
<source>C&amp;hoose</source>
- <translation type="unfinished">اختر</translation>
+ <translation type="unfinished">ا&amp;ختر</translation>
</message>
<message>
<source>Sending addresses</source>
- <translation type="unfinished">العنوان الرقمي المÙرسÙÙ„</translation>
+ <translation type="unfinished">‫العناوين المرسÙلة‬</translation>
</message>
<message>
<source>Receiving addresses</source>
- <translation type="unfinished">العنوان الرقمي المÙرسَل إليه</translation>
+ <translation type="unfinished">العناوين المستلمة</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 type="unfinished">هذه هي عناوين البيتكوين لإرسال المدÙوعات. دائما تحقق من المبلغ وعنوان المستلم قبل الإرسال.</translation>
+ <translation type="unfinished">‫هذه عناوين البتكوين الخاصة بك لإرسال المدÙوعات. تأكد دائما من القيم المدخلة ومن العنوان المستلم قبل الارسال.‬</translation>
</message>
<message>
<source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
Signing is only possible with addresses of the type 'legacy'.</source>
- <translation type="unfinished">هذه هي عناوين بتكوين الخاصة بك لتلقي المدÙوعات. استخدم الزر "إنشاء عنوان استلام جديد" ÙÙŠ علامة تبويب الاستلام لإنشاء عناوين جديدة.
-التوقيع ممكن Ùقط مع عناوين من النوع "قديم".</translation>
+ <translation type="unfinished">هذه عناوين البتكوين الخاصة بك لاستلام المدÙوعات. قم بالنقر على زر انشاء عنوان استلام جديد لإنشاء عناوين جديدة.
+التوقيع ممكن باستخدام العناوين القديمة "Legacy" Ùقط.</translation>
</message>
<message>
<source>&amp;Copy Address</source>
- <translation type="unfinished">نسخ العنوان</translation>
+ <translation type="unfinished">&amp;نسخ العنوان</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation type="unfinished">نسخ&amp;تسمية</translation>
+ <translation type="unfinished">نسخ &amp;المذكرة</translation>
</message>
<message>
<source>&amp;Edit</source>
- <translation type="unfinished">تحرير</translation>
+ <translation type="unfinished">&amp;تحرير</translation>
</message>
<message>
<source>Export Address List</source>
- <translation type="unfinished">صدّر قائمة العناوين</translation>
+ <translation type="unfinished">تصدير قائمة العناوين</translation>
</message>
<message>
<source>Comma separated file</source>
<extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
- <translation type="unfinished">مل٠مÙصَّل بالÙواصل</translation>
+ <translation type="unfinished">مل٠القيم المÙصولة بÙاصلة</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
+ <translation type="unfinished">حدث خطأ أثناء محاولة Ø­Ùظ قائمة العناوين ÙÙŠ %1. يرجى معاودة المحاولة. </translation>
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished">لقد Ùشل التصدير</translation>
+ <translation type="unfinished">Ùشل التصدير</translation>
</message>
</context>
<context>
<name>AddressTableModel</name>
<message>
<source>Label</source>
- <translation type="unfinished">وسم</translation>
+ <translation type="unfinished">المذكرة</translation>
</message>
<message>
<source>Address</source>
- <translation type="unfinished">عنوان</translation>
+ <translation type="unfinished">العنوان</translation>
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(بدون وسم)</translation>
+ <translation type="unfinished">( لا وجود لمذكرة)</translation>
</message>
</context>
<context>
<name>AskPassphraseDialog</name>
<message>
<source>Passphrase Dialog</source>
- <translation type="unfinished">مربع كلمة المرور</translation>
+ <translation type="unfinished">‫حوار عبارة المرور‬</translation>
</message>
<message>
<source>Enter passphrase</source>
- <translation type="unfinished">ادخل كلمة المرور</translation>
+ <translation type="unfinished">‫ادخل عبارة المرور‬</translation>
</message>
<message>
<source>New passphrase</source>
- <translation type="unfinished">كلمة مرور جديد</translation>
+ <translation type="unfinished">‫أنشئ عبارة مرور‬</translation>
</message>
<message>
<source>Repeat new passphrase</source>
- <translation type="unfinished">إعادة إدخال كلمة المرور</translation>
+ <translation type="unfinished">‫أعد عبارة المرور‬</translation>
</message>
<message>
<source>Show passphrase</source>
- <translation type="unfinished">أظهر كلمة المرور</translation>
+ <translation type="unfinished">‫عرض عبارة المرور‬</translation>
</message>
<message>
<source>Encrypt wallet</source>
@@ -144,15 +149,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation type="unfinished">العملية تحتاج كملة المرور المحÙظة لتستطيع Ùتحها.</translation>
+ <translation type="unfinished">‫هذه العملية تتطلب عبارة المرور Ù„ÙÙƒ تشÙير المحÙظة.‬</translation>
</message>
<message>
<source>Unlock wallet</source>
- <translation type="unfinished">Ùتح المحÙظة</translation>
+ <translation type="unfinished">Ùتح Ù‚ÙÙ„ المحÙظة</translation>
</message>
<message>
<source>Change passphrase</source>
- <translation type="unfinished">تغيير كلمة المرور</translation>
+ <translation type="unfinished">‫تغيير عبارة المرور‬</translation>
</message>
<message>
<source>Confirm wallet encryption</source>
@@ -160,47 +165,47 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">إذا Ø´Ùرت محÙظتك ÙˆÙقدت كلمة المرور، ستÙقد كل ما تملك من البيتكوين.</translation>
+ <translation type="unfinished">تحذير: إذا قمت بتشÙير المحÙظة وأضعت الكلمة السرية؛ &lt;b&gt;ستÙقد كل البتكوين&lt;/b&gt;!</translation>
</message>
<message>
<source>Are you sure you wish to encrypt your wallet?</source>
- <translation type="unfinished">هل انت متأكد بأنك تريد تشÙير محÙظتك؟</translation>
+ <translation type="unfinished">هل أنت متأكد من رغبتك ÙÙŠ تشÙير المحÙظة؟</translation>
</message>
<message>
<source>Wallet encrypted</source>
- <translation type="unfinished">تم تشÙير المحÙظة</translation>
+ <translation type="unfinished">المحÙظة مشÙرة</translation>
</message>
<message>
<source>Enter the new passphrase for 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 type="unfinished">أدخل كلمة المرور الجديدة للمحÙظة. &lt;br/&gt; الرجاء استخدام كلمة مرور تتكون من &lt;b&gt; عشرة أحر٠عشوائية أو أكثر &lt;/b&gt; ØŒ أو &lt;b&gt; ثماني كلمات أو أكثر&lt;/b&gt; .</translation>
+ <translation type="unfinished">أدخل عبارة المرور للمحÙظة. &lt;br/&gt;الرجاء استخدام عبارة مرور تتكون من &lt;b&gt;عشر خانات عشوائية أو أكثر&lt;/b&gt;ØŒ أو &lt;b&gt;ثمان كلمات أو أكثر&lt;/b&gt;.</translation>
</message>
<message>
<source>Enter the old passphrase and new passphrase for the wallet.</source>
- <translation type="unfinished">ادخل كملة المرور القديمة وكلمة المرور الجديدة للمحÙظة.</translation>
+ <translation type="unfinished">أدخل ‫عبارة المرور‬ السابقة و‫عبارة المرور‬ الجديدة للمحÙظة</translation>
</message>
<message>
<source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
- <translation type="unfinished">تذكر أن تشÙير محÙظتك لا يحمي البيتكوين الخاصة بك بشكل كامل من السرقة من قبل البرامج الخبيثةالتي تصيب حاسوبك</translation>
+ <translation type="unfinished">تذكر أن تشÙير محÙظتك قد لا يحميك بشكل كامل من البرمجيات الخبيثة التي تصيب جهازك.</translation>
</message>
<message>
<source>Wallet to be encrypted</source>
- <translation type="unfinished">سو٠يتم تشÙير محÙظتك</translation>
+ <translation type="unfinished">‫المحÙظة سيتم تشÙيرها‬</translation>
</message>
<message>
<source>Your wallet is about to be encrypted. </source>
- <translation type="unfinished">سو٠يتم تشÙير محÙظتك.</translation>
+ <translation type="unfinished">سو٠تشÙر محÙظتك.</translation>
</message>
<message>
<source>Your wallet is now encrypted. </source>
- <translation type="unfinished">محÙظتك ألان مشÙرة</translation>
+ <translation type="unfinished">محÙظتك الان مشÙرة.</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 type="unfinished">هام: أي نسخة إحتياطية سابقة قمت بها لمحÙظتك يجب استبدالها بأخرى حديثة، مشÙرة. لأسباب أمنية، النسخ الاحتياطية السابقة لملÙات المحÙظة الغير مشÙرة تصبح عديمة الÙائدة مع بداية استخدام المحÙظة المشÙرة الجديدة.</translation>
+ <translation type="unfinished">مهم!!!: يجب استبدال أي نسخة احتياطية سابقة بمل٠المحÙظة المشÙر الجديد. لأسباب أمنية، لن تستطيع استخدام النسخ الاحتياطية السابقة الغير مشÙرة عندما تبدأ ÙÙŠ استخدام المحÙظة المشÙرة الجديدة.</translation>
</message>
<message>
<source>Wallet encryption failed</source>
- <translation type="unfinished">خطأ ÙÙŠ تشÙير المحÙظة</translation>
+ <translation type="unfinished">Ùشل تشÙير المحÙظة</translation>
</message>
<message>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
@@ -208,7 +213,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The supplied passphrases do not match.</source>
- <translation type="unfinished">كلمتي المرور ليستا متطابقتان</translation>
+ <translation type="unfinished">عبارتي مرور غير متطابقتين.</translation>
</message>
<message>
<source>Wallet unlock failed</source>
@@ -216,22 +221,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The passphrase entered for the wallet decryption was incorrect.</source>
- <translation type="unfinished">كلمة المرور التي تم إدخالها Ù„ÙÙƒ تشÙير المحÙظة غير صحيحة.</translation>
+ <translation type="unfinished">‫عبارة المرور التي تم إدخالها Ù„ÙÙƒ تشÙير المحÙظة غير صحيحة.‬</translation>
</message>
<message>
<source>Wallet passphrase was successfully changed.</source>
- <translation type="unfinished">لقد تم تغير عبارة مرور المحÙظة بنجاح</translation>
+ <translation type="unfinished">‫لقد تم تغيير عبارة المرور بنجاح.‬</translation>
</message>
<message>
<source>Warning: The Caps Lock key is on!</source>
- <translation type="unfinished">تحذير: Ù…Ùتاح الحرو٠الكبيرة Ù…Ùعل</translation>
+ <translation type="unfinished">‫تحذير: Ù…Ùتاح الحرو٠الكبيرة Ù…Ùعل!‬</translation>
</message>
</context>
<context>
<name>BanTableModel</name>
<message>
<source>IP/Netmask</source>
- <translation type="unfinished">عنوان البروتوكول/قناع</translation>
+ <translation type="unfinished">‫بروتوكول الانترنت/قناع الشبكة‬</translation>
</message>
<message>
<source>Banned Until</source>
@@ -241,8 +246,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">مل٠الاعدادات %1 قد يكون تال٠او غير صالح</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
- <translation type="unfinished">استثناء هارب</translation>
+ <translation type="unfinished">‫‫Runaway exception‬</translation>
</message>
<message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
@@ -252,12 +261,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Internal error</source>
<translation type="unfinished">خطأ داخلي</translation>
</message>
- </context>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">حدث خطأ داخلي. سيحاول %1 المتابعة بأمان. هذا خطأ غير متوقع يمكن الإبلاغ عنه كما هو موضح أدناه.</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">‫هل تريد اعادة ضبط الاعدادات للقيم الاÙتراضية؟ أو الالغاء دون اجراء تغييرات؟‬</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">‫حدث خطأ Ùادح. تأكد أن أذونات مل٠الاعدادات تسمح بالكتابة، جرب الاستمرار بتÙعيل خيار -دون اعدادات.‬</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
- <translation type="unfinished">خطأ: دليل البيانات المحدد "%1" غير موجود.</translation>
+ <translation type="unfinished">‫خطأ: المجلد المحدد "%1" غير موجود.‬</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">‫خطأ: لا يمكن تحليل مل٠الإعداد: %1.‬</translation>
</message>
<message>
<source>Error: %1</source>
@@ -265,7 +292,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>%1 didn't yet exit safely…</source>
- <translation type="unfinished">%1 لم يخرج بامان بعد</translation>
+ <translation type="unfinished">‫%1 لم يغلق بامان بعد…‬</translation>
</message>
<message>
<source>unknown</source>
@@ -273,7 +300,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Amount</source>
- <translation type="unfinished">مبلغ</translation>
+ <translation type="unfinished">‫القيمة‬</translation>
</message>
<message>
<source>Enter a Bitcoin address (e.g. %1)</source>
@@ -281,7 +308,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unroutable</source>
- <translation type="unfinished">غير قابل للطرق</translation>
+ <translation type="unfinished">‫غير قابل للتوجيه‬</translation>
</message>
<message>
<source>Internal</source>
@@ -290,22 +317,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Inbound</source>
<extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
- <translation type="unfinished">داخل</translation>
+ <translation type="unfinished">‫وارد‬</translation>
</message>
<message>
<source>Outbound</source>
<extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment>
- <translation type="unfinished">خارجي</translation>
+ <translation type="unfinished">‫صادر‬</translation>
</message>
<message>
<source>Full Relay</source>
<extracomment>Peer connection type that relays all network information.</extracomment>
- <translation type="unfinished">تتابع كامل</translation>
+ <translation type="unfinished">‫موصل كامل‬</translation>
</message>
<message>
<source>Block Relay</source>
<extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment>
- <translation type="unfinished">بلوك ريلاي</translation>
+ <translation type="unfinished">‫موصل طابق‬</translation>
</message>
<message>
<source>Manual</source>
@@ -315,12 +342,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Feeler</source>
<extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment>
- <translation type="unfinished">المحسس</translation>
+ <translation type="unfinished">‫تÙقدي‬</translation>
</message>
<message>
<source>Address Fetch</source>
<extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
- <translation type="unfinished">إحضار العنوان</translation>
+ <translation type="unfinished">‫جلب العنوان‬</translation>
</message>
<message>
<source>%1 d</source>
@@ -353,56 +380,56 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n second(s)</numerusform>
+ <numerusform>%n second(s)</numerusform>
+ <numerusform>%n second(s)</numerusform>
+ <numerusform>%n second(s)</numerusform>
+ <numerusform>%n second(s)</numerusform>
+ <numerusform>%n‫‫ ثواني‬</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n minute(s)</numerusform>
+ <numerusform>%n minute(s)</numerusform>
+ <numerusform>%n minute(s)</numerusform>
+ <numerusform>%n minute(s)</numerusform>
+ <numerusform>%n minute(s)</numerusform>
+ <numerusform>%n ‫دقائق‬</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n hour(s)</numerusform>
+ <numerusform>%n hour(s)</numerusform>
+ <numerusform>%n hour(s)</numerusform>
+ <numerusform>%n hour(s)</numerusform>
+ <numerusform>%n hour(s)</numerusform>
+ <numerusform>%n‫ساعات‬</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n day(s)</numerusform>
+ <numerusform>%n day(s)</numerusform>
+ <numerusform>%n day(s)</numerusform>
+ <numerusform>%n day(s)</numerusform>
+ <numerusform>%n day(s)</numerusform>
+ <numerusform>%n ‫أيام‬</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n week(s)</numerusform>
+ <numerusform>%n week(s)</numerusform>
+ <numerusform>%n week(s)</numerusform>
+ <numerusform>%n week(s)</numerusform>
+ <numerusform>%n week(s)</numerusform>
+ <numerusform>%n ‫أسابيع‬</numerusform>
</translation>
</message>
<message>
@@ -412,12 +439,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n year(s)</numerusform>
+ <numerusform>%n year(s)</numerusform>
+ <numerusform>%n year(s)</numerusform>
+ <numerusform>%n year(s)</numerusform>
+ <numerusform>%n year(s)</numerusform>
+ <numerusform>%n ‫سنوات‬</numerusform>
</translation>
</message>
<message>
@@ -430,38 +457,62 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>%1 MB</source>
- <translation type="unfinished">%1 ميقا بايت</translation>
+ <translation type="unfinished">%1 ‫ميجابايت‬</translation>
</message>
<message>
<source>%1 GB</source>
- <translation type="unfinished">%1 قيقا بايت</translation>
+ <translation type="unfinished">%1 ‫جيجابايت‬</translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">‫مل٠الاعدادات لا يمكن قراءته‬</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">‫لم نتمكن من كتابة مل٠الاعدادات‬</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">%s المبرمجون</translation>
</message>
<message>
+ <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
+ <translation type="unfinished">‫‫%s مشكل. حاول استخدام أداة محÙظة البتكوين للاصلاح أو استعادة نسخة احتياطية.‬</translation>
+ </message>
+ <message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <translation type="unfinished">-maxtxfee الموضوع عالي جدا! رسوم بهذا الحجم من الممكن أن تدÙع على معاملة.</translation>
+ <translation type="unfinished">‫الحد الأعلى للرسوم عال جدا! رسوم بهذه الكمية تكÙÙŠ لإرسال عملية كاملة.‬</translation>
+ </message>
+ <message>
+ <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
+ <translation type="unfinished">‫لا يمكن استرجاع إصدار المحÙظة من %i الى %i. لم يتغير إصدار المحÙظة.‬</translation>
</message>
<message>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
- <translation type="unfinished">لا يمكن الحصول على Ù‚ÙÙ„ على دليل البيانات %s. من المحتمل أن %s يعمل بالÙعل.</translation>
+ <translation type="unfinished">‫لا يمكن اقÙال المجلد %s. من المحتمل أن %s يعمل بالÙعل.‬</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation type="unfinished">موزع بموجب ترخيص برامج MIT ، راجع المل٠المصاحب %s أو %s</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 type="unfinished">خطأ ÙÙŠ قراءة %s! جميع المÙاتيح قرأت بشكل صحيح، لكن بيانات المعاملة أو إدخالات سجل العناوين قد تكون Ù…Ùقودة أو غير صحيحة.</translation>
</message>
<message>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">‫خطأ ÙÙŠ قراءة %s بيانات العملية قد تكون Ù…Ùقودة أو غير صحيحة. اعادة Ùحص المحÙظة.‬</translation>
+ </message>
+ <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
- <translation type="unfinished">عملية حساب الرسوم Ùشلت. الرسوم الاحتياطية غير Ù…Ùعلة. انتظر عدة كتل أو مكن خيار الرسوم الاحتياطية. </translation>
+ <translation type="unfinished">‫عملية حساب الرسوم Ùشلت. خيار الرسوم الاحتياطية غير Ù…Ùعل. انتظر عدة طوابق أو Ùعل خيار الرسوم الاحتياطية.‬</translation>
</message>
<message>
<source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
- <translation type="unfinished">المل٠%s موجود مسبقا , اذا كنت متأكدا من المتابعة يرجى ارساله بعيدا للاستمرار </translation>
+ <translation type="unfinished">المل٠%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>
@@ -469,7 +520,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">رجاء تأكد من أن التاريخ والوقت ÙÙŠ حاسوبك صحيحان! اذا كانت ساعتك خاطئة، %s لن يعمل كما بصورة صحيحة.</translation>
+ <translation type="unfinished">رجاء تأكد من أن التاريخ والوقت ÙÙŠ حاسوبك صحيحان! اذا كانت ساعتك خاطئة، %s لن يعمل بصورة صحيحة.</translation>
</message>
<message>
<source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
@@ -477,11 +528,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
- <translation type="unfinished">تم تكوين تقليم أقل من الحد الأدنى %d ميجابايت. من Ùضلك استعمل رقم أعلى.</translation>
+ <translation type="unfinished">‫الاختصار أقل من الحد الأدنى %d ميجابايت. من Ùضلك ارÙع الحد.‬</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 type="unfinished">تقليم: اخر مزامنة للمحÙظة كانت قبل البيانات الملقمة. تحتاج الى - اعادة Ùهرسة (قم بتنزيل سلسلة الكتل بأكملها مرة أخرى ÙÙŠ حال تم تقليم عقدة)</translation>
+ <translation type="unfinished">‫الاختصار: اخر مزامنة للمحÙظة كانت قبل البيانات المختصرة. تحتاج الى - اعادة Ùهرسة (قم بتنزيل الطوابق المتتالية بأكملها مرة أخرى ÙÙŠ حال تم اختصار النود)‬</translation>
</message>
<message>
<source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
@@ -489,7 +540,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">قاعدة بيانات الكتل تحتوي على كتلة يبدو أنها من المستقبل. قد يكون هذا بسبب أن التاريخ والوقت ÙÙŠ حاسوبك قم ضبط بشكل غير صحيح. قم بإعادة بناء قاعدة بيانات الكتل ÙÙŠ حال كنت متأكد من أن التاريخ والوقت قد تم ضبطهما بشكل صحيح.</translation>
+ <translation type="unfinished">‫قاعدة بيانات الطوابق تحتوي على طابق مستقبلي كما يبدو. قد يكون هذا بسبب أن التاريخ والوقت ÙÙŠ جهازك لم يضبطا بشكل صحيح. قم بإعادة بناء قاعدة بيانات الطوابق ÙÙŠ حال كنت متأكدا من أن التاريخ والوقت قد تم ضبطهما بشكل صحيح‬</translation>
</message>
<message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
@@ -497,7 +548,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">هذه بنية للتجربة ما قبل-الاصدار - استخدمها على مسؤوليتك الخاصة - لا تستخدمها للتعدين أو لتطبيقات التجارة.</translation>
+ <translation type="unfinished">‫هذه بناء برمجي تجريبي - استخدمه على مسؤوليتك الخاصة - لا تستخدمه للتعدين أو التجارة‬</translation>
+ </message>
+ <message>
+ <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
+ <translation type="unfinished">‫هذا هو الحد الاعلى للرسوم التي تدÙعها (بالاضاÙØ© للرسوم العادية) لتÙادي الدÙع الجزئي واعطاء أولوية لاختيار الوحدات.‬</translation>
</message>
<message>
<source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
@@ -508,28 +563,36 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">هذه هي رسوم المعاملة التي قد تدÙعها عندما تكون عملية حساب الرسوم غير متوÙرة.</translation>
</message>
<message>
- <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
- <translation type="unfinished">غير قادر على اعادة الكتل. سو٠تحتاج الى اعادة بناء قاعدة البيانات باستخدام - reindex-chainstate</translation>
+ <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source>
+ <translation type="unfinished">‫صيغة مل٠المحÙظة غير معروÙØ© “%sâ€. الرجاء تقديم اما “bdb†أو “sqliteâ€.‬</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">‫تم انشاء المحÙظة بنجاح. سيتم الغاء العمل بنوعية المحاÙظ القديمة ولن يتم دعم انشاءها أو Ùتحها مستقبلا.‬</translation>
</message>
<message>
<source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
- <translation type="unfinished">تحذير: تم اكتشا٠مÙاتيح خاصة ÙÙŠ المحÙظة {%s} مع Ù…Ùاتيح خاصة موقÙØ©. </translation>
+ <translation type="unfinished">‫تحذير: تم اكتشا٠مÙاتيح خاصة ÙÙŠ المحÙظة {%s} رغم أن خيار التعامل مع المÙاتيح الخاصة معطل‬} مع Ù…Ùاتيح خاصة موقÙØ©. </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 type="unfinished">تحذير: لا يبدو أننا نتÙÙ‚ تمامًا مع أقراننا! قد تحتاج إلى الترقية ØŒ أو قد تحتاج العقد الأخرى إلى الترقية.</translation>
+ <translation type="unfinished">‫تحذير: لا يبدو أننا نتÙÙ‚ تمامًا مع أقراننا! قد تحتاج إلى الترقية ØŒ أو قد تحتاج الأنواد الأخرى إلى الترقية.‬</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 type="unfinished">تحتاج إلى إعادة إنشاء قاعدة البيانات باستخدام -reindex للعودة إلى الوضعية الغير مجردة. هذا سو٠يعيد تحميل سلسلة الكتل بأكملها</translation>
+ <translation type="unfinished">‫تحتاج إلى إعادة إنشاء قاعدة البيانات باستخدام -reindex للعودة إلى الوضعية النود الكامل. هذا سو٠يعيد تحميل الطوابق المتتالية بأكملها‬</translation>
</message>
<message>
<source>%s is set very high!</source>
- <translation type="unfinished">%s عال٠جداً</translation>
+ <translation type="unfinished">ضبط %s مرتÙع جدا!‬</translation>
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
- <translation type="unfinished">-الحد الأقصى للذاكرة على الأقل %d ميغابايت</translation>
+ <translation type="unfinished">‫-الحد الأقصى لتجمع الذاكرة %d ميجابايت‬ على الأقل</translation>
+ </message>
+ <message>
+ <source>A fatal internal error occurred, see debug.log for details</source>
+ <translation type="unfinished">‫حدث خطأ داخلي شديد، راجع مل٠تصحيح الأخطاء للتÙاصيل‬</translation>
</message>
<message>
<source>Cannot resolve -%s address: '%s'</source>
@@ -537,7 +600,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Cannot write to data directory '%s'; check permissions.</source>
- <translation type="unfinished">لايمكن الكتابة على دليل البيانات '%s'؛ تحقق من السماحيات. </translation>
+ <translation type="unfinished">‫لايمكن الكتابة ÙÙŠ المجلد '%s'Ø› تحقق من الصلاحيات.‬</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s طلب الاستماع على منÙØ° %u. يعتبر منÙذه "سيئًا" وبالتالي Ùمن غير المحتمل أن يتصل به أي من أقران Bitcoin Core. انظر الى doc / p2p-bad-ports.md للحصول على التÙاصيل والقائمة الكاملة.</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">‫Ùشل ÙÙŠ إعادة تسمية مل٠invalid peers.dat. يرجى نقله أو حذÙÙ‡ وحاول مرة أخرى.‬</translation>
+ </message>
+ <message>
+ <source>Config setting for %s only applied on %s network when in [%s] section.</source>
+ <translation type="unfinished">يتم تطبيق إعداد التكوين لـ%s Ùقط على شبكة %s ÙÙŠ قسم [%s].</translation>
</message>
<message>
<source>Copyright (C) %i-%i</source>
@@ -545,15 +620,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Corrupted block database detected</source>
- <translation type="unfinished">تم الكش٠عن قاعدة بيانات كتل تالÙØ©</translation>
+ <translation type="unfinished">‫تم الكش٠عن قاعدة بيانات طوابق تالÙة‬</translation>
+ </message>
+ <message>
+ <source>Could not find asmap file %s</source>
+ <translation type="unfinished">تعذر العثور على مل٠asmap %s</translation>
+ </message>
+ <message>
+ <source>Could not parse asmap file %s</source>
+ <translation type="unfinished">تعذر تحليل مل٠asmap %s</translation>
</message>
<message>
<source>Disk space is too low!</source>
- <translation type="unfinished">تحذير: مساحة القرص منخÙضة</translation>
+ <translation type="unfinished">‫تحذير: مساحة التخزين منخÙضة!‬</translation>
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
- <translation type="unfinished">هل تريد إعادة بناء قاعدة بيانات الكتل الآن؟</translation>
+ <translation type="unfinished">‫هل تريد إعادة بناء قاعدة بيانات الطوابق الآن؟‬</translation>
</message>
<message>
<source>Done loading</source>
@@ -561,7 +644,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Dump file %s does not exist.</source>
- <translation type="unfinished">مل٠مهمل %s غير موجود</translation>
+ <translation type="unfinished">‫مل٠الاسقاط %s غير موجود.‬</translation>
</message>
<message>
<source>Error creating %s</source>
@@ -573,7 +656,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error loading %s: Private keys can only be disabled during creation</source>
- <translation type="unfinished">خطأ ÙÙŠ تحميل %s: لا يمكن تعطيل المÙاتيح الخاصة إلا أثناء الإنشاء.</translation>
+ <translation type="unfinished">‫خطأ ÙÙŠ تحميل %s: يمكن تعطيل المÙاتيح الخاصة أثناء الانشاء Ùقط‬</translation>
</message>
<message>
<source>Error loading %s: Wallet corrupted</source>
@@ -581,35 +664,51 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error loading %s: Wallet requires newer version of %s</source>
- <translation type="unfinished">خطا تحميل %s: المحÙظة تتطلب النسخة الجديدة من %s.</translation>
+ <translation type="unfinished">‫خطأ ÙÙŠ تحميل %s: المحÙظة تتطلب الاصدار الجديد من %s‬</translation>
</message>
<message>
<source>Error loading block database</source>
- <translation type="unfinished">خطأ ÙÙŠ تحميل قاعدة بيانات الكتل</translation>
+ <translation type="unfinished">‫خطأ ÙÙŠ تحميل قاعدة بيانات الطوابق‬</translation>
</message>
<message>
<source>Error opening block database</source>
- <translation type="unfinished">خطأ ÙÙŠ Ùتح قاعدة بيانات الكتل</translation>
+ <translation type="unfinished">‫خطأ ÙÙŠ Ùتح قاعدة بيانات الطوابق‬</translation>
</message>
<message>
<source>Error reading from database, shutting down.</source>
- <translation type="unfinished">خطأ ÙÙŠ القراءة من قاعدة البيانات ØŒ والتوقÙ.</translation>
+ <translation type="unfinished">‫خطأ ÙÙŠ القراءة من قاعدة البيانات ØŒ يجري التوقÙ.‬</translation>
</message>
<message>
<source>Error reading next record from wallet database</source>
<translation type="unfinished">خطأ قراءة السجل التالي من قاعدة بيانات المحÙظة</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">خطأ ÙÙŠ ترقية قاعدة بيانات chainstate</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">‫خطأ: لا يمكن اضاÙØ© عملية المراقبة Ùقط لمحÙظة المراقبة‬</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">‫خطأ: لا يمكن حذ٠عمليات المراقبة Ùقط‬</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
- <translation type="unfinished">خطأ : لا يمكن انشاء مؤشر ضمن قاعدة البيانات </translation>
+ <translation type="unfinished">‫خطأ : لم نتمكن من انشاء علامة Ùارقة (cursor) ÙÙŠ قاعدة البيانات‬</translation>
</message>
<message>
<source>Error: Disk space is low for %s</source>
- <translation type="unfinished">خطأ : مساحة القرص منخÙضة Ù„ %s</translation>
+ <translation type="unfinished">‫خطأ : مساحة التخزين منخÙضة Ù„ %s</translation>
+ </message>
+ <message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">‫خطأ: Ùشل انشاء محÙظة المراقبة Ùقط الجديدة‬</translation>
+ </message>
+ <message>
+ <source>Error: Got key that was not hex: %s</source>
+ <translation type="unfinished">‫خطأ: المÙتاح ليس ÙÙŠ صيغة ست عشرية: %s</translation>
+ </message>
+ <message>
+ <source>Error: Got value that was not hex: %s</source>
+ <translation type="unfinished">‫خطأ: القيمة ليست ÙÙŠ صيغة ست عشرية: %s</translation>
</message>
<message>
<source>Error: Missing checksum</source>
@@ -617,7 +716,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error: No %s addresses available.</source>
- <translation type="unfinished">خطأ : لا عناوين%s متوÙرة </translation>
+ <translation type="unfinished">‫خطأ : لا يتوÙر %s عناوين.‬</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">‫خطأ: غير قادر على قراءة السجلات ÙÙŠ قاعدة البيانات‬</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">‫خطأ: غير قادر النسخ الاحتياطي للمحÙظة‬</translation>
+ </message>
+ <message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">‫خطأ: غير قادر على قراءة السجلات ÙÙŠ قاعدة البيانات‬</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">‫خطأ: غير قادر على ازالة عناوين المراقبة Ùقط من السجل‬</translation>
</message>
<message>
<source>Error: Unable to write record to new wallet</source>
@@ -629,27 +744,35 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Failed to rescan the wallet during initialization</source>
- <translation type="unfinished">Ùشل ÙÙŠ اعادة مسح المحÙظة خلال عملية التهيئة.</translation>
+ <translation type="unfinished">‫Ùشلت عملية اعادة تÙحص وتدقيق المحÙظة أثناء التهيئة‬</translation>
</message>
<message>
<source>Failed to verify database</source>
<translation type="unfinished">Ùشل ÙÙŠ التحقق من قاعدة البيانات</translation>
</message>
<message>
+ <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source>
+ <translation type="unfinished">‫معدل الرسوم (%s) أقل من الحد الادنى لاعدادات معدل الرسوم (%s)‬</translation>
+ </message>
+ <message>
<source>Ignoring duplicate -wallet %s.</source>
- <translation type="unfinished"> تم تجاهل تعري٠مكرر -wallet %s</translation>
+ <translation type="unfinished">‫تجاهل المحÙظة المكررة %s.‬</translation>
</message>
<message>
<source>Importing…</source>
- <translation type="unfinished">استيراد </translation>
+ <translation type="unfinished">‫الاستيراد…‬</translation>
</message>
<message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
- <translation type="unfinished">لم يتم العثور على كتلة تكوين أو لم تكون صحيحة. datadir خاطئة للشبكة؟</translation>
+ <translation type="unfinished">‫لم يتم العثور على طابق الأساس أو المعلومات غير صحيحة. مجلد بيانات خاطئ للشبكة؟‬</translation>
</message>
<message>
<source>Initialization sanity check failed. %s is shutting down.</source>
- <translation type="unfinished">Ùشل بالتحقق ÙÙŠ اختبار التعقل. تم إيقا٠%s.</translation>
+ <translation type="unfinished">‫Ùشل التحقق من اختبار التعقل. تم إيقا٠%s.</translation>
+ </message>
+ <message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">‫المدخلات غير موجودة أو تم صرÙها‬</translation>
</message>
<message>
<source>Insufficient funds</source>
@@ -661,19 +784,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Invalid P2P permission: '%s'</source>
- <translation type="unfinished"> إذن غير صالح لالند للند: '%s' </translation>
+ <translation type="unfinished">‫إذن القرين للقرين غير صالح: ‘%s’‬</translation>
</message>
<message>
<source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">مبلغ غير صحيح -%s=: '%s'</translation>
+ <translation type="unfinished">‫قيمة غير صحيحة‬ ل - %s=&lt;amount&gt;:"%s"</translation>
</message>
<message>
<source>Invalid amount for -discardfee=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">مبلغ غير صحيح -discardfee=: '%s'</translation>
+ <translation type="unfinished">‫قيمة غير صحيحة‬ -discardfee=&lt;amount&gt;:"%s"</translation>
</message>
<message>
<source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">مبلغ غير صحيح -fallbackfee=: '%s'</translation>
+ <translation type="unfinished">مبلغ غير صحيح ل -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
<source>Loading P2P addresses…</source>
@@ -685,11 +808,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Loading block index…</source>
- <translation type="unfinished">تحميل مؤشر الكتلة</translation>
+ <translation type="unfinished">‫تحميل Ùهرس الطابق…‬</translation>
</message>
<message>
<source>Loading wallet…</source>
- <translation type="unfinished">تحميل المحÙظة</translation>
+ <translation type="unfinished">‫تحميل المحÙظة…‬</translation>
+ </message>
+ <message>
+ <source>Missing amount</source>
+ <translation type="unfinished">‫يÙتقد القيمة‬</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -697,27 +824,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Prune cannot be configured with a negative value.</source>
- <translation type="unfinished">لا يمكن تهيئة التجريد بقيمة سالبة.</translation>
+ <translation type="unfinished">‫لا يمكن ضبط الاختصار بقيمة سالبة.‬</translation>
</message>
<message>
<source>Prune mode is incompatible with -txindex.</source>
- <translation type="unfinished">وضع التجريد غير متواÙÙ‚ مع -txindex.</translation>
+ <translation type="unfinished">‫وضع الاختصار غير متواÙÙ‚ مع -txindex.‬</translation>
</message>
<message>
<source>Replaying blocks…</source>
- <translation type="unfinished">كتل الإعادة</translation>
+ <translation type="unfinished">‫إستعادة الطوابق…‬</translation>
</message>
<message>
<source>Rescanning…</source>
- <translation type="unfinished">إعادة المسح </translation>
+ <translation type="unfinished">‫إعادة التÙحص والتدقيق…‬</translation>
</message>
<message>
<source>SQLiteDatabase: Failed to execute statement to verify database: %s</source>
- <translation type="unfinished">SQLiteDatabase: Ùشل ÙÙŠ تحضير التصريح لجلب التطبيق id: %s</translation>
+ <translation type="unfinished">‫‫SQLiteDatabase: Ùشل ÙÙŠ تنÙيذ الامر لتوثيق قاعدة البيانات: %s</translation>
</message>
<message>
<source>Section [%s] is not recognized.</source>
- <translation type="unfinished">لم يتم التعر٠على القسم  [%s]</translation>
+ <translation type="unfinished">لم يتم التعر٠على القسم [%s]</translation>
</message>
<message>
<source>Signing transaction failed</source>
@@ -725,13 +852,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Specified -walletdir "%s" does not exist</source>
- <translation type="unfinished">مل٠المحÙظة المحدد "%s" غير موجود
-</translation>
+ <translation type="unfinished">‫مجلد المحÙظة المحددة "%s" غير موجود</translation>
</message>
<message>
<source>Specified -walletdir "%s" is a relative path</source>
- <translation type="unfinished">مل٠المحÙظة المحدد "%s" غير موجود
-</translation>
+ <translation type="unfinished">‫مسار مجلد المحÙظة المحدد "%s" مختصر ومتغير‬</translation>
</message>
<message>
<source>The source code is available from %s.</source>
@@ -739,11 +864,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The transaction amount is too small to pay the fee</source>
- <translation type="unfinished">قيمة المعاملة صغيرة جدا لدÙع الأجر</translation>
+ <translation type="unfinished">‫قيمة المعاملة صغيرة جدا ولا تكÙÙŠ لدÙع الرسوم‬</translation>
</message>
<message>
<source>The wallet will avoid paying less than the minimum relay fee.</source>
- <translation type="unfinished">سو٠تتجنب المحÙظة دÙع أقل من الحد الأدنى لرسوم التتابع.</translation>
+ <translation type="unfinished">‫سو٠تتجنب المحÙظة دÙع رسوم أقل من الحد الأدنى للتوصيل.‬</translation>
</message>
<message>
<source>This is experimental software.</source>
@@ -755,7 +880,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>This is the transaction fee you will pay if you send a transaction.</source>
- <translation type="unfinished">هذه هي رسوم تحويل الأموال التي ستدÙعها إذا قمت بتحويل الأموال.</translation>
+ <translation type="unfinished">‫هذه هي رسوم ارسال العملية التي ستدÙعها إذا قمت بارسال العمليات.‬</translation>
</message>
<message>
<source>Transaction amount too small</source>
@@ -763,17 +888,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Transaction amounts must not be negative</source>
- <translation type="unfinished">يجب ألا تكون قيمة المعاملة سلبية</translation>
- </message>
- <message>
- <source>Transaction has too long of a mempool chain</source>
- <translation type="unfinished">المعاملات طويلة جداً على حجم سلسلة الذاكرة </translation>
+ <translation type="unfinished">‫يجب ألا تكون قيمة العملية بالسالب‬</translation>
</message>
<message>
<source>Transaction must have at least one recipient</source>
<translation type="unfinished">يجب أن تحتوي المعاملة على مستلم واحد على الأقل</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">‫العملية تتطلب عنوان Ùكة ولكن لم نتمكن من توليد العنوان.‬</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">المعاملة كبيرة جدا</translation>
</message>
@@ -791,7 +916,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unable to generate keys</source>
- <translation type="unfinished"> غير قادر على توليد Ù…Ùاتيح.</translation>
+ <translation type="unfinished"> غير قادر على توليد Ù…Ùاتيح</translation>
</message>
<message>
<source>Unable to open %s for writing</source>
@@ -803,7 +928,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unknown -blockfilterindex value %s.</source>
- <translation type="unfinished">قيمة -blockfilterindex  مجهولة %s.</translation>
+ <translation type="unfinished">‫قيمة -blockfilterindex  مجهولة %s.‬</translation>
</message>
<message>
<source>Unknown address type '%s'</source>
@@ -814,12 +939,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">شبكة مجهولة عرÙت حددت ÙÙŠ -onlynet: '%s'</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">ترقية قاعدة بيانات UTXO</translation>
- </message>
- <message>
<source>Verifying blocks…</source>
- <translation type="unfinished">جار التحقق من الكتل...</translation>
+ <translation type="unfinished">جار التحقق من الطوابق...</translation>
</message>
<message>
<source>Verifying wallet(s)…</source>
@@ -827,7 +948,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Wallet needed to be rewritten: restart %s to complete</source>
- <translation type="unfinished">يلزم إعادة كتابة المحÙظة: إعادة تشغيل %s لإكمال العملية</translation>
+ <translation type="unfinished">يجب إعادة كتابة المحÙظة: يلزم إعادة تشغيل %s لإكمال العملية</translation>
</message>
</context>
<context>
@@ -850,7 +971,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>E&amp;xit</source>
- <translation type="unfinished">خروج</translation>
+ <translation type="unfinished">‫خ&amp;روج‬</translation>
</message>
<message>
<source>Quit application</source>
@@ -858,11 +979,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;About %1</source>
- <translation type="unfinished">حوالي %1</translation>
+ <translation type="unfinished">&amp;حوالي %1</translation>
</message>
<message>
<source>Show information about %1</source>
- <translation type="unfinished">أظهر المعلومات حولة %1</translation>
+ <translation type="unfinished">‫أظهر المعلومات حول %1‬</translation>
</message>
<message>
<source>About &amp;Qt</source>
@@ -870,32 +991,36 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Show information about Qt</source>
- <translation type="unfinished">اظهر المعلومات</translation>
+ <translation type="unfinished">‫اظهر المعلومات عن Qt‬</translation>
</message>
<message>
<source>Modify configuration options for %1</source>
- <translation type="unfinished">تغيير خيارات الإعداد لأساس ل%1</translation>
+ <translation type="unfinished">تغيير خيارات الإعداد ل%1</translation>
</message>
<message>
<source>Create a new wallet</source>
<translation type="unfinished">إنشاء محÙظة جديدة</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">‫&amp;تصغير‬</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">المحÙظة:</translation>
</message>
<message>
<source>Network activity disabled.</source>
<extracomment>A substring of the tooltip.</extracomment>
- <translation type="unfinished">تم إلغاء تÙعيل الشبكه</translation>
+ <translation type="unfinished">‫نشاط الشبكة معطل.‬</translation>
</message>
<message>
<source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
- <translation type="unfinished">%1 اتصال نشط بشبكة البيتكوين</translation>
+ <translation type="unfinished">البروكسي &lt;b&gt;يعمل &lt;/b&gt;:%1</translation>
</message>
<message>
<source>Send coins to a Bitcoin address</source>
- <translation type="unfinished">ارسل عملات الى عنوان بيتكوين</translation>
+ <translation type="unfinished">‫ارسل بتكوين الى عنوان‬</translation>
</message>
<message>
<source>Backup wallet to another location</source>
@@ -903,7 +1028,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Change the passphrase used for wallet encryption</source>
- <translation type="unfinished">تغيير كلمة المرور المستخدمة لتشÙير المحÙظة</translation>
+ <translation type="unfinished">‫تغيير عبارة المرور المستخدمة لتشÙير المحÙظة‬</translation>
</message>
<message>
<source>&amp;Send</source>
@@ -911,15 +1036,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Receive</source>
- <translation type="unfinished">&amp;استقبل</translation>
+ <translation type="unfinished">‫&amp;استلم‬</translation>
</message>
<message>
<source>&amp;Options…</source>
- <translation type="unfinished">&amp; خيارات</translation>
+ <translation type="unfinished">‫&amp;خيارات…‬</translation>
</message>
<message>
<source>&amp;Encrypt Wallet…</source>
- <translation type="unfinished">&amp; تشÙير المحÙظة</translation>
+ <translation type="unfinished">‫&amp;تشÙير المحÙظة…‬</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
@@ -927,39 +1052,39 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Backup Wallet…</source>
- <translation type="unfinished">&amp; محÙظة احتياطية</translation>
+ <translation type="unfinished">‫&amp;انسخ المحÙظة احتياطيا…‬</translation>
</message>
<message>
<source>&amp;Change Passphrase…</source>
- <translation type="unfinished">وتغيير العبارات...</translation>
+ <translation type="unfinished">‫&amp;تغيير عبارة المرور…‬</translation>
</message>
<message>
<source>Sign &amp;message…</source>
- <translation type="unfinished">علامة ورسالة...</translation>
+ <translation type="unfinished">‫توقيع &amp;رسالة…‬</translation>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation type="unfinished">وقَع الرسائل بواسطة ال: Bitcoin الخاص بك لإثبات امتلاكك لهم</translation>
+ <translation type="unfinished">‫وقَع الرسائل باستخدام عناوين البتكوين لإثبات امتلاكك لهذه العناوين‬</translation>
</message>
<message>
<source>&amp;Verify message…</source>
- <translation type="unfinished">&amp; تحقق من الرسالة</translation>
+ <translation type="unfinished">‫&amp;تحقق من الرسالة…‬</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation type="unfinished">تحقق من الرسائل للتأكد من أنَها ÙˆÙقعت برسائل Bitcoin محدَدة</translation>
+ <translation type="unfinished">‫تحقق من الرسائل للتأكد من أنَها ÙˆÙقّعت بعناوين بتكوين محددة‬</translation>
</message>
<message>
<source>&amp;Load PSBT from file…</source>
- <translation type="unfinished">وتحميل PSBT من ملÙ...</translation>
+ <translation type="unfinished">‫&amp;تحميل معاملة PSBT من ملÙ…‬</translation>
</message>
<message>
<source>Open &amp;URI…</source>
- <translation type="unfinished">Ùتح ورابط...</translation>
+ <translation type="unfinished">‫Ùتح &amp;رابط…‬</translation>
</message>
<message>
<source>Close Wallet…</source>
- <translation type="unfinished">اغلاق المحÙظة</translation>
+ <translation type="unfinished">‫اغلاق المحÙظة…‬</translation>
</message>
<message>
<source>Create Wallet…</source>
@@ -967,7 +1092,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Close All Wallets…</source>
- <translation type="unfinished">اغلاق جميع المحاÙظ</translation>
+ <translation type="unfinished">‫اغلاق جميع المحاÙظ…‬</translation>
</message>
<message>
<source>&amp;File</source>
@@ -986,36 +1111,40 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">شريط أدوات علامات التبويب</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">مزامنة الرؤوس (%1%)...</translation>
+ </message>
+ <message>
<source>Synchronizing with network…</source>
- <translation type="unfinished">مزامنة مع الشبكة ...</translation>
+ <translation type="unfinished">‫تزامن مع الشبكة…‬</translation>
</message>
<message>
<source>Indexing blocks on disk…</source>
- <translation type="unfinished">كتل الÙهرسة على القرص ...</translation>
+ <translation type="unfinished">‫Ùهرسة الطوابق على وحدة التخزين المحلي…‬</translation>
</message>
<message>
<source>Processing blocks on disk…</source>
- <translation type="unfinished">كتل المعالجة على القرص ...</translation>
+ <translation type="unfinished">‫معالجة الطوابق على وحدة التخزين المحلي…‬</translation>
</message>
<message>
<source>Reindexing blocks on disk…</source>
- <translation type="unfinished">جار٠إعادة Ùهرسة الكتل الموجودة على القرص ...</translation>
+ <translation type="unfinished">‫إعادة Ùهرسة الطوابق ÙÙŠ وحدة التخزين المحلي…‬</translation>
</message>
<message>
<source>Connecting to peers…</source>
- <translation type="unfinished">الاتصال بالأقران ...</translation>
+ <translation type="unfinished">‫الاتصال بالأقران…‬</translation>
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation type="unfinished">أطلب دÙعات (يولد كودات الرمز المربع وبيت كوين: العناوين المعطاة)</translation>
+ <translation type="unfinished">‫أطلب مدÙوعات (أنشئ رموز استجابة (QR Codes) وعناوين بتكوين)‬</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
- <translation type="unfinished">عرض قائمة عناوين الإرسال المستخدمة والملصقات</translation>
+ <translation type="unfinished">‫عرض قائمة العناوين المرسÙلة والمذكرات (المستخدمة سابقا)‬</translation>
</message>
<message>
<source>Show the list of used receiving addresses and labels</source>
- <translation type="unfinished">عرض قائمة عناوين الإستقبال المستخدمة والملصقات</translation>
+ <translation type="unfinished">‫عرض قائمة العناوين المستلمة والمذكرات (المستخدمة سابقا)‬</translation>
</message>
<message>
<source>&amp;Command-line options</source>
@@ -1024,29 +1153,29 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Processed %n block(s) of transaction history.</numerusform>
+ <numerusform>Processed %n block(s) of transaction history.</numerusform>
+ <numerusform>Processed %n block(s) of transaction history.</numerusform>
+ <numerusform>Processed %n block(s) of transaction history.</numerusform>
+ <numerusform>Processed %n block(s) of transaction history.</numerusform>
+ <numerusform>‫تمت معالجة %n طوابق من العمليات التاريخية.‬</numerusform>
</translation>
</message>
<message>
<source>%1 behind</source>
- <translation type="unfinished">خل٠%1</translation>
+ <translation type="unfinished">‫متأخر‬ %1</translation>
</message>
<message>
<source>Catching up…</source>
- <translation type="unfinished">يمسك…</translation>
+ <translation type="unfinished">‫يجري التدارك…‬</translation>
</message>
<message>
<source>Last received block was generated %1 ago.</source>
- <translation type="unfinished">تم توليد الكتلة المستقبلة الأخيرة منذ %1.</translation>
+ <translation type="unfinished">‫آخر طابق مستلم تم بناءه قبل %1.</translation>
</message>
<message>
<source>Transactions after this will not yet be visible.</source>
- <translation type="unfinished">المعاملات بعد ذلك لن تكون مريئة بعد.</translation>
+ <translation type="unfinished">‫المعاملات بعد هذه لن تكون ظاهرة Ùورا.‬</translation>
</message>
<message>
<source>Error</source>
@@ -1062,35 +1191,39 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Up to date</source>
- <translation type="unfinished">محدث</translation>
+ <translation type="unfinished">‫حديث‬</translation>
</message>
<message>
<source>Load Partially Signed Bitcoin Transaction</source>
- <translation type="unfinished">تحميل معاملة بتكوين الموقعة جزئيًا</translation>
+ <translation type="unfinished">‫تحميل معاملة بتكوين موقعة جزئيًا (PSBT)‬</translation>
+ </message>
+ <message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">‫تحميل معاملة بتكوين موقعة جزئيا (‫PSBT) من &amp;الحاÙظة…‬</translation>
</message>
<message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
- <translation type="unfinished">تحميل معاملة بتكوين الموقعة جزئيًا من الحاÙظة</translation>
+ <translation type="unfinished">‫تحميل معاملة بتكوين موقعة جزئيًا ‫(‫PSBT) من الحاÙظة‬</translation>
</message>
<message>
<source>Node window</source>
- <translation type="unfinished">ناÙذة Node </translation>
+ <translation type="unfinished">‫ناÙذة النود‬</translation>
</message>
<message>
<source>Open node debugging and diagnostic console</source>
- <translation type="unfinished">اÙتح وحدة التحكم ÙÙŠ تصحيح أخطاء node والتشخيص</translation>
+ <translation type="unfinished">‫اÙتح وحدة التحكم ÙÙŠ تصحيح الأخطاء والتشخيص للنود‬</translation>
</message>
<message>
<source>&amp;Sending addresses</source>
- <translation type="unfinished">&amp;عناوين الإرسال</translation>
+ <translation type="unfinished">‫&amp;عناوين الإرسال‬</translation>
</message>
<message>
<source>&amp;Receiving addresses</source>
- <translation type="unfinished">&amp;عناوين الإستقبال</translation>
+ <translation type="unfinished">‫&amp;عناوين الإستلام‬</translation>
</message>
<message>
<source>Open a bitcoin: URI</source>
- <translation type="unfinished">اÙتح عملة بيتكوين: URI</translation>
+ <translation type="unfinished">‫اÙتح رابط بتكوين: URI‬</translation>
</message>
<message>
<source>Open Wallet</source>
@@ -1098,39 +1231,69 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Open a wallet</source>
- <translation type="unfinished">اÙتح المحÙظة</translation>
+ <translation type="unfinished">‫اÙتح محÙظة‬</translation>
</message>
<message>
<source>Close wallet</source>
<translation type="unfinished">اغلق المحÙظة</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">‫استعادة محÙظة…‬</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">‫استعادة محÙظة من مل٠النسخ الاحتياطي‬</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
- <translation type="unfinished">إغلاق جميع المحاÙظ ...</translation>
+ <translation type="unfinished">‫إغلاق جميع المحاÙظ‬</translation>
</message>
<message>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
- <translation type="unfinished">بين اشارة المساعدة %1 للحصول على قائمة من خيارات اوامر البت كوين المحتملة </translation>
+ <translation type="unfinished">‫اعرض %1 رسالة المساعدة للحصول على قائمة من خيارات سطر أوامر البتكوين المحتملة‬</translation>
</message>
<message>
<source>&amp;Mask values</source>
- <translation type="unfinished">&amp; إخÙاء القيم</translation>
+ <translation type="unfinished">&amp;إخÙاء القيم</translation>
</message>
<message>
<source>Mask the values in the Overview tab</source>
- <translation type="unfinished">إخÙاء القيم ÙÙŠ علامة التبويب نظرة عامة</translation>
+ <translation type="unfinished">‫إخÙاء القيم ÙÙŠ علامة التبويب: نظرة عامة‬</translation>
</message>
<message>
<source>default wallet</source>
- <translation type="unfinished">المحÙظة الإÙتراضية</translation>
+ <translation type="unfinished">‫محÙظة اÙتراضية‬</translation>
</message>
<message>
<source>No wallets available</source>
- <translation type="unfinished">المحÙظة الرقمية غير متوÙرة</translation>
+ <translation type="unfinished">‫لا يوجد محÙظة متاحة‬</translation>
+ </message>
+ <message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">بيانات المحÙظة</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">‫تحميل النسخة الاحتياطية لمحÙظة‬</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">استعادة المحÙظة</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">إسم المحÙظة</translation>
</message>
<message>
<source>&amp;Window</source>
- <translation type="unfinished">ناÙذه</translation>
+ <translation type="unfinished">‫&amp;ناÙذة‬</translation>
</message>
<message>
<source>Zoom</source>
@@ -1142,18 +1305,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>%1 client</source>
- <translation type="unfinished">الزبون %1</translation>
+ <translation type="unfinished">‫العميل %1</translation>
+ </message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">‫&amp;اخÙاء‬</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">‫ع&amp;رض‬</translation>
</message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
+ <numerusform>%n اتصال نشط بشبكة البتكوين.</numerusform>
</translation>
</message>
<message>
@@ -1164,7 +1335,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Show Peers tab</source>
<extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
- <translation type="unfinished">إظهار علامة التبويب النظراء</translation>
+ <translation type="unfinished">‫إظهار تبويب الأقران‬</translation>
</message>
<message>
<source>Disable network activity</source>
@@ -1177,6 +1348,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">تمكين نشاط الشبكة</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">ما قبل مزامنة الرؤوس (%1%)…</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">خطأ: %1</translation>
</message>
@@ -1188,46 +1363,45 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Date: %1
</source>
<translation type="unfinished">التاريخ %1
-
-
</translation>
</message>
<message>
<source>Amount: %1
</source>
- <translation type="unfinished">الكمية %1
+ <translation type="unfinished">القيمة %1
</translation>
</message>
<message>
<source>Wallet: %1
</source>
- <translation type="unfinished">المحÙظة: %1</translation>
+ <translation type="unfinished">المحÙظة: %1
+</translation>
</message>
<message>
<source>Type: %1
</source>
- <translation type="unfinished">نوع %1
+ <translation type="unfinished">النوع %1
</translation>
</message>
<message>
<source>Label: %1
</source>
- <translation type="unfinished">علامه: %1
+ <translation type="unfinished">‫المذكرة‬: %1
</translation>
</message>
<message>
<source>Address: %1
</source>
- <translation type="unfinished">عنوان %1
+ <translation type="unfinished">العنوان %1
</translation>
</message>
<message>
<source>Sent transaction</source>
- <translation type="unfinished">إرسال المعاملة</translation>
+ <translation type="unfinished">‫العمليات المرسلة‬</translation>
</message>
<message>
<source>Incoming transaction</source>
- <translation type="unfinished">المعاملات الواردة</translation>
+ <translation type="unfinished">‫العمليات الواردة‬</translation>
</message>
<message>
<source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
@@ -1239,7 +1413,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
- <translation type="unfinished">المÙتاح السري &lt;b&gt;معطل&lt;/b&gt;</translation>
+ <translation type="unfinished">المÙتاح الخاص &lt;b&gt;معطل&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>
@@ -1258,14 +1432,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>UnitDisplayStatusBarControl</name>
<message>
<source>Unit to show amounts in. Click to select another unit.</source>
- <translation type="unfinished">الوحدة لإظهار المبالغ Ùيها. انقر لتحديد وحدة أخرى.</translation>
+ <translation type="unfinished">‫وحدة عرض القيمة. انقر لتغيير وحدة العرض.‬</translation>
</message>
</context>
<context>
<name>CoinControlDialog</name>
<message>
<source>Coin Selection</source>
- <translation type="unfinished">اختيار العمله</translation>
+ <translation type="unfinished">اختيار وحدات البتكوين</translation>
</message>
<message>
<source>Quantity:</source>
@@ -1273,11 +1447,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Bytes:</source>
- <translation type="unfinished">بايت</translation>
+ <translation type="unfinished">بايت:</translation>
</message>
<message>
<source>Amount:</source>
- <translation type="unfinished">القيمة :</translation>
+ <translation type="unfinished">القيمة:</translation>
</message>
<message>
<source>Fee:</source>
@@ -1289,15 +1463,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>After Fee:</source>
- <translation type="unfinished">بعد الرسوم :</translation>
+ <translation type="unfinished">بعد الرسوم:</translation>
</message>
<message>
<source>Change:</source>
- <translation type="unfinished">تعديل :</translation>
+ <translation type="unfinished">تعديل:</translation>
</message>
<message>
<source>(un)select all</source>
- <translation type="unfinished">عدم اختيار الجميع</translation>
+ <translation type="unfinished">‫الغاء تحديد الكل‬</translation>
</message>
<message>
<source>Tree mode</source>
@@ -1309,15 +1483,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Amount</source>
- <translation type="unfinished">مبلغ</translation>
+ <translation type="unfinished">‫القيمة‬</translation>
</message>
<message>
<source>Received with label</source>
- <translation type="unfinished">مستقبل مع ملصق</translation>
+ <translation type="unfinished">‫استÙلم وله مذكرة‬</translation>
</message>
<message>
<source>Received with address</source>
- <translation type="unfinished">مستقبل مع عنوان</translation>
+ <translation type="unfinished">‫مستلم مع عنوان‬</translation>
</message>
<message>
<source>Date</source>
@@ -1329,23 +1503,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirmed</source>
- <translation type="unfinished">تأكيد</translation>
+ <translation type="unfinished">‫ناÙذ‬</translation>
</message>
<message>
<source>Copy amount</source>
- <translation type="unfinished">نسخ الكمية</translation>
+ <translation type="unfinished">‫نسخ القيمة‬</translation>
</message>
<message>
<source>&amp;Copy address</source>
- <translation type="unfinished">انسخ العنوان</translation>
+ <translation type="unfinished">‫&amp;نسخ العنوان‬</translation>
</message>
<message>
<source>Copy &amp;label</source>
- <translation type="unfinished">نسخ Ùˆ تصنيÙ</translation>
+ <translation type="unfinished">‫نسخ &amp;اضاÙØ© مذكرة‬</translation>
</message>
<message>
<source>Copy &amp;amount</source>
- <translation type="unfinished">نسخ &amp;مبلغ</translation>
+ <translation type="unfinished">‫نسخ &amp;القيمة‬</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">‫نسخ &amp;معر٠العملية ÙˆÙهرس المخرجات‬</translation>
</message>
<message>
<source>L&amp;ock unspent</source>
@@ -1377,7 +1555,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Copy change</source>
- <translation type="unfinished">نسخ التعديل</translation>
+ <translation type="unfinished">‫نسخ الÙكة‬</translation>
</message>
<message>
<source>(%1 locked)</source>
@@ -1393,23 +1571,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
- <translation type="unfinished">يتحول هذا الملصق إلى اللون الأحمر إذا تلقى أي مستلم كمية أصغر من عتبة الغبار الحالية.</translation>
+ <translation type="unfinished">‫تتحول هذه المذكرة إلى اللون الأحمر إذا تلقى مستلم كمية أقل من الحد الأعلى الحالي للغبار .‬</translation>
</message>
<message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
- <translation type="unfinished">يمكن أن يختل٠+/- %1 من ساتوشي(s) لكل إدخال.</translation>
+ <translation type="unfinished">‫يمكن يزيد أو ينقص %1 ساتوشي لكل مدخل.‬</translation>
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(بدون وسم)</translation>
+ <translation type="unfinished">( لا وجود لمذكرة)</translation>
</message>
<message>
<source>change from %1 (%2)</source>
- <translation type="unfinished">تغير من %1 (%2)</translation>
+ <translation type="unfinished">تغيير من %1 (%2)</translation>
</message>
<message>
<source>(change)</source>
- <translation type="unfinished">(تغير)</translation>
+ <translation type="unfinished">‫(غيّر)‬</translation>
</message>
</context>
<context>
@@ -1422,11 +1600,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
- <translation type="unfinished">جاري انشاء المحÙظة &lt;b&gt;%1&lt;/b&gt;... </translation>
+ <translation type="unfinished">جار انشاء المحÙظة &lt;b&gt;%1&lt;/b&gt;...</translation>
</message>
<message>
<source>Create wallet failed</source>
- <translation type="unfinished">Ùشل إنشاء المحÙظة</translation>
+ <translation type="unfinished">‫تعذر إنشاء المحÙظة‬</translation>
</message>
<message>
<source>Create wallet warning</source>
@@ -1436,12 +1614,29 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">لا يمكن سرد الموقعين</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">‫تم العثور على موقّعين خارجيين ÙƒÙثر (Too Many)‬</translation>
+ </message>
+</context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">‫تحميل المحÙظة‬</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">‫تحميل المحاÙظ…‬</translation>
+ </message>
</context>
<context>
<name>OpenWalletActivity</name>
<message>
<source>Open wallet failed</source>
- <translation type="unfinished">Ùشل Ùتح محÙظة</translation>
+ <translation type="unfinished">‫تعذر Ùتح محÙظة‬</translation>
</message>
<message>
<source>Open wallet warning</source>
@@ -1449,17 +1644,45 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>default wallet</source>
- <translation type="unfinished">المحÙظة الإÙتراضية</translation>
+ <translation type="unfinished">‫محÙظة اÙتراضية‬</translation>
</message>
<message>
<source>Open Wallet</source>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
- <translation type="unfinished">اÙتح المحÙظة</translation>
+ <translation type="unfinished">‫اÙتح محÙظة‬</translation>
</message>
<message>
<source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
- <translation type="unfinished">جاري Ùتح المحÙظة&lt;b&gt;%1&lt;/b&gt;...</translation>
+ <translation type="unfinished">جار Ùتح المحÙظة&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">استعادة المحÙظة</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">استعادة المحÙظة &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">‫تعذر استعادة المحÙظة‬</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">‫تحذير استعادة المحÙظة‬</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">‫رسالة استعادة محÙظة‬</translation>
</message>
</context>
<context>
@@ -1469,12 +1692,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">اغلق المحÙظة</translation>
</message>
<message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">هل أنت متأكد من رغبتك ÙÙŠ إغلاق المحÙظة &lt;i&gt;%1&lt;/i&gt;ØŸ </translation>
+ </message>
+ <message>
<source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
- <translation type="unfinished">اغلاق المحÙظة Ù„Ùترة طويلة قد يؤدي الى الاضطرار الى اعادة مزامنة السلسلة بأكملها اذا تم تمكين التلقيم.</translation>
+ <translation type="unfinished">‫اغلاق المحÙظة Ù„Ùترة طويلة قد يتطلب اعادة مزامنة المتتالية بأكملها إذا كانت النود مختصرة.‬</translation>
</message>
<message>
<source>Close all wallets</source>
- <translation type="unfinished">إغلاق جميع المحاÙظ ...</translation>
+ <translation type="unfinished">إغلاق جميع المحاÙظ</translation>
</message>
<message>
<source>Are you sure you wish to close all wallets?</source>
@@ -1497,7 +1724,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
- <translation type="unfinished">Ø´Ùر المحÙظة. المحÙظة سيتم تشÙيرها بإستخدام كلمة مرور من إختيارك.</translation>
+ <translation type="unfinished">‫شÙر المحÙظة. المحÙظة سيتم تشÙيرها بإستخدام عبارة مرور من اختيارك.‬</translation>
</message>
<message>
<source>Encrypt Wallet</source>
@@ -1509,7 +1736,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
- <translation type="unfinished">تعطيل المÙاتيح الخاصة لهذه المحÙظة. لن تحتوي المحاÙظ ذات المÙاتيح الخاصة المعطلة على Ù…Ùاتيح خاصة ولا يمكن أن تحتوي على Ù…Ùتاح HD أو Ù…Ùاتيح خاصة مستوردة. هذا مثالي لمحاÙظ مشاهدة Ùقط Ùقط.</translation>
+ <translation type="unfinished">‫تعطيل المÙاتيح الخاصة لهذه المحÙظة. لن تحتوي المحاÙظ ذات المÙاتيح الخاصة المعطلة على Ù…Ùاتيح خاصة ولا يمكن أن تحتوي على Ù…Ùتاح HD أو Ù…Ùاتيح خاصة مستوردة. هذا مثالي لمحاÙظ المراقبة Ùقط.‬</translation>
</message>
<message>
<source>Disable Private Keys</source>
@@ -1533,7 +1760,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
- <translation type="unfinished">استخدم جهاز توقيع خارجي مثل محÙظة الأجهزة. قم بتكوين البرنامج النصي للموقÙّع الخارجي ÙÙŠ تÙضيلات المحÙظة أولاً.</translation>
+ <translation type="unfinished">‫استخدم جهاز توقيع خارجي مثل محÙظة خارجية. أعد مسار المحÙظة الخارجية ÙÙŠ اعدادات المحÙظة أولاً.‬</translation>
</message>
<message>
<source>External signer</source>
@@ -1561,15 +1788,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Label</source>
- <translation type="unfinished">&amp;وصÙ</translation>
+ <translation type="unfinished">‫&amp;مذكرة‬</translation>
</message>
<message>
<source>The label associated with this address list entry</source>
- <translation type="unfinished">الملصق المرتبط بقائمة العناوين المدخلة</translation>
+ <translation type="unfinished">‫المذكرة المرتبطة بقائمة العناوين هذه‬</translation>
</message>
<message>
<source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
- <translation type="unfinished">العنوان المرتبط بقائمة العناوين المدخلة. Ùˆ التي يمكن تعديلها Ùقط بواسطة ارسال العناوين</translation>
+ <translation type="unfinished">‫العنوان مرتبط بقائمة العناوين المدخلة. يمكن التعديل لعناوين الارسال Ùقط.‬</translation>
</message>
<message>
<source>&amp;Address</source>
@@ -1589,11 +1816,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The entered address "%1" is not a valid Bitcoin address.</source>
- <translation type="unfinished">العنوان المدخل "%1" ليس عنوان بيت كوين صحيح.</translation>
+ <translation type="unfinished">‫العنوان المدخل "%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 type="unfinished">العنوان "%1" موجود بالÙعل كعنوان إستقبال تحت مسمى "%2" ولذلك لا يمكن إضاÙته كعنوان إرسال.</translation>
+ <translation type="unfinished">‫العنوان "%1" موجود بالÙعل كعنوان استلام مع المذكرة "%2" لذلك لا يمكن إضاÙته كعنوان إرسال.‬</translation>
</message>
<message>
<source>The entered address "%1" is already in the address book with label "%2".</source>
@@ -1601,18 +1828,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Could not unlock wallet.</source>
- <translation type="unfinished"> يمكن Ùتح المحÙظة.</translation>
+ <translation type="unfinished">‫تعذر Ùتح المحÙظة.‬</translation>
</message>
<message>
<source>New key generation failed.</source>
- <translation type="unfinished">Ùشل توليد Ù…Ùتاح جديد.</translation>
+ <translation type="unfinished">‫تعذر توليد Ù…Ùتاح جديد.‬</translation>
</message>
</context>
<context>
<name>FreespaceChecker</name>
<message>
<source>A new data directory will be created.</source>
- <translation type="unfinished">سيتم انشاء دليل بيانات جديد.</translation>
+ <translation type="unfinished">‫سيتم انشاء مجلد بيانات جديد.‬</translation>
</message>
<message>
<source>name</source>
@@ -1620,15 +1847,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation type="unfinished">الدليل موجوج بالÙعل. أض٠%1 اذا نويت إنشاء دليل جديد هنا.</translation>
+ <translation type="unfinished">‫المجلد موجود بالÙعل. أض٠%1 اذا أردت إنشاء مجلد جديد هنا.‬</translation>
</message>
<message>
<source>Path already exists, and is not a directory.</source>
- <translation type="unfinished">المسار موجود بالÙعل، وهو ليس دليلاً.</translation>
+ <translation type="unfinished">‫المسار موجود بالÙعل، وهو ليس مجلدا.‬</translation>
</message>
<message>
<source>Cannot create data directory here.</source>
- <translation type="unfinished">لا يمكن انشاء دليل بيانات هنا .</translation>
+ <translation type="unfinished">‫لا يمكن انشاء مجلد بيانات هنا.‬</translation>
</message>
</context>
<context>
@@ -1637,45 +1864,70 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Bitcoin</source>
<translation type="unfinished">بتكوين</translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(من %1 الجيجابايت المطلوبة)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB of space available</numerusform>
+ <numerusform>%n GB of space available</numerusform>
+ <numerusform>%n GB of space available</numerusform>
+ <numerusform>%n GB of space available</numerusform>
+ <numerusform>%n GB of space available</numerusform>
+ <numerusform>‫‫%n جيجابايت من المساحة متوÙرة</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 مطلوب غيغابايت للسلسلة الكاملة)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>‫(مطلوب %n جيجابايت)‬</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>‫( مطلوب %n جيجابايت لكامل المتتالية)‬</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
- <translation type="unfinished">سيتم تخزين %1 جيجابايت على الأقل من البيانات ÙÙŠ هذا الدليل، وستنمو مع الوقت.</translation>
+ <translation type="unfinished">‫سيتم تخزين %1 جيجابايت على الأقل من المجلد ÙÙŠ هذا الدليل، وستنمو مع الوقت.‬</translation>
</message>
<message>
<source>Approximately %1 GB of data will be stored in this directory.</source>
- <translation type="unfinished">سيتم تخزين %1 جيجابايت تقريباً من البيانات ÙÙŠ هذا الدليل.</translation>
+ <translation type="unfinished">‫سيتم تخزين %1 جيجابايت تقريباً من البيانات ÙÙŠ هذا المجلد.‬</translation>
</message>
<message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
</translation>
</message>
<message>
<source>%1 will download and store a copy of the Bitcoin block chain.</source>
- <translation type="unfinished">سيقوم %1 بتنزيل نسخة من سلسلة كتل بتكوين وتخزينها.</translation>
+ <translation type="unfinished">‫سيقوم %1 بتنزيل نسخة من الطوابق المتتالية للبتكوين وتخزينها.‬</translation>
</message>
<message>
<source>The wallet will also be stored in this directory.</source>
- <translation type="unfinished">سو٠يتم تخزين المحÙظة ÙÙŠ هذا الدليل.</translation>
+ <translation type="unfinished">‫سو٠يتم تخزين المحÙظة ÙÙŠ هذا المجلد.‬</translation>
</message>
<message>
<source>Error: Specified data directory "%1" cannot be created.</source>
- <translation type="unfinished">خطأ: لا يمكن تكوين دليل بيانات مخصص ل %1</translation>
+ <translation type="unfinished">‫خطأ: مجلد البيانات المحدد “%1†لا يمكن انشاءه.‬</translation>
</message>
<message>
<source>Error</source>
@@ -1683,54 +1935,54 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Welcome</source>
- <translation type="unfinished">أهلا</translation>
+ <translation type="unfinished">‫مرحبا‬</translation>
</message>
<message>
<source>Welcome to %1.</source>
- <translation type="unfinished"> اهلا بكم ÙÙŠ %1</translation>
+ <translation type="unfinished">‫مرحبا بكم ÙÙŠ %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 type="unfinished">بما انه هذه اول مرة لانطلاق هذا البرنامج, Ùيمكنك ان تختار اين سيخزن %1 بياناته</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 type="unfinished">عند النقر على "مواÙÙ‚" ØŒ سيبدأ %1 ÙÙŠ تنزيل ومعالجة سلسلة الكتل %4 الكاملة (%2 جيجابايت) بدءًا من المعاملات الأقدم ÙÙŠ %3 عند تشغيل %4 ÙÙŠ البداية.</translation>
+ <translation type="unfinished">‫بما ان هذه المرة الأولى لتشغيل هذا البرنامج، يمكنك اختيار موقع تخزين %1 البيانات.‬</translation>
</message>
<message>
<source>Limit block chain storage to</source>
- <translation type="unfinished">تقييد تخزين سلسلة الكتل إلى</translation>
+ <translation type="unfinished">‫تقييد تخزين الطوابق المتتالية حتى‬</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
- <translation type="unfinished">تتطلب العودة إلى هذا الإعداد إعادة تنزيل سلسلة الكتل بالكامل. من الأسرع تنزيل السلسلة الكاملة أولاً وتقليمها لاحقًا. تعطيل بعض الميزات المتقدمة.</translation>
+ <translation type="unfinished">‫تتطلب العودة إلى هذا الإعداد إعادة تنزيل الطوابق المتتالية بالكامل. من الأسرع تنزيل المتتالية الكاملة أولاً ثم اختصارها لاحقًا. تتعطل بعض الميزات المتقدمة.‬</translation>
</message>
<message>
<source> GB</source>
- <translation type="unfinished">غيغابايت</translation>
+ <translation type="unfinished">‫ ‫جيجابايت‬</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 type="unfinished">تÙعد هذه المزامنة الأولية أمرًا شاقًا للغاية، وقد تعرض جهاز الكمبيوتر الخاص بك للمشاكل الذي لم يلاحظها أحد سابقًا. ÙÙŠ كل مرة تقوم Ùيها بتشغيل %1ØŒ سيتابع التحميل من حيث تم التوقÙ.</translation>
+ <translation type="unfinished">‫تÙعد المزامنة الأولية عملية مجهدة للأجهزة، Ùˆ قد تكتش٠بعض المشاكل المتعلقة بعتاد جهازك والتي لم تلاحظها مسبقًا. ÙÙŠ كل مرة تقوم Ùيها بتشغيل %1ØŒ سيتابع البرنامج التحميل من حيث توق٠سابقا.‬</translation>
+ </message>
+ <message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">‫عندما تنقر مواÙÙ‚. %1 سنبدأ التحميل ومعالجة كامل %4 الطوابق المتتالية (%2 GB) بدأً من أوائل العمليات ÙÙŠ %3 عندما %4 تم الاطلاق لأول مرة.‬</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 type="unfinished">إذا كنت قد اخترت تقييد تخزين سلسلة الكتل (التجريد)ØŒ Ùيجب تحميل البيانات القديمة ومعالجتها، ولكن سيتم حذÙها بعد ذلك للحÙاظ على انخÙاض استخدام القرص.</translation>
+ <translation type="unfinished">‫إذا اخترت تقييد تخزين الطوابق المتتالية (الاختصار)ØŒ Ùيجب تحميل البيانات القديمة ومعالجتها، وسيتم حذÙها بعد ذلك لابقاء مساحة التخزين ÙÙŠ النطاق المحدد.‬</translation>
</message>
<message>
<source>Use the default data directory</source>
- <translation type="unfinished">استخدام دليل البانات الاÙتراضي</translation>
+ <translation type="unfinished">‫استخدام مجلد البيانات الاÙتراضي‬</translation>
</message>
<message>
<source>Use a custom data directory:</source>
- <translation type="unfinished">استخدام دليل بيانات مخصص:</translation>
+ <translation type="unfinished">‫استخدام مجلد بيانات آخر:‬</translation>
</message>
</context>
<context>
<name>HelpMessageDialog</name>
<message>
<source>version</source>
- <translation type="unfinished">النسخة</translation>
+ <translation type="unfinished">‫الاصدار‬</translation>
</message>
<message>
<source>About %1</source>
@@ -1745,42 +1997,42 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>ShutdownWindow</name>
<message>
<source>%1 is shutting down…</source>
- <translation type="unfinished">%1 يتم الإغلاق ...</translation>
+ <translation type="unfinished">‫%1 يتم الإغلاق…‬</translation>
</message>
<message>
<source>Do not shut down the computer until this window disappears.</source>
- <translation type="unfinished">لا توق٠عمل الكمبيوتر حتى تختÙÙŠ هذه الناÙذة</translation>
+ <translation type="unfinished">‫لا تغلق الكمبيوتر حتى تختÙÙŠ هذه الناÙذة.‬</translation>
</message>
</context>
<context>
<name>ModalOverlay</name>
<message>
<source>Form</source>
- <translation type="unfinished">نمودج</translation>
+ <translation type="unfinished">‫نموذج‬</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 type="unfinished">قد لا تكون المعاملات الأخيرة مرئية بعد، وبالتالي قد يكون رصيد محÙظتك غير صحيح. ستكون هذه المعلومات صحيحة بمجرد الانتهاء من محÙظتك مع شبكة البيتكوين، كما هو Ù…Ùصل أدناه.</translation>
+ <translation type="unfinished">‫قد لا تكون العمليات الأخيرة مرئية بعد، وبالتالي قد يكون رصيد محÙظتك غير دقيق. ستكون هذه المعلومات دقيقة بمجرد انتهاء مزامنة محÙظتك مع شبكة البيتكوين، كما هو موضح أدناه.‬</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 type="unfinished">لن تقبل الشبكة محاولة إنÙاق البتكوين المتأثرة بالمعاملات التي لم يتم عرضها بعد.</translation>
+ <translation type="unfinished">‫لن تقبل الشبكة محاولة انÙاق وحدات البتكوين ÙÙŠ الطوابق لم يتم مزامنتها بعد.‬</translation>
</message>
<message>
<source>Number of blocks left</source>
- <translation type="unfinished">عدد الكتل الÙاضلة</translation>
+ <translation type="unfinished">‫عدد الطوابق المتبقية‬</translation>
</message>
<message>
<source>Unknown…</source>
- <translation type="unfinished">غير معروÙ</translation>
+ <translation type="unfinished">‫غير معروÙ…‬</translation>
</message>
<message>
<source>calculating…</source>
- <translation type="unfinished">جاري الحساب</translation>
+ <translation type="unfinished">‫جار الحساب…‬</translation>
</message>
<message>
<source>Last block time</source>
- <translation type="unfinished">اخر وقت الكتلة</translation>
+ <translation type="unfinished">‫وقت الطابق الأخير‬</translation>
</message>
<message>
<source>Progress</source>
@@ -1788,11 +2040,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Progress increase per hour</source>
- <translation type="unfinished">تقدم يزيد بلساعة</translation>
+ <translation type="unfinished">‫التقدم لكل ساعة‬</translation>
</message>
<message>
<source>Estimated time left until synced</source>
- <translation type="unfinished">الوقت المتبقي للمزامنة</translation>
+ <translation type="unfinished">‫الوقت المتبقي حتى التزامن‬</translation>
</message>
<message>
<source>Hide</source>
@@ -1800,18 +2052,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Esc</source>
- <translation type="unfinished">خروج</translation>
+ <translation type="unfinished">‫‫Esc‬</translation>
</message>
<message>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
- <translation type="unfinished">مجهول. مزامنة الرؤوس (%1،%2٪) ...</translation>
+ <translation type="unfinished">‫غير معروÙ. مزامنة الرؤوس (%1, %2%)…‬</translation>
+ </message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">‫غير معروÙ. ما قبل مزامنة الرؤوس (%1, %2%)…‬</translation>
</message>
</context>
<context>
<name>OpenURIDialog</name>
<message>
<source>Open bitcoin URI</source>
- <translation type="unfinished">اÙتح بتكوين URI</translation>
+ <translation type="unfinished">‫اÙتح رابط بتكوين (URI)‬</translation>
</message>
<message>
<source>URI:</source>
@@ -1820,22 +2076,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Paste address from clipboard</source>
<extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
- <translation type="unfinished">انسخ العنوان من لوحة المÙاتيح</translation>
+ <translation type="unfinished">‫ألصق العنوان من الحاÙظة‬</translation>
</message>
</context>
<context>
<name>OptionsDialog</name>
<message>
<source>Options</source>
- <translation type="unfinished">خيارات ...</translation>
+ <translation type="unfinished">خيارات</translation>
</message>
<message>
<source>&amp;Main</source>
- <translation type="unfinished">&amp;الرئيسي</translation>
+ <translation type="unfinished">‫&amp;الرئيسية‬</translation>
</message>
<message>
<source>Automatically start %1 after logging in to the system.</source>
- <translation type="unfinished">ابدأ تلقائيًا %1 بعد تسجيل الدخول إلى النظام.</translation>
+ <translation type="unfinished">‫تشغيل البرنامج تلقائيا %1 بعد تسجيل الدخول إلى النظام.‬</translation>
</message>
<message>
<source>&amp;Start %1 on system login</source>
@@ -1843,11 +2099,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
- <translation type="unfinished">يؤدي تمكين التقليم إلى تقليل مساحة القرص المطلوبة بشكل كبير لتخزين المعاملات. لا تزال جميع الكتل مصدق عليها بشكل كامل. تتطلب العودة إلى هذا الإعداد إعادة تنزيل blockchain بالكامل.</translation>
+ <translation type="unfinished">‫يؤدي تمكين خيار اختصار النود إلى تقليل مساحة التخزين المطلوبة بشكل كبير. يتم المصادقة على جميع الطوابق رغم تÙعيل هذا الخيار،. إلغاء هذا الاعداد يتطلب اعادة تحميل الطوابق المتتالية من جديد بشكل كامل.‬</translation>
</message>
<message>
<source>Size of &amp;database cache</source>
- <translation type="unfinished">حجم ذاكرة التخزين المؤقت لقاعدة البيانات</translation>
+ <translation type="unfinished">‫حجم ذاكرة التخزين المؤقت ل&amp;قاعدة البيانات‬</translation>
</message>
<message>
<source>Number of script &amp;verification threads</source>
@@ -1855,23 +2111,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
- <translation type="unfinished">عنوان IP للوكيل (مثل IPv4: 127.0.0.1 / IPv6: ::1)</translation>
+ <translation type="unfinished">‫عنوان 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 type="unfinished">إظهار ما إذا كان وكيل SOCKS5 الاÙتراضي الموÙر تم استخدامه للوصول إلى النظراء عبر نوع الشبكة هذا.</translation>
+ <translation type="unfinished">إظهار ما إذا كان وكيل SOCKS5 الاÙتراضي الموÙر تم استخدامه للوصول إلى الأقران عبر نوع الشبكة هذا.</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 type="unfinished">التصغير بدلاً من الخروج من التطبيق عند إغلاق الناÙذة. عند تÙعيل هذا الخيار، سيتم إغلاق التطبيق Ùقط بعد اختيار الخروج من القائمة.</translation>
+ <translation type="unfinished">‫التصغير بدلاً من الخروج من التطبيق عند إغلاق الناÙذة. عند تÙعيل هذا الخيار، سيتم إغلاق التطبيق Ùقط بعد النقر على خروج من القائمة المنسدلة.‬</translation>
+ </message>
+ <message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">‫التÙضيلات المعينة عن طريق سطر الأوامر لها أولوية أكبر وتتجاوز التÙضيلات المختارة هنا:‬</translation>
</message>
<message>
<source>Open the %1 configuration file from the working directory.</source>
- <translation type="unfinished">Ùتح مل٠الإعدادات %1 من الدليل العامل.</translation>
+ <translation type="unfinished">‫Ùتح مل٠%1 الإعداد من مجلد العمل.‬</translation>
</message>
<message>
<source>Open Configuration File</source>
- <translation type="unfinished">Ùتح مل٠الإعدادات</translation>
+ <translation type="unfinished">‫Ùتح مل٠الإعداد‬</translation>
</message>
<message>
<source>Reset all client options to default.</source>
@@ -1879,7 +2139,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Reset Options</source>
- <translation type="unfinished">&amp;استعادة الخيارات</translation>
+ <translation type="unfinished">‫&amp;اعادة تهيئة الخيارات‬</translation>
</message>
<message>
<source>&amp;Network</source>
@@ -1887,47 +2147,77 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Prune &amp;block storage to</source>
- <translation type="unfinished">تقليم وحظر التخزين لـ</translation>
+ <translation type="unfinished">‫اختصار &amp;تخزين الطابق</translation>
</message>
<message>
<source>GB</source>
- <translation type="unfinished">جب</translation>
+ <translation type="unfinished">‫جيجابايت‬</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain.</source>
- <translation type="unfinished">تتطلب العودة إلى هذا الإعداد إعادة تنزيل سلسلة الكتل بالكامل.</translation>
+ <translation type="unfinished">‫العودة الى هذا الاعداد تتطلب إعادة تنزيل الطوابق المتتالية بالكامل.‬</translation>
+ </message>
+ <message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">‫الحد الأعلى لحجم قاعدة البيانات المؤقتة (الكاش). رÙع حد الكاش يزيد من سرعة المزامنة. هذا الخيار Ù…Ùيد أثناء المزامنة وقد لا ÙŠÙيد بعد اكتمال المزامنة ÙÙŠ معظم الحالات. تخÙيض حجم الكاش يقلل من استهلاك الذاكرة. ذاكرة تجمع الذاكرة (mempool) الغير مستخدمة مضمنة ÙÙŠ هذا الكاش.‬</translation>
</message>
<message>
<source>MiB</source>
- <translation type="unfinished">ميجا بايت</translation>
+ <translation type="unfinished">‫ميجابايت‬</translation>
</message>
<message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
- <translation type="unfinished">(0 = تلقائي, &lt;0 = اترك هذا العدد من الأنوية حر)</translation>
+ <translation type="unfinished">‫(0 = تلقائي, &lt;0 = لترك أنوية حرة بقدر الرقم السالب)‬</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">‫تÙعيل خادم نداء &amp;الاجراء البعيد (RPC)‬</translation>
</message>
<message>
<source>W&amp;allet</source>
- <translation type="unfinished">&amp;محÙظة</translation>
+ <translation type="unfinished">‫م&amp;Ø­Ùظة‬</translation>
+ </message>
+ <message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">‫تعيين خيار خصم الرسوم من القيمة كخيار اÙتراضي أم لا.‬</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">‫اخصم &amp;الرسوم من القيمة بشكل اÙتراضي‬</translation>
</message>
<message>
<source>Expert</source>
- <translation type="unfinished">تصدير</translation>
+ <translation type="unfinished">‫خبير‬</translation>
</message>
<message>
<source>Enable coin &amp;control features</source>
- <translation type="unfinished">تÙعيل ميزات التحكم ÙÙŠ العملة</translation>
+ <translation type="unfinished">‫تÙعيل ميزة &amp;التحكم بوحدات البتكوين‬</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 type="unfinished">اذا قمت بتعطيل الانÙاق من النقود الغير مؤكدة، النقود من معاملة غير مؤكدة لن تكون قابلة للاستعمال حتى تحتوي تلك المعاملة على الأقل على تأكيد واحد. هذا أيضا يؤثر على كيÙية حساب رصيدك.</translation>
+ <translation type="unfinished">‫اذا قمت بتعطيل خيار الانÙاق من الÙكة الغير مؤكدة، لن يكون بمقدورك التحكم بتلك الÙكة حتى تنْÙÙØ° العملية وتحصل على تأكيد واحد على الأقل. هذا أيضا يؤثر على كيÙية حساب رصيدك.‬</translation>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
- <translation type="unfinished">دÙع الÙكة غير المؤكدة</translation>
+ <translation type="unfinished">‫&amp;دÙع الÙكة غير المؤكدة‬</translation>
+ </message>
+ <message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">‫تÙعيل التحكم ب &amp;المعاملات الموقعة جزئيا‬</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">‫خيار عرض التحكم بالمعاملات الموقعة جزئيا.‬</translation>
</message>
<message>
<source>External Signer (e.g. hardware wallet)</source>
- <translation type="unfinished">الموقّع الخارجي (مثل محÙظة الأجهزة)</translation>
+ <translation type="unfinished">‫جهاز التوقيع الخارجي (مثل المحÙظة الخارجية)‬</translation>
</message>
<message>
<source>&amp;External signer script path</source>
@@ -1935,19 +2225,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
- <translation type="unfinished">المسار الكامل إلى برنامج نصي متواÙÙ‚ مع Bitcoin Core (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). احذر: يمكن أن تسرق البرامج الضارة عملاتك!</translation>
+ <translation type="unfinished">‫مثال لمسار كامل متواÙÙ‚ مع البتكوين الأساسي Bitcoin Core (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). احذر: يمكن أن تسرق البرمجيات الضارة عملاتك!‬</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 type="unfinished">Ùتح منÙØ° خادم البتكوين تلقائيا على الموجه. هذا Ùقط يعمل عندما يكون الموجه الخاص بك يدعم UPnP ومÙعل ايضا.</translation>
+ <translation type="unfinished">‫Ùتح منÙØ° عميل البتكوين تلقائيا على الموجه. يعمل Ùقط عندما يكون الموجه الخاص بك يدعم UPnP ومÙعل ايضا.‬</translation>
</message>
<message>
<source>Map port using &amp;UPnP</source>
- <translation type="unfinished">ربط المنÙØ° باستخدام UPnP</translation>
+ <translation type="unfinished">‫ربط المنÙØ° باستخدام &amp;UPnP‬</translation>
</message>
<message>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
- <translation type="unfinished">اÙتح منÙØ° عميل Bitcoin تلقائيًا على جهاز التوجيه. يعمل هذا Ùقط عندما يدعم جهاز التوجيه الخاص بك NAT-PMP ويتم تمكينه. يمكن أن يكون المنÙØ° الخارجي عشوائيًا.</translation>
+ <translation type="unfinished">‫اÙتح منÙØ° عميل بتكوين تلقائيًا على جهاز التوجيه. يعمل هذا Ùقط عندما يدعم جهاز التوجيه الخاص بك NAT-PMP ويتم تمكينه. يمكن أن يكون المنÙØ° الخارجي عشوائيًا.‬</translation>
</message>
<message>
<source>Map port using NA&amp;T-PMP</source>
@@ -1959,7 +2249,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Allow incomin&amp;g connections</source>
- <translation type="unfinished">السماح بالاتصالات الواردة.</translation>
+ <translation type="unfinished">‫السماح بالاتصالات الوارد&amp;ة‬</translation>
</message>
<message>
<source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
@@ -1983,7 +2273,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Used for reaching peers via:</source>
- <translation type="unfinished">مستخدم للاتصال بالاصدقاء من خلال:</translation>
+ <translation type="unfinished">مستخدم للاتصال بالاقران من خلال:</translation>
</message>
<message>
<source>Tor</source>
@@ -1991,27 +2281,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Window</source>
- <translation type="unfinished">ناÙذه</translation>
+ <translation type="unfinished">&amp;ناÙذة</translation>
</message>
<message>
<source>Show the icon in the system tray.</source>
- <translation type="unfinished">أظهر الرمز ÙÙŠ لوحة النظام.</translation>
+ <translation type="unfinished">عرض الأيقونة ÙÙŠ زاوية الأيقونات.</translation>
</message>
<message>
<source>&amp;Show tray icon</source>
- <translation type="unfinished">&amp; اعرض لوحة الأيقونة </translation>
+ <translation type="unfinished">‫&amp;اعرض الأيقونة ÙÙŠ الزاوية‬</translation>
</message>
<message>
<source>Show only a tray icon after minimizing the window.</source>
- <translation type="unfinished">إظهار آيقونة الصينية Ùقط بعد تصغير الناÙذة.</translation>
+ <translation type="unfinished">‫عرض الأيقونة ÙÙŠ زاوية الأيقونات Ùقط بعد تصغير الناÙذة.‬</translation>
</message>
<message>
<source>&amp;Minimize to the tray instead of the taskbar</source>
- <translation type="unfinished">التصغير إلى صينية النظام بدلاً من شريط المهام</translation>
+ <translation type="unfinished">‫التصغير إلى زاوية الأيقونات بدلاً من شريط المهام‬</translation>
</message>
<message>
<source>M&amp;inimize on close</source>
- <translation type="unfinished">تصغير عند الإغلاق</translation>
+ <translation type="unfinished">‫ت&amp;صغير عند الإغلاق‬</translation>
</message>
<message>
<source>&amp;Display</source>
@@ -2023,19 +2313,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
- <translation type="unfinished">سيسري هذا الإعداد بعد إعادة تشغيل %1.</translation>
+ <translation type="unfinished">‫يمكن ضبط الواجهة اللغوية للمستخدم من هنا. هذا الإعداد يتطلب إعادة تشغيل %1.‬</translation>
</message>
<message>
<source>&amp;Unit to show amounts in:</source>
- <translation type="unfinished">الوحدة لإظهار المبالغ Ùيها:</translation>
+ <translation type="unfinished">‫وحدة لعرض القيم:‬</translation>
</message>
<message>
<source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
- <translation type="unfinished">اختر وحدة التقسيم الÙرعية الاÙتراضية للعرض ÙÙŠ الواجهة وعند إرسال العملات.</translation>
+ <translation type="unfinished">‫اختر وحدة التقسيم الÙرعية الاÙتراضية للعرض ÙÙŠ الواجهة وعند إرسال البتكوين.‬</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 type="unfinished">‫عناوين أطرا٠أخرى (مثل: مستكش٠الطوابق) تظهر ÙÙŠ الناÙذة المبوبة للعمليات كخيار ÙÙŠ القائمة المنبثقة. %s ÙÙŠ الرابط تÙستبدل بمعر٠التجزئة. سيتم Ùصل العناوين بخط Ø£Ùقي |.‬</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">‫&amp;عناوين عمليات أطرا٠أخرى‬</translation>
</message>
<message>
<source>Whether to show coin control features or not.</source>
- <translation type="unfinished">ما اذا أردت إظهار ميزات التحكم ÙÙŠ العملة أم لا.</translation>
+ <translation type="unfinished">‫ما اذا أردت إظهار ميزات التحكم ÙÙŠ وحدات البتكوين أم لا.‬</translation>
</message>
<message>
<source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
@@ -2051,15 +2349,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>embedded "%1"</source>
- <translation type="unfinished">المضمنة "%1"</translation>
+ <translation type="unfinished">‫مضمنة "%1"‬</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">يتم تجاوز الخيارات المعينة ÙÙŠ مربع الحوار هذا بواسطة سطر الأوامر أو ÙÙŠ مل٠التكوين:</translation>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">‫أقرب تطابق "%1"</translation>
</message>
<message>
<source>&amp;OK</source>
- <translation type="unfinished">تم</translation>
+ <translation type="unfinished">&amp;تم</translation>
</message>
<message>
<source>&amp;Cancel</source>
@@ -2068,7 +2366,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Compiled without external signing support (required for external signing)</source>
<extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
- <translation type="unfinished">مجمعة بدون دعم توقيع خارجي (مطلوب للتوقيع الخارجي)</translation>
+ <translation type="unfinished">‫مجمعة بدون دعم التوقيع الخارجي (مطلوب للتوقيع الخارجي)‬</translation>
</message>
<message>
<source>default</source>
@@ -2080,25 +2378,37 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">تأكيد استعادة الخيارات</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
- <translation type="unfinished">يتطلب إعادة تشغيل العميل لتÙعيل التغييرات.</translation>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
+ <translation type="unfinished">‫يجب إعادة تشغيل العميل لتÙعيل التغييرات.‬</translation>
+ </message>
+ <message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">‫سيتم النسخ الاحتياطي للاعدادات على “%1â€.‬".</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
- <translation type="unfinished">سو٠يتم إيقا٠العميل تماماً. هل تريد الإستمرار؟</translation>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
+ <translation type="unfinished">‫سو٠يتم إيقا٠العميل تماماً. هل تريد الإستمرار؟‬</translation>
</message>
<message>
<source>Configuration options</source>
<extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
- <translation type="unfinished">إعداد الخيارات</translation>
+ <translation type="unfinished">‫خيارات الإعداد‬</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>
<extracomment>Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</extracomment>
- <translation type="unfinished">يتم استخدام مل٠التكوين لتحديد خيارات المستخدم المتقدمة التي تتجاوز إعدادات واجهة المستخدم الرسومية. بالإضاÙØ© إلى ذلك ØŒ ستتجاوز أي خيارات سطر أوامر مل٠التكوين هذا.</translation>
+ <translation type="unfinished">‫يتم استخدام مل٠الإعداد لتحديد خيارات المستخدم المتقدمة التي تتجاوز إعدادات واجهة المستخدم الرسومية. بالإضاÙØ© إلى ذلك ØŒ ستتجاوز خيارات سطر الأوامر مل٠الإعداد هذا.‬</translation>
+ </message>
+ <message>
+ <source>Continue</source>
+ <translation type="unfinished">‫استمرار‬</translation>
</message>
<message>
<source>Cancel</source>
@@ -2110,7 +2420,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The configuration file could not be opened.</source>
- <translation type="unfinished">لم تتمكن من Ùتح مل٠الإعدادات.</translation>
+ <translation type="unfinished">‫لم تتمكن من Ùتح مل٠الإعداد.‬</translation>
</message>
<message>
<source>This change would require a client restart.</source>
@@ -2118,14 +2428,21 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The supplied proxy address is invalid.</source>
- <translation type="unfinished">عنوان الوكيل توÙيره غير صالح.</translation>
+ <translation type="unfinished">‫عنوان الوكيل الذي تم ادخاله غير صالح.‬</translation>
+ </message>
+</context>
+<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">‫لا يمكن قراءة الاعدادات “%1â€, %2.‬</translation>
</message>
</context>
<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
- <translation type="unfinished">نمودج</translation>
+ <translation type="unfinished">‫نموذج‬</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>
@@ -2133,15 +2450,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Watch-only:</source>
- <translation type="unfinished">مشاهدة Ùقط:</translation>
+ <translation type="unfinished">‫مراقبة Ùقط:‬</translation>
</message>
<message>
<source>Available:</source>
- <translation type="unfinished">متوÙر</translation>
+ <translation type="unfinished">‫متاح:‬</translation>
</message>
<message>
<source>Your current spendable balance</source>
- <translation type="unfinished">رصيدك القابل للصرÙ</translation>
+ <translation type="unfinished">‫الرصيد المتاح للصرÙ‬</translation>
</message>
<message>
<source>Pending:</source>
@@ -2153,7 +2470,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Immature:</source>
- <translation type="unfinished">غير ناضجة</translation>
+ <translation type="unfinished">‫غير ناضج:‬</translation>
</message>
<message>
<source>Mined balance that has not yet matured</source>
@@ -2173,7 +2490,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Your current balance in watch-only addresses</source>
- <translation type="unfinished">رصيدك الحالي ÙÙŠ العناوين المشاهدة Ùقط</translation>
+ <translation type="unfinished">‫رصيد عناوين المراقبة‬</translation>
</message>
<message>
<source>Spendable:</source>
@@ -2181,19 +2498,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Recent transactions</source>
- <translation type="unfinished">أحدث المعاملات</translation>
+ <translation type="unfinished">العمليات الأخيرة</translation>
</message>
<message>
<source>Unconfirmed transactions to watch-only addresses</source>
- <translation type="unfinished">معاملات غير مؤكدة للعناوين المشاهدة Ùقط</translation>
+ <translation type="unfinished">‫عمليات غير مؤكدة لعناوين المراقبة‬</translation>
</message>
<message>
<source>Mined balance in watch-only addresses that has not yet matured</source>
- <translation type="unfinished">الرصيد المعدّن ÙÙŠ العناوين المشاهدة Ùقط التي لم تنضج بعد</translation>
+ <translation type="unfinished">‫الرصيد المعدّن ÙÙŠ عناوين المراقبة الذي لم ينضج بعد‬</translation>
</message>
<message>
<source>Current total balance in watch-only addresses</source>
- <translation type="unfinished">الرصيد الإجمالي الحالي ÙÙŠ العناوين المشاهدة Ùقط</translation>
+ <translation type="unfinished">‫الرصيد الإجمالي الحالي ÙÙŠ عناوين المراقبة‬</translation>
</message>
<message>
<source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
@@ -2208,11 +2525,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Sign Tx</source>
- <translation type="unfinished">تسجيل Tx</translation>
+ <translation type="unfinished">‫توقيع العملية‬</translation>
</message>
<message>
<source>Broadcast Tx</source>
- <translation type="unfinished">بث TX</translation>
+ <translation type="unfinished">‫بث العملية‬</translation>
</message>
<message>
<source>Copy to Clipboard</source>
@@ -2220,7 +2537,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Save…</source>
- <translation type="unfinished">Ø­Ùظ ...</translation>
+ <translation type="unfinished">‫حÙظ…‬</translation>
</message>
<message>
<source>Close</source>
@@ -2228,43 +2545,47 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Failed to load transaction: %1</source>
- <translation type="unfinished">Ùشل تحميل المعاملة: %1</translation>
+ <translation type="unfinished">‫Ùشل تحميل العملية: %1‬</translation>
</message>
<message>
<source>Failed to sign transaction: %1</source>
<translation type="unfinished">Ùشل توقيع المعاملة: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">‫لا يمكن توقيع المدخلات والمحÙظة مقÙلة.‬</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">تعذر توقيع المزيد من المدخلات.</translation>
</message>
<message>
<source>Signed %1 inputs, but more signatures are still required.</source>
- <translation type="unfinished">تم توقيع %1 إدخالات، ولكن لا تزال هناك حاجة إلى المزيد من التوقيعات.</translation>
+ <translation type="unfinished">‫تم توقيع %1 مدخلات، مطلوب توقيعات اضاÙية.‬</translation>
</message>
<message>
<source>Signed transaction successfully. Transaction is ready to broadcast.</source>
- <translation type="unfinished">تم توقيع المعاملة بنجاح. المعاملة جاهزة للبث.</translation>
+ <translation type="unfinished">‫تم توقيع المعاملة بنجاح. العملية جاهزة للبث.‬</translation>
</message>
<message>
<source>Unknown error processing transaction.</source>
- <translation type="unfinished">خطأ غير معرو٠ÙÙŠ معالجة المعاملة.</translation>
+ <translation type="unfinished">‫خطأ غير معرو٠ÙÙŠ معالجة العملية.‬</translation>
</message>
<message>
<source>Transaction broadcast successfully! Transaction ID: %1</source>
- <translation type="unfinished">تم بث المعاملة بنجاح! معرّ٠المعاملة: %1</translation>
+ <translation type="unfinished">‫تم بث العملية بنجاح! معرّ٠العملية: %1‬</translation>
</message>
<message>
<source>Transaction broadcast failed: %1</source>
- <translation type="unfinished">Ùشل بث المعاملة: %1</translation>
+ <translation type="unfinished">‫Ùشل بث العملية: %1‬</translation>
</message>
<message>
<source>PSBT copied to clipboard.</source>
- <translation type="unfinished">نسخ PSBT إلى الحاÙظة.</translation>
+ <translation type="unfinished">‫نسخ المعاملة الموقعة جزئيا إلى الحاÙظة.‬</translation>
</message>
<message>
<source>Save Transaction Data</source>
- <translation type="unfinished">Ø­Ùظ بيانات المعاملات</translation>
+ <translation type="unfinished">‫حÙظ بيانات العملية‬</translation>
</message>
<message>
<source>Partially Signed Transaction (Binary)</source>
@@ -2273,7 +2594,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>PSBT saved to disk.</source>
- <translation type="unfinished">تم Ø­Ùظ PSBT على القرص.</translation>
+ <translation type="unfinished">‫تم Ø­Ùظ المعاملة الموقعة جزئيا على وحدة التخزين.‬</translation>
</message>
<message>
<source> * Sends %1 to %2</source>
@@ -2281,11 +2602,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unable to calculate transaction fee or total transaction amount.</source>
- <translation type="unfinished">غير قادر على حساب رسوم المعاملة أو إجمالي مبلغ المعاملة.</translation>
+ <translation type="unfinished">‫غير قادر على حساب رسوم العملية أو إجمالي قيمة العملية.‬</translation>
</message>
<message>
<source>Pays transaction fee: </source>
- <translation type="unfinished">دÙع رسوم المعاملة:</translation>
+ <translation type="unfinished">‫دÙع رسوم العملية: ‬</translation>
</message>
<message>
<source>Total Amount</source>
@@ -2296,6 +2617,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">أو</translation>
</message>
<message>
+ <source>Transaction has %1 unsigned inputs.</source>
+ <translation type="unfinished">‫المعاملة تحتوي على %1 من المدخلات غير موقعة.‬</translation>
+ </message>
+ <message>
<source>Transaction is missing some information about inputs.</source>
<translation type="unfinished">تÙتقد المعاملة إلى بعض المعلومات حول المدخلات </translation>
</message>
@@ -2304,20 +2629,24 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">المعاملة ما زالت تحتاج التوقيع.</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">‫(لكن لم يتم تحميل محÙظة.)‬</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
- <translation type="unfinished">.لكن هذه المخÙضة لا يمكنها توقيع للمعاملات</translation>
+ <translation type="unfinished">‫(لكن لا يمكن توقيع العمليات بهذه المحÙظة.)‬</translation>
</message>
<message>
<source>(But this wallet does not have the right keys.)</source>
- <translation type="unfinished">لكن هذه المحÙظة لا تحتوي على المÙاتيح الصحيحة.</translation>
+ <translation type="unfinished">‫(لكن هذه المحÙظة لا تحتوي على المÙاتيح الصحيحة.)‬</translation>
</message>
<message>
<source>Transaction is fully signed and ready for broadcast.</source>
- <translation type="unfinished"> الصÙقة موقعة بالكامل وجاهزة للبث</translation>
+ <translation type="unfinished">‫المعاملة موقعة بالكامل وجاهزة للبث.‬</translation>
</message>
<message>
<source>Transaction status is unknown.</source>
- <translation type="unfinished">حالة المعاملة غير معروÙØ©.</translation>
+ <translation type="unfinished">‫حالة العملية غير معروÙØ©.‬</translation>
</message>
</context>
<context>
@@ -2342,11 +2671,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Cannot process payment request because BIP70 is not supported.
Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
- <translation type="unfinished">لا يمكن معالجة طلب الدÙع لأن BIP70 غير مدعوم. نظرًا لوجود عيوب أمنية واسعة النطاق ÙÙŠ BIP70 ØŒ يوصى بشدة بتجاهل أي تعليمات تاجر لتبديل المحاÙظ. إذا كنت تتلقى هذا الخطأ ØŒ يجب أن تطلب من التاجر تقديم عنوان URI متواÙÙ‚ مع BIP21.</translation>
+ <translation type="unfinished">‫لا يمكن معالجة طلب الدÙع لأن BIP70 غير مدعوم.
+‬‫‫‫نظرًا لوجود عيوب أمنية كبيرة ÙÙŠ ‫BIP70 يوصى بشدة بتجاهل أي تعليمات من المستلمين لتبديل المحاÙظ.
+‬‫‫‫إذا كنت تتلقى هذا الخطأ ØŒ يجب أن تطلب من المستلم تقديم عنوان URI متواÙÙ‚ مع BIP21.‬</translation>
</message>
<message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
- <translation type="unfinished">لا يمكن تحليل العنوان (URI)! يمكن أن يحدث هذا بسبب عنوان بتكوين غير صالح أو معلمات عنوان (URI) غير صحيحة.</translation>
+ <translation type="unfinished">‫لا يمكن تحليل العنوان (URI)! يمكن أن يحدث هذا بسبب عنوان بتكوين غير صالح أو محددات عنوان غير صحيحة.‬</translation>
</message>
<message>
<source>Payment request file handling</source>
@@ -2371,6 +2702,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">الأقران</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">العمر</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">جهة</translation>
@@ -2383,12 +2719,12 @@ If you are receiving this error you should request the merchant provide a BIP21
<message>
<source>Received</source>
<extracomment>Title of Peers Table column which indicates the total amount of network information we have received from the peer.</extracomment>
- <translation type="unfinished">إستقبل</translation>
+ <translation type="unfinished">‫استÙلم‬</translation>
</message>
<message>
<source>Address</source>
<extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
- <translation type="unfinished">عنوان</translation>
+ <translation type="unfinished">العنوان</translation>
</message>
<message>
<source>Type</source>
@@ -2398,24 +2734,24 @@ If you are receiving this error you should request the merchant provide a BIP21
<message>
<source>Network</source>
<extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment>
- <translation type="unfinished">الشبكه</translation>
+ <translation type="unfinished">الشبكة</translation>
</message>
<message>
<source>Inbound</source>
<extracomment>An Inbound Connection from a Peer.</extracomment>
- <translation type="unfinished">داخل</translation>
+ <translation type="unfinished">‫وارد‬</translation>
</message>
<message>
<source>Outbound</source>
<extracomment>An Outbound Connection to a Peer.</extracomment>
- <translation type="unfinished">خارجي</translation>
+ <translation type="unfinished">‫صادر‬</translation>
</message>
</context>
<context>
<name>QRImageWidget</name>
<message>
<source>&amp;Save Image…</source>
- <translation type="unfinished">&amp;احÙظ الصورة…</translation>
+ <translation type="unfinished">&amp;احÙظ الصورة...</translation>
</message>
<message>
<source>&amp;Copy Image</source>
@@ -2423,19 +2759,19 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Resulting URI too long, try to reduce the text for label / message.</source>
- <translation type="unfinished">العنوان المستخدم طويل جدًا، حاول أن تقوم بتقليل نص التسمية / الرسالة.</translation>
+ <translation type="unfinished">‫العنوان الناتج طويل جدًا، حاول أن تقلص النص للمذكرة / الرسالة.‬</translation>
</message>
<message>
<source>Error encoding URI into QR Code.</source>
- <translation type="unfinished">خطأ ÙÙŠ ترميز العنوان إلى الرمز المربع.</translation>
+ <translation type="unfinished">‫خطأ ÙÙŠ ترميز العنوان إلى رمز الاستجابة السريع QR.‬</translation>
</message>
<message>
<source>QR code support not available.</source>
- <translation type="unfinished">دعم كود الـQR غير متوÙر.</translation>
+ <translation type="unfinished">‫دعم رمز الاستجابة السريع QR غير متوÙر.‬</translation>
</message>
<message>
<source>Save QR Code</source>
- <translation type="unfinished">Ø­Ùظ رمز الاستجابة السريعة QR</translation>
+ <translation type="unfinished">Ø­Ùظ رمز الاستجابة السريع QR</translation>
</message>
<message>
<source>PNG Image</source>
@@ -2451,11 +2787,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Client version</source>
- <translation type="unfinished">نسخه العميل</translation>
+ <translation type="unfinished">‫اصدار العميل‬</translation>
</message>
<message>
<source>&amp;Information</source>
- <translation type="unfinished">المعلومات</translation>
+ <translation type="unfinished">‫&amp;المعلومات‬</translation>
</message>
<message>
<source>General</source>
@@ -2463,11 +2799,19 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Datadir</source>
- <translation type="unfinished">دليل البيانات</translation>
+ <translation type="unfinished">‫مجلد البيانات‬</translation>
+ </message>
+ <message>
+ <source>To specify a non-default location of the data directory use the '%1' option.</source>
+ <translation type="unfinished">‫لتحديد مكان غير-Ø¥Ùتراضي لمجلد البيانات استخدم خيار الـ'%1'.‬</translation>
</message>
<message>
<source>Blocksdir</source>
- <translation type="unfinished">مل٠الكتل blocksdir</translation>
+ <translation type="unfinished">‫مجلد الطوابق‬</translation>
+ </message>
+ <message>
+ <source>To specify a non-default location of the blocks directory use the '%1' option.</source>
+ <translation type="unfinished">‫لتحديد مكان غير-Ø¥Ùتراضي لمجلد البيانات استخدم خيار الـ'"%1'.‬</translation>
</message>
<message>
<source>Startup time</source>
@@ -2475,7 +2819,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Network</source>
- <translation type="unfinished">الشبكه</translation>
+ <translation type="unfinished">الشبكة</translation>
</message>
<message>
<source>Name</source>
@@ -2495,7 +2839,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Current number of transactions</source>
- <translation type="unfinished">عدد المعاملات الحالي</translation>
+ <translation type="unfinished">عدد العمليات الحالي</translation>
</message>
<message>
<source>Memory usage</source>
@@ -2507,15 +2851,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>(none)</source>
- <translation type="unfinished">(لايوجد)</translation>
+ <translation type="unfinished">‫(لا شيء)‬</translation>
</message>
<message>
<source>&amp;Reset</source>
- <translation type="unfinished">إعادة تعيين</translation>
+ <translation type="unfinished">‫&amp;إعادة تعيين‬</translation>
</message>
<message>
<source>Received</source>
- <translation type="unfinished">إستقبل</translation>
+ <translation type="unfinished">‫مستلم‬</translation>
</message>
<message>
<source>Sent</source>
@@ -2523,15 +2867,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>&amp;Peers</source>
- <translation type="unfinished">&amp;اصدقاء</translation>
+ <translation type="unfinished">‫&amp;أقران‬</translation>
</message>
<message>
<source>Banned peers</source>
- <translation type="unfinished">الأقران الممنوعين</translation>
+ <translation type="unfinished">‫الأقران المحظورون‬</translation>
</message>
<message>
<source>Select a peer to view detailed information.</source>
- <translation type="unfinished">حدد نظير لعرض معلومات Ù…Ùصلة.</translation>
+ <translation type="unfinished">‫اختر قرينا لعرض معلومات Ù…Ùصلة.‬</translation>
</message>
<message>
<source>Version</source>
@@ -2539,23 +2883,57 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Starting Block</source>
- <translation type="unfinished">كتلة البداية</translation>
+ <translation type="unfinished">‫طابق البداية‬</translation>
</message>
<message>
<source>Synced Headers</source>
- <translation type="unfinished">رؤوس متزامنة</translation>
+ <translation type="unfinished">‫رؤوس مزامنة‬</translation>
</message>
<message>
<source>Synced Blocks</source>
- <translation type="unfinished">كتل متزامنة</translation>
+ <translation type="unfinished">‫طوابق مزامنة‬</translation>
+ </message>
+ <message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">‫آخر عملية‬</translation>
</message>
<message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
- <translation type="unfinished">يستخدم النظام المستقل المعين لتنويع اختيار الأقران.</translation>
+ <translation type="unfinished">‫النظام التÙصيلي المستقل المستخدم لتنويع اختيار الأقران.‬</translation>
</message>
<message>
<source>Mapped AS</source>
- <translation type="unfinished">تعيين AS</translation>
+ <translation type="unfinished">‫‫Mapped AS‬</translation>
+ </message>
+ <message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">‫توصيل العناوين لهذا القرين أم لا.‬</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">‫توصيل العنوان‬</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">‫مجموع العناوين المستلمة والمعالجة من هذا القرين (تستثنى العناوين المسقطة بسبب التقييد الحدي)‬</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">‫مجموع العناوين المستلمة والمسقطة من هذا القرين (غير معالجة) بسبب التقييد الحدي.‬</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">‫العناوين المعالجة‬</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">‫عناوين مقيدة حديا‬</translation>
</message>
<message>
<source>User Agent</source>
@@ -2563,11 +2941,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Node window</source>
- <translation type="unfinished">ناÙذة Node </translation>
+ <translation type="unfinished">‫ناÙذة نود‬</translation>
</message>
<message>
<source>Current block height</source>
- <translation type="unfinished">ارتÙاع الكتلة الحالي</translation>
+ <translation type="unfinished">‫ارتÙاع الطابق الحالي‬</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 type="unfinished">‫اÙتح %1 مل٠سجل المعالجة والتصحيح من مجلد البيانات الحالي. قد يستغرق عدة ثواني للسجلات الكبيرة.‬</translation>
</message>
<message>
<source>Decrease font size</source>
@@ -2591,7 +2973,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
- <translation type="unfinished">بروتوكول الشبكة الذي يتصل به هذا النظير من خلال: IPv4 أو IPv6 أو Onion أو I2P أو CJDNS.</translation>
+ <translation type="unfinished">‫بروتوكول الشبكة الذي يتصل به هذا القرين من خلال: IPv4 أو IPv6 أو Onion أو I2P أو CJDNS.‬</translation>
</message>
<message>
<source>Services</source>
@@ -2599,19 +2981,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Whether the peer requested us to relay transactions.</source>
- <translation type="unfinished">ما إذا كان الزميل قد طلب منا ترحيل المعاملات.</translation>
+ <translation type="unfinished">‫ما إذا كان القرين قد طلب توصيل العمليات.‬</translation>
</message>
<message>
<source>Wants Tx Relay</source>
- <translation type="unfinished">يريد Tx Relay</translation>
- </message>
- <message>
- <source>High bandwidth BIP152 compact block relay: %1</source>
- <translation type="unfinished">عرض النطاق الترددي العالي BIP152 كتلة التتابع المدمجة: %1</translation>
+ <translation type="unfinished">‫يريد موصل عمليات‬</translation>
</message>
<message>
<source>High Bandwidth</source>
- <translation type="unfinished">عرض النطاق الترددي العالي</translation>
+ <translation type="unfinished">‫نطاق بيانات عالي‬</translation>
</message>
<message>
<source>Connection Time</source>
@@ -2619,24 +2997,24 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
- <translation type="unfinished">الوقت المنقضي منذ استلام كتلة جديدة اجتياز اختبارات الصلاحية الأولية من هذا النظير.</translation>
+ <translation type="unfinished">‫الوقت المنقضي منذ استلام طابق جديد مجتاز لاختبارات الصلاحية الأولية من هذا القرين.‬</translation>
</message>
<message>
<source>Last Block</source>
- <translation type="unfinished">الكتلة الأخيرة </translation>
+ <translation type="unfinished">‫الطابق الأخير‬</translation>
</message>
<message>
<source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
<extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
- <translation type="unfinished">الوقت المنقضي منذ استلام معاملة جديدة تم قبولها ÙÙŠ مجموعة المذكرات الخاصة بنا من هذا النظير.</translation>
+ <translation type="unfinished">‫الوقت المنقضي منذ استلام عملية مقبولة ÙÙŠ تجمع الذاكرة من هذا النظير.‬</translation>
</message>
<message>
<source>Last Send</source>
- <translation type="unfinished">آخر استقبال</translation>
+ <translation type="unfinished">‫آخر ارسال‬</translation>
</message>
<message>
<source>Last Receive</source>
- <translation type="unfinished">آخر إرسال</translation>
+ <translation type="unfinished">‫آخر إستلام‬</translation>
</message>
<message>
<source>Ping Time</source>
@@ -2660,19 +3038,19 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Last block time</source>
- <translation type="unfinished">اخر وقت الكتلة</translation>
+ <translation type="unfinished">‫وقت اخر طابق‬</translation>
</message>
<message>
<source>&amp;Open</source>
- <translation type="unfinished">الÙتح</translation>
+ <translation type="unfinished">‫&amp;Ùتح‬</translation>
</message>
<message>
<source>&amp;Console</source>
- <translation type="unfinished">وحدة التحكم</translation>
+ <translation type="unfinished">‫&amp;سطر الأوامر‬</translation>
</message>
<message>
<source>&amp;Network Traffic</source>
- <translation type="unfinished">&amp;حركة مرور الشبكة</translation>
+ <translation type="unfinished">&amp;حركة الشبكة</translation>
</message>
<message>
<source>Totals</source>
@@ -2680,11 +3058,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Debug log file</source>
- <translation type="unfinished">تصحيح مل٠السجل</translation>
+ <translation type="unfinished">‫مل٠سجل تصحيح الأخطاء‬</translation>
</message>
<message>
<source>Clear console</source>
- <translation type="unfinished">مسح وحدة التحكم</translation>
+ <translation type="unfinished">‫مسح الأوامر‬</translation>
</message>
<message>
<source>In:</source>
@@ -2697,27 +3075,27 @@ If you are receiving this error you should request the merchant provide a BIP21
<message>
<source>Inbound: initiated by peer</source>
<extracomment>Explanatory text for an inbound peer connection.</extracomment>
- <translation type="unfinished">الواردة: بدأها النظير</translation>
+ <translation type="unfinished">‫الواردة: بدأها القرين‬</translation>
</message>
<message>
<source>Outbound Full Relay: default</source>
<extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment>
- <translation type="unfinished">ترحيل كامل صادر: اÙتراضي</translation>
+ <translation type="unfinished">‫الموصل الكامل الصادر: اÙتراضي‬</translation>
</message>
<message>
<source>Outbound Block Relay: does not relay transactions or addresses</source>
<extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment>
- <translation type="unfinished">ترحيل الكتلة الصادرة: لا يقوم بترحيل المعاملات أو العناوين</translation>
+ <translation type="unfinished">‫موصل الطابق الصادر: لا يقوم بتوصيل العمليات أو العناوين‬</translation>
</message>
<message>
<source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
<extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment>
- <translation type="unfinished">دليل الصادر: تمت إضاÙته باستخدام خيارات RPC %1 أو %2/%3 التكوين</translation>
+ <translation type="unfinished">‫دليل الصادر: مضا٠باستخدام نداء الاجراء البعيد RPC %1 أو %2/%3 خيارات الاعداد‬</translation>
</message>
<message>
<source>Outbound Feeler: short-lived, for testing addresses</source>
<extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment>
- <translation type="unfinished">أداة التجسس الصادرة: قصيرة الأجل ، لاختبار العناوين</translation>
+ <translation type="unfinished">‫أداة التÙقد الصادر: قصير الأجل ØŒ لاختبار العناوين‬</translation>
</message>
<message>
<source>Outbound Address Fetch: short-lived, for soliciting addresses</source>
@@ -2726,15 +3104,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>we selected the peer for high bandwidth relay</source>
- <translation type="unfinished">اخترنا النظير لترحيل النطاق الترددي العالي</translation>
+ <translation type="unfinished">‫اخترنا القرين لتوصيل نطاق البيانات العالي‬</translation>
</message>
<message>
<source>the peer selected us for high bandwidth relay</source>
- <translation type="unfinished">اختارنا النظير لترحيل النطاق الترددي العالي</translation>
+ <translation type="unfinished">‫القرين اختارنا لتوصيل بيانات ذات نطاق عالي‬</translation>
</message>
<message>
<source>no high bandwidth relay selected</source>
- <translation type="unfinished">لم يتم تحديد ترحيل النطاق الترددي العالي</translation>
+ <translation type="unfinished">‫لم يتم تحديد موصل للبيانات عالية النطاق‬</translation>
</message>
<message>
<source>Ctrl++</source>
@@ -2747,19 +3125,13 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">Ctrl + -</translation>
</message>
<message>
- <source>Ctrl+_</source>
- <extracomment>Secondary shortcut to decrease the RPC console font size.</extracomment>
- <translation type="unfinished">Ctrl+_
- </translation>
- </message>
- <message>
<source>&amp;Copy address</source>
<extracomment>Context menu action to copy the address of a peer.</extracomment>
- <translation type="unfinished">انسخ العنوان</translation>
+ <translation type="unfinished">&amp;انسخ العنوان</translation>
</message>
<message>
<source>&amp;Disconnect</source>
- <translation type="unfinished">قطع الاتصال</translation>
+ <translation type="unfinished">&amp;قطع الاتصال</translation>
</message>
<message>
<source>1 &amp;hour</source>
@@ -2779,7 +3151,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>&amp;Unban</source>
- <translation type="unfinished">رÙع الحظر</translation>
+ <translation type="unfinished">&amp;رÙع الحظر</translation>
</message>
<message>
<source>Network activity disabled</source>
@@ -2787,7 +3159,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Executing command without any wallet</source>
- <translation type="unfinished">تنÙيذ الأوامر بدون محÙظة </translation>
+ <translation type="unfinished">‫تنÙيذ الأوامر بدون أي محÙظة‬</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation type="unfinished">‫تنÙيذ الأوامر باستخدام "%1" من المحÙظة‬</translation>
</message>
<message>
<source>Executing…</source>
@@ -2795,6 +3171,10 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">جار التنÙيذ...</translation>
</message>
<message>
+ <source>(peer: %1)</source>
+ <translation type="unfinished">(قرين: %1)</translation>
+ </message>
+ <message>
<source>via %1</source>
<translation type="unfinished">خلال %1</translation>
</message>
@@ -2824,7 +3204,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Unknown</source>
- <translation type="unfinished">غير معرÙ</translation>
+ <translation type="unfinished">غير معروÙ</translation>
</message>
</context>
<context>
@@ -2835,7 +3215,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>&amp;Label:</source>
- <translation type="unfinished">&amp;وص٠:</translation>
+ <translation type="unfinished">&amp;المذكرة :</translation>
</message>
<message>
<source>&amp;Message:</source>
@@ -2843,7 +3223,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</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 type="unfinished">رسالة اختيارية لإرÙاقها بطلب الدÙع، والتي سيتم عرضها عند Ùتح الطلب. ملاحظة: لن يتم إرسال الرسالة مع الدÙعة عبر شبكة البتكوين.</translation>
+ <translation type="unfinished">‫رسالة اختيارية لإرÙاقها بطلب الدÙع، والتي سيتم عرضها عند Ùتح الطلب. ملاحظة: لن يتم إرسال الرسالة مع العملية عبر شبكة البتكوين.‬</translation>
</message>
<message>
<source>An optional label to associate with the new receiving address.</source>
@@ -2859,7 +3239,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
- <translation type="unfinished">ÙˆÙسم اختياري للربط مع عنوان الاستقبال (يستعمل من قبلك لتحديد Ùاتورة). هو أيضا مرÙÙ‚ بطلب الدÙع.</translation>
+ <translation type="unfinished">‫مذكرة اختيارية للربط مع عنوان الاستلام (يستعمل من قبلك لتعري٠Ùاتورة). هو أيضا مرÙÙ‚ بطلب الدÙع.‬</translation>
</message>
<message>
<source>An optional message that is attached to the payment request and may be displayed to the sender.</source>
@@ -2867,11 +3247,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>&amp;Create new receiving address</source>
- <translation type="unfinished">و إنشاء عناوين استقبال جديدة</translation>
+ <translation type="unfinished">&amp;إنشاء عناوين استلام جديدة</translation>
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation type="unfinished">مسح كل حقول النموذج المطلوبة</translation>
+ <translation type="unfinished">‫مسح كل الحقول من النموذج.‬</translation>
</message>
<message>
<source>Clear</source>
@@ -2899,38 +3279,42 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Copy &amp;URI</source>
- <translation type="unfinished">نسخ &amp;URI</translation>
+ <translation type="unfinished">‫نسخ &amp;الرابط (URI)‬</translation>
</message>
<message>
<source>&amp;Copy address</source>
- <translation type="unfinished">انسخ العنوان</translation>
+ <translation type="unfinished">‫&amp;نسخ العنوان‬</translation>
</message>
<message>
<source>Copy &amp;label</source>
- <translation type="unfinished">نسخ Ùˆ تصنيÙ</translation>
+ <translation type="unfinished">‫نسخ &amp;مذكرة‬</translation>
</message>
<message>
<source>Copy &amp;message</source>
- <translation type="unfinished">نسخ و ارسال </translation>
+ <translation type="unfinished">‫نسخ &amp;رسالة‬</translation>
</message>
<message>
<source>Copy &amp;amount</source>
- <translation type="unfinished">نسخ &amp;مبلغ</translation>
+ <translation type="unfinished">‫نسخ &amp;القيمة‬</translation>
</message>
<message>
<source>Could not unlock wallet.</source>
- <translation type="unfinished"> يمكن Ùتح المحÙظة.</translation>
+ <translation type="unfinished">‫تعذر Ùتح المحÙظة.‬</translation>
+ </message>
+ <message>
+ <source>Could not generate new %1 address</source>
+ <translation type="unfinished">تعذر توليد عنوان %1 جديد.</translation>
</message>
- </context>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
<source>Request payment to …</source>
- <translation type="unfinished"> طلب الدÙع لـ....</translation>
+ <translation type="unfinished"> طلب الدÙع لـ ...</translation>
</message>
<message>
<source>Address:</source>
- <translation type="unfinished">العناوين:</translation>
+ <translation type="unfinished">العنوان:</translation>
</message>
<message>
<source>Amount:</source>
@@ -2938,11 +3322,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Label:</source>
- <translation type="unfinished">وسم:</translation>
+ <translation type="unfinished">مذكرة:</translation>
</message>
<message>
<source>Message:</source>
- <translation type="unfinished">الرسائل</translation>
+ <translation type="unfinished">رسالة:</translation>
</message>
<message>
<source>Wallet:</source>
@@ -2950,7 +3334,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Copy &amp;URI</source>
- <translation type="unfinished">نسخ &amp;URI</translation>
+ <translation type="unfinished">‫نسخ &amp;الرابط (URI)‬</translation>
</message>
<message>
<source>Copy &amp;Address</source>
@@ -2958,7 +3342,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>&amp;Verify</source>
- <translation type="unfinished">تأكيد</translation>
+ <translation type="unfinished">&amp;تحقق</translation>
+ </message>
+ <message>
+ <source>Verify this address on e.g. a hardware wallet screen</source>
+ <translation type="unfinished">تحقق من العنوان على شاشة المحÙظة الخارجية</translation>
</message>
<message>
<source>&amp;Save Image…</source>
@@ -2981,7 +3369,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Label</source>
- <translation type="unfinished">وسم</translation>
+ <translation type="unfinished">المذكرة</translation>
</message>
<message>
<source>Message</source>
@@ -2989,7 +3377,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(بدون وسم)</translation>
+ <translation type="unfinished">( لا وجود لمذكرة)</translation>
</message>
<message>
<source>(no message)</source>
@@ -2997,7 +3385,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>(no amount requested)</source>
- <translation type="unfinished">(لا يوجد مبلغ مطلوب)</translation>
+ <translation type="unfinished">(لا يوجد قيمة مطلوبة)</translation>
</message>
<message>
<source>Requested</source>
@@ -3008,11 +3396,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
- <translation type="unfinished">إرسال العملات</translation>
+ <translation type="unfinished">إرسال البتكوين</translation>
</message>
<message>
<source>Coin Control Features</source>
- <translation type="unfinished">ميزات التحكم بالعملة</translation>
+ <translation type="unfinished">‫ميزات التحكم بوحدات البتكوين‬</translation>
</message>
<message>
<source>automatically selected</source>
@@ -3032,7 +3420,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Amount:</source>
- <translation type="unfinished">القيمة :</translation>
+ <translation type="unfinished">القيمة:</translation>
</message>
<message>
<source>Fee:</source>
@@ -3040,15 +3428,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>After Fee:</source>
- <translation type="unfinished">بعد الرسوم :</translation>
+ <translation type="unfinished">بعد الرسوم:</translation>
</message>
<message>
<source>Change:</source>
- <translation type="unfinished">تعديل :</translation>
+ <translation type="unfinished">تعديل:</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 type="unfinished">إذا تم تنشيط هذا، ولكن عنوان الÙكة Ùارغ أو غير صالح، Ùسيتم إرسال الÙكة إلى عنوان تم إنشاؤه حديثًا.</translation>
+ <translation type="unfinished">‫إذا تم تنشيط هذا، ولكن عنوان الÙكة Ùارغ أو غير صالح، Ùسيتم إرسال الÙكة إلى عنوان مولّد حديثًا.‬</translation>
</message>
<message>
<source>Custom change address</source>
@@ -3060,7 +3448,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</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 type="unfinished">يمكن أن يؤدي استخدام الرسوم الاحتياطية إلى إرسال معاملة تستغرق عدة ساعات أو أيام (أو أبدًا) للتأكيد. ضع ÙÙŠ اعتبارك اختيار الرسوم يدويًا أو انتظر حتى تتحقق من صحة السلسلة الكاملة.</translation>
+ <translation type="unfinished">‫يمكن أن يؤدي استخدام الرسوم الاحتياطية إلى إرسال معاملة تستغرق عدة ساعات أو أيام (أو أبدًا) للتأكيد. ضع ÙÙŠ اعتبارك اختيار الرسوم يدويًا أو انتظر حتى تتحقق من صحة المتتالية الكاملة.‬</translation>
</message>
<message>
<source>Warning: Fee estimation is currently not possible.</source>
@@ -3092,11 +3480,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation type="unfinished">مسح كل حقول النموذج المطلوبة</translation>
+ <translation type="unfinished">‫مسح كل الحقول من النموذج.‬</translation>
</message>
<message>
<source>Inputs…</source>
- <translation type="unfinished">المدخلات </translation>
+ <translation type="unfinished">المدخلات...</translation>
</message>
<message>
<source>Dust:</source>
@@ -3104,19 +3492,31 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Choose…</source>
- <translation type="unfinished">اختيار </translation>
+ <translation type="unfinished">اختيار...</translation>
</message>
<message>
<source>Hide transaction fee settings</source>
<translation type="unfinished">اخÙاء اعدادات رسوم المعاملة</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 rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation type="unfinished">‫حدد الرسوم المخصصة لكل كيلوبايت (١٠٠٠ بايت) من حجم العملية الاÙتراضي.
+
+ملاحظة: بما أن الرسوم تحتسب لكل بايت، معدل الرسوم Ù„ “ ١٠٠ ساتوشي لكل كيلوبايت اÙتراضي†لعملية بحجم ٥٠٠ بايت اÙتراضي (نص٠كيلوبايت اÙتراضي) ستكون ٥٠ ساتوشي Ùقط.‬</translation>
+ </message>
+ <message>
<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>
+ <translation type="unfinished">‫قد ÙŠÙرض المعدنون والأنواد الموصلة حدا أدنى للرسوم عندما يكون عدد العمليات قليل نسبة لسعة الطوابق. يمكنك دÙع الحد الأدنى ولكن كن على دراية بأن العملية قد لا تنÙØ° ÙÙŠ حالة أن الطلب على عمليات البتكوين Ùاق قدرة الشبكة على المعالجة.‬</translation>
</message>
<message>
<source>A too low fee might result in a never confirming transaction (read the tooltip)</source>
- <translation type="unfinished">رسوم قليلة جدا من الممكن أن تؤدي الى معاملة لن تتأكد أبدا (اقرأ التلميح).</translation>
+ <translation type="unfinished">‫الرسوم القليلة جدا قد تؤدي الى عملية لا تتأكد أبدا (اقرأ التلميح).‬</translation>
+ </message>
+ <message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source>
+ <translation type="unfinished">‫(الرسوم الذكية غير مهيأة بعد. عادة يتطلب عدة طوابق…)‬</translation>
</message>
<message>
<source>Confirmation time target:</source>
@@ -3128,7 +3528,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</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 type="unfinished">مع الإستبدال بواسطة الرسوم (BIP-125) يمكنك زيادة رسوم المعاملة بعد إرسالها. وبدون ذلك، قد نوصي برسوم أعلى للتعويض عن مخاطر تأخير المعاملة المتزايدة.</translation>
+ <translation type="unfinished">‫يمكنك زيادة رسوم المعاملة بعد إرسالها عند تÙعيل الاستبدال بواسطة الرسوم (BIP-125). نوصي بوضع رسوم أعلى اذا لم يتم التÙعيل لتÙادي مخاطر تأخير العملية.‬</translation>
</message>
<message>
<source>Clear &amp;All</source>
@@ -3144,7 +3544,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>S&amp;end</source>
- <translation type="unfinished">&amp;ارسال</translation>
+ <translation type="unfinished">‫ا&amp;رسال‬</translation>
</message>
<message>
<source>Copy quantity</source>
@@ -3172,47 +3572,63 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Copy change</source>
- <translation type="unfinished">نسخ التعديل</translation>
+ <translation type="unfinished">‫نسخ الÙكة‬</translation>
</message>
<message>
<source>%1 (%2 blocks)</source>
- <translation type="unfinished">%1 (%2 كثلة)</translation>
+ <translation type="unfinished">%1 (%2 طوابق)</translation>
</message>
<message>
<source>Sign on device</source>
<extracomment>"device" usually means a hardware wallet.</extracomment>
- <translation type="unfinished">ولوج الى المحÙظة </translation>
+ <translation type="unfinished">‫جهاز التوقيع‬</translation>
</message>
<message>
<source>Connect your hardware wallet first.</source>
- <translation type="unfinished">قم بتوصيل جهاز المحÙظة أولا </translation>
+ <translation type="unfinished">‫قم بتوصيل المحÙظة الخارجية أولا.‬</translation>
+ </message>
+ <message>
+ <source>Set external signer script path in Options -&gt; Wallet</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">‫أعد المسار البرمجي للموقع الخارجي من خيارات -&gt; محÙظة‬</translation>
</message>
<message>
<source>Cr&amp;eate Unsigned</source>
- <translation type="unfinished">إنشاء غير موقع
- </translation>
+ <translation type="unfinished">‫إن&amp;شاء من غير توقيع‬</translation>
+ </message>
+ <message>
+ <source> from wallet '%1'</source>
+ <translation type="unfinished">من المحÙظة '%1'</translation>
+ </message>
+ <message>
+ <source>%1 to '%2'</source>
+ <translation type="unfinished">%1 الى "%2"</translation>
</message>
<message>
<source>%1 to %2</source>
<translation type="unfinished">%1 الى %2</translation>
</message>
<message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">‫لمراجعة قائمة المستلمين انقر على “عرض التÙاصيل…â€â€¬</translation>
+ </message>
+ <message>
<source>Sign failed</source>
- <translation type="unfinished">Ùشل التسجيل</translation>
+ <translation type="unfinished">‫Ùشل التوقيع‬</translation>
</message>
<message>
<source>External signer not found</source>
<extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
- <translation type="unfinished">لم يتم العثور على تسجيل خارجي</translation>
+ <translation type="unfinished">‫لم يتم العثور على موقّع خارجي‬</translation>
</message>
<message>
<source>External signer failure</source>
<extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
- <translation type="unfinished">Ùشل التسجيل الخارجي</translation>
+ <translation type="unfinished">‫Ùشل الموقّع الخارجي‬</translation>
</message>
<message>
<source>Save Transaction Data</source>
- <translation type="unfinished">Ø­Ùظ بيانات المعاملات</translation>
+ <translation type="unfinished">Ø­Ùظ بيانات العملية</translation>
</message>
<message>
<source>Partially Signed Transaction (Binary)</source>
@@ -3233,7 +3649,22 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
- <translation type="unfinished">يمكنك زيادة الرسوم لاحقًا (بإشارة الإستبدال بواسطة الرسوم، BIP-125).</translation>
+ <translation type="unfinished">‫يمكنك زيادة الرسوم لاحقًا (الاستبدال بواسطة الرسوم، BIP-125 Ù…Ùعل).‬</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment>
+ <translation type="unfinished">‫رجاء، راجع معاملتك. هذا ينشئ معاملة بتكوين موقعة جزئيا (PSBT) ويمكنك Ø­Ùظها أو نسخها Ùˆ التوقيع مع محÙظة %1 غير متصلة بالشبكة، أو محÙظة خارجية متواÙقة مع الـPSBT.‬</translation>
+ </message>
+ <message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">‫هل تريد انشاء هذه المعاملة؟‬</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">‫رجاء، راجع معاملتك.تستطيع انشاء وارسال هذه العملية أو انشاء معاملة بتكوين موقعة جزئيا (PSBT) ويمكنك Ø­Ùظها أو نسخها Ùˆ التوقيع مع محÙظة %1 غير متصلة بالشبكة، أو محÙظة خارجية متواÙقة مع الـPSBT.‬</translation>
</message>
<message>
<source>Please, review your transaction.</source>
@@ -3246,7 +3677,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Not signalling Replace-By-Fee, BIP-125.</source>
- <translation type="unfinished">لا يشير إلى الإستبدال بواسطة الرسوم، BIP-125.</translation>
+ <translation type="unfinished">‫الاستبدال بواسطة الرسوم، BIP-125 غير Ù…Ùعلة.‬</translation>
</message>
<message>
<source>Total Amount</source>
@@ -3254,23 +3685,23 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Confirm send coins</source>
- <translation type="unfinished">تأكيد الإرسال Coins</translation>
+ <translation type="unfinished">‫تأكيد ارسال وحدات البتكوين‬</translation>
</message>
<message>
<source>Watch-only balance:</source>
- <translation type="unfinished">رصيد للاستعراض Ùقط:</translation>
+ <translation type="unfinished">‫رصيد المراقبة:‬</translation>
</message>
<message>
<source>The recipient address is not valid. Please recheck.</source>
- <translation type="unfinished">عنوان المستلم غير صالح. يرجى إعادة الÙحص.</translation>
+ <translation type="unfinished">‫عنوان المستلم غير صالح. يرجى مراجعة العنوان.‬</translation>
</message>
<message>
<source>The amount to pay must be larger than 0.</source>
- <translation type="unfinished">المبلغ المدÙوع يجب ان يكون اكبر من 0</translation>
+ <translation type="unfinished">‫القيمة المدÙوعة يجب ان تكون اكبر من 0.‬</translation>
</message>
<message>
<source>The amount exceeds your balance.</source>
- <translation type="unfinished">القيمة تتجاوز رصيدك</translation>
+ <translation type="unfinished">القيمة تتجاوز رصيدك.</translation>
</message>
<message>
<source>The total exceeds your balance when the %1 transaction fee is included.</source>
@@ -3278,29 +3709,25 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Duplicate address found: addresses should only be used once each.</source>
- <translation type="unfinished">تم العثور على عنوان مكرر: يجب استخدام العناوين مرة واحدة Ùقط.</translation>
+ <translation type="unfinished">‫تم العثور على عنوان مكرر: من الأÙضل استخدام العناوين مرة واحدة Ùقط.‬</translation>
</message>
<message>
<source>Transaction creation failed!</source>
- <translation type="unfinished">Ùشل ÙÙŠ إنشاء المعاملة!</translation>
+ <translation type="unfinished">‫تعذر إنشاء المعاملة!‬</translation>
</message>
<message>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">تعتبر الرسوم الأعلى من %1 رسوماً باهظة.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">انتهاء صلاحية طلب الدÙع.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
+ <numerusform>‫الوقت التقديري للنÙاذ خلال %n طوابق.‬</numerusform>
</translation>
</message>
<message>
@@ -3317,11 +3744,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</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 type="unfinished">العنوان الذي قمت بتحديده للتغيير ليس جزءا من هذه المحÙظة. أي أو جميع الأموال ÙÙŠ محÙظتك قد يتم إرسالها لهذا العنوان. هل أنت متأكد؟</translation>
+ <translation type="unfinished">‫العنوان الذي قمت بتحديده للÙكة ليس جزءا من هذه المحÙظة. بعض أو جميع الأموال ÙÙŠ محÙظتك قد يتم إرسالها لهذا العنوان. هل أنت متأكد؟‬</translation>
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(بدون وسم)</translation>
+ <translation type="unfinished">( لا وجود لمذكرة)</translation>
</message>
</context>
<context>
@@ -3336,35 +3763,35 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>&amp;Label:</source>
- <translation type="unfinished">&amp;وص٠:</translation>
+ <translation type="unfinished">&amp;مذكرة :</translation>
</message>
<message>
<source>Choose previously used address</source>
- <translation type="unfinished">اختر عنوانا مستخدم سابقا</translation>
+ <translation type="unfinished">‫اختر عنوانا تم استخدامه سابقا‬</translation>
</message>
<message>
<source>The Bitcoin address to send the payment to</source>
- <translation type="unfinished">عنوان البت كوين المرسل اليه الدÙع</translation>
+ <translation type="unfinished">‫عنوان البتكوين لارسال الدÙعة له‬</translation>
</message>
<message>
<source>Paste address from clipboard</source>
- <translation type="unfinished">انسخ العنوان من لوحة المÙاتيح</translation>
+ <translation type="unfinished">‫الصق العنوان من الحاÙظة‬</translation>
</message>
<message>
<source>Remove this entry</source>
- <translation type="unfinished">ازل هذه المداخله</translation>
+ <translation type="unfinished">‫ازل هذا المدخل‬</translation>
</message>
<message>
<source>The amount to send in the selected unit</source>
- <translation type="unfinished">المبلغ للإرسال ÙÙŠ الوحدة المحددة</translation>
+ <translation type="unfinished">‫القيمة للإرسال ÙÙŠ الوحدة المحددة‬</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 type="unfinished">سيتم خصم الرسوم من المبلغ الذي يتم إرساله. لذا سو٠يتلقى المستلم مبلغ أقل من البتكوين المدخل ÙÙŠ حقل المبلغ. ÙÙŠ حالة تحديد عدة مستلمين، يتم تقسيم الرسوم بالتساوي.</translation>
+ <translation type="unfinished">‫سيتم خصم الرسوم من المبلغ الذي يتم إرساله. لذا سو٠يتلقى المستلم قيمة أقل من البتكوين المدخل ÙÙŠ حقل القيمة. ÙÙŠ حالة تحديد عدة مستلمين، يتم تقسيم الرسوم بالتساوي.‬</translation>
</message>
<message>
<source>S&amp;ubtract fee from amount</source>
- <translation type="unfinished">طرح الرسوم من المبلغ</translation>
+ <translation type="unfinished">‫ط&amp;رح الرسوم من القيمة‬</translation>
</message>
<message>
<source>Use available balance</source>
@@ -3372,31 +3799,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Message:</source>
- <translation type="unfinished">الرسائل</translation>
- </message>
- <message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">هذا طلب دÙع لم يتم مصادقته.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">هذا طلب دÙع تمت مصادقته.</translation>
+ <translation type="unfinished">‫رسالة:‬</translation>
</message>
<message>
<source>Enter a label for this address to add it to the list of used addresses</source>
- <translation type="unfinished">أدخل تسمية لهذا العنوان لإضاÙته إلى قائمة العناوين المستخدمة</translation>
+ <translation type="unfinished">‫أدخل مذكرة لهذا العنوان لإضاÙته إلى قائمة العناوين المستخدمة‬</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 type="unfinished">الرسالة التي تم إرÙاقها مع البتكوين: العنوان الذي سيتم تخزينه مع المعاملة للرجوع إليه. ملاحظة: لن يتم إرسال هذه الرسالة عبر شبكة البتكوين.</translation>
- </message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">ادÙع &amp;الى :</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">مذكرة:</translation>
+ <translation type="unfinished">‫الرسالة يتم إرÙاقها مع البتكوين: الرابط سيتم تخزينه مع العملية لك للرجوع إليه. ملاحظة: لن يتم إرسال هذه الرسالة عبر شبكة البتكوين.‬</translation>
</message>
</context>
<context>
@@ -3414,7 +3825,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<name>SignVerifyMessageDialog</name>
<message>
<source>Signatures - Sign / Verify a Message</source>
- <translation type="unfinished">التواقيع - التوقيع / التحقق من الرسالة</translation>
+ <translation type="unfinished">التواقيع - التوقيع / تحقق من الرسالة</translation>
</message>
<message>
<source>&amp;Sign Message</source>
@@ -3422,11 +3833,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</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 type="unfinished">تستطيع توقيع رسائل/اتÙاقات مع عناوينك لإثبات أنه بإمكانك استقبال بتكوين مرسل إليهم. كن حذرا من عدم توقيع أي شيء غامض أو عشوائي، كهجمات التصيد التي قد تحاول خداعك لتوقيع هويتك لديهم. وقع البيانات المÙصلة بالكامل والتي أنت تواÙÙ‚ عليها Ùقط.</translation>
+ <translation type="unfinished">‫تستطيع توقيع رسائل/اتÙاقيات من عناوينك لإثبات أنه بإمكانك استلام بتكوين مرسل لهذه العناوين. كن حذرا من توقيع أي شيء غامض أو عشوائي، هجمات التصيد قد تحاول خداعك وانتحال هويتك. وقع البيانات الواضحة بالكامل والتي تواÙÙ‚ عليها Ùقط.‬</translation>
</message>
<message>
<source>The Bitcoin address to sign the message with</source>
- <translation type="unfinished">عنوان البتكوين لتوقيع الرسالة به</translation>
+ <translation type="unfinished">عنوان البتكوين لتوقيع الرسالة منه</translation>
</message>
<message>
<source>Choose previously used address</source>
@@ -3434,7 +3845,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Paste address from clipboard</source>
- <translation type="unfinished">انسخ العنوان من لوحة المÙاتيح</translation>
+ <translation type="unfinished">‫ألصق العنوان من الحاÙظة‬</translation>
</message>
<message>
<source>Enter the message you want to sign here</source>
@@ -3450,15 +3861,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Sign the message to prove you own this Bitcoin address</source>
- <translation type="unfinished">وقع الرسالة لتثبت انك تمتلك عنوان البت كوين هذا</translation>
+ <translation type="unfinished">‫وقع الرسالة لتثبت انك تملك عنوان البتكوين هذا‬</translation>
</message>
<message>
<source>Sign &amp;Message</source>
- <translation type="unfinished">توقيع $الرسالة</translation>
+ <translation type="unfinished">توقيع &amp;الرسالة</translation>
</message>
<message>
<source>Reset all sign message fields</source>
- <translation type="unfinished">إعادة تعيين كاÙØ© حقول رسالة التوقيع</translation>
+ <translation type="unfinished">‫إعادة تعيين كاÙØ© حقول توقيع الرسالة‬</translation>
</message>
<message>
<source>Clear &amp;All</source>
@@ -3466,7 +3877,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>&amp;Verify Message</source>
- <translation type="unfinished">&amp;تحقق رسالة</translation>
+ <translation type="unfinished">‫&amp;تحقق من الرسالة‬</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>
@@ -3474,7 +3885,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>The Bitcoin address the message was signed with</source>
- <translation type="unfinished">عنوان البتكوين الذي تم توقيع الرسالة به</translation>
+ <translation type="unfinished">عنوان البتكوين الذي تم توقيع الرسالة منه</translation>
</message>
<message>
<source>The signed message to verify</source>
@@ -3482,15 +3893,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>The signature given when the message was signed</source>
- <translation type="unfinished">التوقيع يعطى عندما تكون الرسالة موقعة.</translation>
+ <translation type="unfinished">‫التوقيع المعطى عند توقيع الرسالة‬</translation>
</message>
<message>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
- <translation type="unfinished">تحقق من الرسالة للتأكد من توقيعها مع عنوان البتكوين المحدد</translation>
+ <translation type="unfinished">‫تحقق من الرسالة للتأكد أنه تم توقيعها من عنوان البتكوين المحدد‬</translation>
</message>
<message>
<source>Verify &amp;Message</source>
- <translation type="unfinished">تحقق &amp;الرسالة</translation>
+ <translation type="unfinished">تحقق من &amp;الرسالة</translation>
</message>
<message>
<source>Reset all verify message fields</source>
@@ -3498,7 +3909,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Click "Sign Message" to generate signature</source>
- <translation type="unfinished">اضغط "توقيع الرسالة" لتوليد التوقيع</translation>
+ <translation type="unfinished">‫انقر "توقيع الرسالة" لانشاء التوقيع‬</translation>
</message>
<message>
<source>The entered address is invalid.</source>
@@ -3506,15 +3917,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Please check the address and try again.</source>
- <translation type="unfinished">الرجاء التأكد من العنوان والمحاولة مرة اخرى</translation>
+ <translation type="unfinished">الرجاء التأكد من العنوان والمحاولة مرة اخرى.</translation>
</message>
<message>
<source>The entered address does not refer to a key.</source>
- <translation type="unfinished">العنوان المدخل لا يشير الى Ù…Ùتاح</translation>
+ <translation type="unfinished">العنوان المدخل لا يشير الى Ù…Ùتاح.</translation>
</message>
<message>
<source>Wallet unlock was cancelled.</source>
- <translation type="unfinished">تم الغاء عملية Ùتح المحÙظة</translation>
+ <translation type="unfinished">تم الغاء عملية Ùتح المحÙظة.</translation>
</message>
<message>
<source>No error</source>
@@ -3522,7 +3933,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Private key for the entered address is not available.</source>
- <translation type="unfinished">المÙتاح الخاص للعنوان المدخل غير موجود.</translation>
+ <translation type="unfinished">‫المÙتاح الخاص للعنوان المدخل غير متاح.‬</translation>
</message>
<message>
<source>Message signing failed.</source>
@@ -3554,6 +3965,17 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
</context>
<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished">‫(انقر q للاغلاق والمواصلة لاحقا)‬</translation>
+ </message>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">‫انقر q للاغلاق‬</translation>
+ </message>
+</context>
+<context>
<name>TrafficGraphWidget</name>
<message>
<source>kB/s</source>
@@ -3564,26 +3986,32 @@ If you are receiving this error you should request the merchant provide a BIP21
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
- <translation type="unfinished">تعارضت مع معاملة لديها %1 تأكيدات</translation>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
+ <translation type="unfinished">‫تعارضت مع عملية أخرى تم تأكيدها %1</translation>
</message>
<message>
- <source>in memory pool</source>
- <translation type="unfinished">ÙÙŠ تجمع الذاكرة</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">‫0/غير مؤكدة، ÙÙŠ تجمع الذاكرة‬</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">ليس ÙÙŠ تجمع الذاكرة</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">‫0/غير مؤكدة، ليست ÙÙŠ تجمع الذاكرة‬</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">مهجور</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">غير مؤكدة/%1</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">تأكيد %1</translation>
</message>
<message>
@@ -3600,7 +4028,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Generated</source>
- <translation type="unfinished">تم اصداره.</translation>
+ <translation type="unfinished">‫مÙصدر‬</translation>
</message>
<message>
<source>From</source>
@@ -3620,25 +4048,21 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>watch-only</source>
- <translation type="unfinished">مشاهدة Ùقط</translation>
+ <translation type="unfinished">‫مراقبة Ùقط‬</translation>
</message>
<message>
<source>label</source>
- <translation type="unfinished">علامة</translation>
- </message>
- <message>
- <source>Credit</source>
- <translation type="unfinished">رصيد</translation>
+ <translation type="unfinished">‫مذكرة‬</translation>
</message>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>matures in %n more block(s)</numerusform>
+ <numerusform>matures in %n more block(s)</numerusform>
+ <numerusform>matures in %n more block(s)</numerusform>
+ <numerusform>matures in %n more block(s)</numerusform>
+ <numerusform>matures in %n more block(s)</numerusform>
+ <numerusform>matures in %n more block(s)</numerusform>
</translation>
</message>
<message>
@@ -3646,24 +4070,12 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">غير مقبولة</translation>
</message>
<message>
- <source>Debit</source>
- <translation type="unfinished">دين</translation>
- </message>
- <message>
- <source>Total debit</source>
- <translation type="unfinished">إجمالي الخصم</translation>
- </message>
- <message>
- <source>Total credit</source>
- <translation type="unfinished">إجمالي الرصيد</translation>
- </message>
- <message>
<source>Transaction fee</source>
- <translation type="unfinished">رسوم المعاملة</translation>
+ <translation type="unfinished">رسوم العملية</translation>
</message>
<message>
<source>Net amount</source>
- <translation type="unfinished">صاÙÙŠ المبلغ</translation>
+ <translation type="unfinished">‫صاÙÙŠ القيمة‬</translation>
</message>
<message>
<source>Message</source>
@@ -3675,11 +4087,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Transaction ID</source>
- <translation type="unfinished">رقم المعاملة</translation>
+ <translation type="unfinished">‫رقم العملية‬</translation>
</message>
<message>
<source>Transaction total size</source>
- <translation type="unfinished">الحجم الكلي للمعاملات</translation>
+ <translation type="unfinished">الحجم الكلي ‫للعملية‬</translation>
</message>
<message>
<source>Transaction virtual size</source>
@@ -3703,7 +4115,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Transaction</source>
- <translation type="unfinished">معاملة</translation>
+ <translation type="unfinished">‫عملية‬</translation>
</message>
<message>
<source>Inputs</source>
@@ -3711,7 +4123,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Amount</source>
- <translation type="unfinished">مبلغ</translation>
+ <translation type="unfinished">‫القيمة‬</translation>
</message>
<message>
<source>true</source>
@@ -3745,7 +4157,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Label</source>
- <translation type="unfinished">وسم</translation>
+ <translation type="unfinished">المذكرة</translation>
</message>
<message>
<source>Unconfirmed</source>
@@ -3761,7 +4173,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Confirmed (%1 confirmations)</source>
- <translation type="unfinished">مؤكد (%1 تأكيدات)</translation>
+ <translation type="unfinished">‫ناÙØ° (%1 تأكيدات)‬</translation>
</message>
<message>
<source>Conflicted</source>
@@ -3773,15 +4185,15 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Generated but not accepted</source>
- <translation type="unfinished">ولدت ولكن لم تقبل</translation>
+ <translation type="unfinished">ولّدت ولكن لم تقبل</translation>
</message>
<message>
<source>Received with</source>
- <translation type="unfinished">استقبل مع</translation>
+ <translation type="unfinished">‫استلم Ùي‬</translation>
</message>
<message>
<source>Received from</source>
- <translation type="unfinished">استقبل من</translation>
+ <translation type="unfinished">‫استلم من</translation>
</message>
<message>
<source>Sent to</source>
@@ -3792,8 +4204,12 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">دÙع لنÙسك</translation>
</message>
<message>
+ <source>Mined</source>
+ <translation type="unfinished">‫معدّن‬</translation>
+ </message>
+ <message>
<source>watch-only</source>
- <translation type="unfinished">مشاهدة Ùقط</translation>
+ <translation type="unfinished">‫مراقبة Ùقط‬</translation>
</message>
<message>
<source>(n/a)</source>
@@ -3801,7 +4217,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(بدون وسم)</translation>
+ <translation type="unfinished">( لا وجود لمذكرة)</translation>
</message>
<message>
<source>Transaction status. Hover over this field to show number of confirmations.</source>
@@ -3809,23 +4225,23 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Date and time that the transaction was received.</source>
- <translation type="unfinished">التاريخ والوقت الذي تم Ùيه تلقي المعاملة.</translation>
+ <translation type="unfinished">‫التاريخ والوقت الذي تم Ùيه استلام العملية.‬</translation>
</message>
<message>
<source>Type of transaction.</source>
- <translation type="unfinished">نوع المعاملات</translation>
+ <translation type="unfinished">‫نوع العملية.‬</translation>
</message>
<message>
<source>Whether or not a watch-only address is involved in this transaction.</source>
- <translation type="unfinished">ما إذا كان العنوان المشاهدة Ùقط متضمنًا ÙÙŠ هذه المعاملة أم لا.</translation>
+ <translation type="unfinished">‫إذا كان عنوان المراقبة له علاقة بهذه العملية أم لا.‬</translation>
</message>
<message>
<source>User-defined intent/purpose of the transaction.</source>
- <translation type="unfinished">تحديد سبب المعاملة من المستخدم</translation>
+ <translation type="unfinished">‫سبب تنÙيذ العملية للمستخدم.‬</translation>
</message>
<message>
<source>Amount removed from or added to balance.</source>
- <translation type="unfinished">المبلغ الذي أزيل أو أضي٠الى الرصيد</translation>
+ <translation type="unfinished">‫القيمة المضاÙØ© أو المزالة من الرصيد.‬</translation>
</message>
</context>
<context>
@@ -3840,11 +4256,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>This week</source>
- <translation type="unfinished">هدا الاسبوع</translation>
+ <translation type="unfinished">هذا الاسبوع</translation>
</message>
<message>
<source>This month</source>
- <translation type="unfinished">هدا الشهر</translation>
+ <translation type="unfinished">هذا الشهر</translation>
</message>
<message>
<source>Last month</source>
@@ -3852,11 +4268,11 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>This year</source>
- <translation type="unfinished">هدا العام</translation>
+ <translation type="unfinished">هذا العام</translation>
</message>
<message>
<source>Received with</source>
- <translation type="unfinished">استقبل مع</translation>
+ <translation type="unfinished">‫استلم Ùي‬</translation>
</message>
<message>
<source>Sent to</source>
@@ -3867,12 +4283,16 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">إليك</translation>
</message>
<message>
+ <source>Mined</source>
+ <translation type="unfinished">‫معدّن‬</translation>
+ </message>
+ <message>
<source>Other</source>
<translation type="unfinished">أخرى</translation>
</message>
<message>
<source>Enter address, transaction id, or label to search</source>
- <translation type="unfinished">أدخل العنوان أو معر٠المعاملة أو التصني٠للبحث</translation>
+ <translation type="unfinished">‫أدخل العنوان أو معر٠المعاملة أو المذكرة للبحث‬</translation>
</message>
<message>
<source>Min amount</source>
@@ -3880,52 +4300,61 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Range…</source>
- <translation type="unfinished">نطاق</translation>
+ <translation type="unfinished">نطاق...</translation>
</message>
<message>
<source>&amp;Copy address</source>
- <translation type="unfinished">انسخ العنوان</translation>
+ <translation type="unfinished">‫&amp;انسخ العنوان‬</translation>
</message>
<message>
<source>Copy &amp;label</source>
- <translation type="unfinished">نسخ Ùˆ تصنيÙ</translation>
+ <translation type="unfinished">‫نسخ &amp;مذكرة‬</translation>
</message>
<message>
<source>Copy &amp;amount</source>
- <translation type="unfinished">نسخ &amp;مبلغ</translation>
+ <translation type="unfinished">‫نسخ &amp;القيمة‬</translation>
</message>
<message>
<source>Copy transaction &amp;ID</source>
- <translation type="unfinished">نسخ المعاملة &amp;المعرÙ</translation>
+ <translation type="unfinished">‫نسخ &amp;معر٠العملية‬</translation>
+ </message>
+ <message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">‫نسخ &amp;النص الأصلي للعملية‬</translation>
</message>
<message>
<source>Copy full transaction &amp;details</source>
- <translation type="unfinished">نسخ كامل تÙاصيل المعاملة</translation>
+ <translation type="unfinished">‫نسخ كامل &amp;تÙاصيل العملية‬</translation>
</message>
<message>
<source>&amp;Show transaction details</source>
- <translation type="unfinished">Ùˆ اظهر تÙاصيل الصÙقة</translation>
+ <translation type="unfinished">‫&amp; اظهر تÙاصيل العملية‬</translation>
</message>
<message>
<source>Increase transaction &amp;fee</source>
- <translation type="unfinished">زيادة الصÙقات Ùˆ الرسوم</translation>
+ <translation type="unfinished">‫زيادة العملية و الرسوم‬</translation>
</message>
<message>
<source>A&amp;bandon transaction</source>
- <translation type="unfinished">التخلي عن المعاملة</translation>
+ <translation type="unfinished">‫ال&amp;تخلي عن العملية</translation>
</message>
<message>
<source>&amp;Edit address label</source>
<translation type="unfinished">و تحرير تسمية العنوان </translation>
</message>
<message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">‫عرض ÙÙŠ %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
- <translation type="unfinished">تصدير تÙاصيل المعاملات</translation>
+ <translation type="unfinished">‫تصدير سجل العمليات التاريخي‬</translation>
</message>
<message>
<source>Comma separated file</source>
<extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
- <translation type="unfinished">مل٠مÙصَّل بالÙواصل</translation>
+ <translation type="unfinished">مل٠القيم المÙصولة بÙاصلة</translation>
</message>
<message>
<source>Confirmed</source>
@@ -3933,7 +4362,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Watch-only</source>
- <translation type="unfinished">مشاهدة Ùقط</translation>
+ <translation type="unfinished">‫مراقبة Ùقط‬</translation>
</message>
<message>
<source>Date</source>
@@ -3945,23 +4374,23 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Label</source>
- <translation type="unfinished">وسم</translation>
+ <translation type="unfinished">المذكرة</translation>
</message>
<message>
<source>Address</source>
- <translation type="unfinished">عنوان</translation>
+ <translation type="unfinished">العنوان</translation>
</message>
<message>
<source>ID</source>
- <translation type="unfinished">العنوان</translation>
+ <translation type="unfinished">‫المعرÙ‬</translation>
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished">لقد Ùشل التصدير</translation>
+ <translation type="unfinished">Ùشل التصدير</translation>
</message>
<message>
<source>There was an error trying to save the transaction history to %1.</source>
- <translation type="unfinished">حدث خطأ أثناء محاولة Ø­Ùظ محÙوظات المعاملة إلى %1.</translation>
+ <translation type="unfinished">‫حدث خطأ أثناء محاولة Ø­Ùظ سجل العملية التاريخي ÙÙŠ %1.‬</translation>
</message>
<message>
<source>Exporting Successful</source>
@@ -3969,7 +4398,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>The transaction history was successfully saved to %1.</source>
- <translation type="unfinished">تم Ø­Ùظ محÙوظات المعاملة بنجاح إلى %1.</translation>
+ <translation type="unfinished">‫تم Ø­Ùظ سجل العملية التاريخي بنجاح ÙÙŠ %1.‬</translation>
</message>
<message>
<source>Range:</source>
@@ -3986,8 +4415,8 @@ If you are receiving this error you should request the merchant provide a BIP21
<source>No wallet has been loaded.
Go to File &gt; Open Wallet to load a wallet.
- OR -</source>
- <translation type="unfinished">لم يتم تحميل أية محاÙظ.
-اذهب الى مل٠&gt; اÙتح محÙظة لتحميل محÙظة.
+ <translation type="unfinished">لم يتم تحميل أي محاÙظ.
+اذهب الى مل٠&gt; Ùتح محÙظة لتحميل محÙظة.
- أو -</translation>
</message>
<message>
@@ -4000,11 +4429,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Unable to decode PSBT from clipboard (invalid base64)</source>
- <translation type="unfinished">تعذر ÙÙƒ تشÙير PSBT من الحاÙظة (base64 غير صالح)</translation>
+ <translation type="unfinished">‫تعذر قراءة وتحليل ترميز PSBT من الحاÙظة (base64 غير صالح)‬</translation>
</message>
<message>
<source>Load Transaction Data</source>
- <translation type="unfinished">تحميل بيانات المعاملة</translation>
+ <translation type="unfinished">‫تحميل بيانات العملية‬</translation>
</message>
<message>
<source>Partially Signed Transaction (*.psbt)</source>
@@ -4016,14 +4445,14 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Unable to decode PSBT</source>
- <translation type="unfinished">غير قادر على ÙÙƒ تشÙير PSBT</translation>
+ <translation type="unfinished">‫غير قادر على قراءة وتحليل ترميز PSBT‬</translation>
</message>
</context>
<context>
<name>WalletModel</name>
<message>
<source>Send Coins</source>
- <translation type="unfinished">إرسال العملات</translation>
+ <translation type="unfinished">‫إرسال وحدات البتكوين‬</translation>
</message>
<message>
<source>Fee bump error</source>
@@ -4031,7 +4460,7 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Increasing transaction fee failed</source>
- <translation type="unfinished">Ùشل ÙÙŠ زيادة رسوم المعاملة</translation>
+ <translation type="unfinished">Ùشل ÙÙŠ زيادة رسوم العملية</translation>
</message>
<message>
<source>Do you want to increase the fee?</source>
@@ -4040,7 +4469,7 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Current fee:</source>
- <translation type="unfinished">الأجر الحالي:</translation>
+ <translation type="unfinished">‫الرسوم الان:‬</translation>
</message>
<message>
<source>Increase:</source>
@@ -4048,7 +4477,7 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>New fee:</source>
- <translation type="unfinished">أجر جديد:</translation>
+ <translation type="unfinished">‫رسم جديد:‬</translation>
</message>
<message>
<source>Confirm fee bump</source>
@@ -4083,15 +4512,15 @@ Go to File &gt; Open Wallet to load a wallet.
<name>WalletView</name>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">استخراج</translation>
+ <translation type="unfinished">&amp;تصدير</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation type="unfinished">استخراج البيانات ÙÙŠ علامة التبويب الحالية إلى ملÙ</translation>
+ <translation type="unfinished">صدّر البيانات ÙÙŠ التبويب الحالي الى ملÙ</translation>
</message>
<message>
<source>Backup Wallet</source>
- <translation type="unfinished">نسخ احتياط للمحÙظة</translation>
+ <translation type="unfinished">‫انسخ المحÙظة احتياطيا‬</translation>
</message>
<message>
<source>Wallet Data</source>
@@ -4100,11 +4529,15 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Backup Failed</source>
- <translation type="unfinished">Ùشل النسخ الاحتياطي</translation>
+ <translation type="unfinished">‫تعذر النسخ الاحتياطي‬</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation type="unfinished">لقد حدث خطأ أثناء محاولة Ø­Ùظ بيانات المحÙظة الى %1.</translation>
</message>
<message>
<source>Backup Successful</source>
- <translation type="unfinished">نجاح النسخ الاحتياطي</translation>
+ <translation type="unfinished">‫نجح النسخ الاحتياطي‬</translation>
</message>
<message>
<source>The wallet data was successfully saved to %1.</source>
diff --git a/src/qt/locale/bitcoin_az.ts b/src/qt/locale/bitcoin_az.ts
index 6b1d4072a8..2160142922 100644
--- a/src/qt/locale/bitcoin_az.ts
+++ b/src/qt/locale/bitcoin_az.ts
@@ -92,6 +92,11 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<translation type="unfinished">Ünvan siyahısını ixrac et</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Vergüllə ayrılmış fayl</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">Ünvan siyahısını %1 daxilində saxlamağı sınayarkən xəta baş verdi. Zəhmət olmasa yenidən sınayın.</translation>
@@ -159,20 +164,68 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<translation type="unfinished">Pulqabı şifrələməsini təsdiqlə</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 type="unfinished">XÉ™bÉ™rdarlıq: ÆgÉ™r siz pulqabınızı ÅŸifrÉ™dÉ™n çıxarsanız vÉ™ ÅŸifrÉ™li sözü itirmiÅŸ olsanız &lt;b&gt;BÃœTÃœN BÄ°TCOÄ°NLÆRÄ°NÄ°ZÄ° Ä°TÄ°RÆCÆKSÄ°NÄ°Z&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished">Pulqabınızı şifrədən çıxarmaq istədiyinizə əminsiniz?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished">Pulqabı şifrələndi.</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase for 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 type="unfinished">Pulqabı üçün yeni şifrəli sözü daxil edin.&lt;br/&gt;Lütfən &lt;b&gt;on və daha çox qarışıq simvollardan&lt;/b&gt; və ya &lt;b&gt;səkkiz və daha çox sayda sözdən&lt;/b&gt; ibarət şifrəli söz istifadə edin.</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase for the wallet.</source>
+ <translation type="unfinished">Pulqabı üçün köhnə şifrəli sözü və yeni şifrəli sözü daxil edin</translation>
+ </message>
+ <message>
<source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
- <translation type="unfinished">Unutmayın ki, cüzdanınızın şifrələməsi bitcoinlərinizi kompüterinizə zərərli proqram tərəfindən oğurlanmaqdan tamamilə qoruya bilməz.</translation>
+ <translation type="unfinished">Unutmayın ki, pulqabınızın şifrələməsi bitcoinlərinizi kompüterinizə zərərli proqram tərəfindən oğurlanmaqdan tamamilə qoruya bilməz.</translation>
</message>
<message>
<source>Wallet to be encrypted</source>
- <translation type="unfinished">Cüzdan şifrələnəcək</translation>
+ <translation type="unfinished">Pulqabı şifrələnəcək</translation>
</message>
<message>
<source>Your wallet is about to be encrypted. </source>
- <translation type="unfinished">Cüzdanınız şifrələnmək üzrədir.</translation>
+ <translation type="unfinished">Pulqabınız şifrələnmək üzrədir.</translation>
</message>
<message>
<source>Your wallet is now encrypted. </source>
- <translation type="unfinished">Cüzdanınız artıq şifrələnib.</translation>
+ <translation type="unfinished">Pulqabınız artıq şifrələnib.</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 type="unfinished">VACİBDİR: Pulqabınızın əvvəlki ehtiyyat nüsxələri yenicə yaradılan şifrələnmiş cüzdan ilə əvəz olunmalıdır. Təhlükəsizlik baxımından yeni şifrələnmiş pulqabını işə salan kimi əvvəlki şifrəsi açılmış pulqabının ehtiyyat nüsxələri qeyri-işlək olacaqdır.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation type="unfinished">Cüzdanın şifrələnməsi baş tutmadı</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation type="unfinished">Daxili xəta səbəbindən cüzdanın şifrələnməsi baş tutmadı. Cüzdanınız şifrələnmədi.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">Təqdim etdiyiniz şifrəli söz uyğun deyil.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation type="unfinished">Cüzdanın şifrədən çıxarılması baş tutmadı</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation type="unfinished">Cüzdanı şifrədən çıxarmaq üçün daxil etdiyiniz şifrəli söz səhvdir.</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished">Cüzdanın şifrəli sözü uğurla dəyişdirildi.</translation>
</message>
<message>
<source>Warning: The Caps Lock key is on!</source>
@@ -180,7 +233,67 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
</message>
</context>
<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>Banned Until</source>
+ <translation type="unfinished">QadaÄŸan edildi</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Ola bilsin ki, %1 faylı zədələnib və ya yararsızdır.</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">İdarə edilə bilməyən istisna</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">Ciddi xəta baş verdi. %1 təhlükəsiz davam etdirilə bilməz və bağlanacaqdır.</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">Daxili xəta</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Daxili xəta baş verdi. %1 təhlükəsiz davam etməyə cəhd edəcək. Bu gözlənilməz bir xətadır və onun haqqında aşağıdakı şəkildə bildirmək olar.</translation>
+ </message>
+</context>
+<context>
<name>QObject</name>
+ <message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Siz ayarları dəyərləri ilkin dəyərlərinə sıfırlamaq istəyirsiniz, yoxsa dəyişiklik etmədən bu əməliyyatı ləğv etmək istəyirsiniz?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Ciddi xəta baş verdi. Ayarlar faylının yazılabilən olduğunu yoxlayın və ya -nonsettings (ayarlarsız) parametri ilə işə salın.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation type="unfinished">Xəta: Göstərilmiş verilənlər qovluğu "%1" mövcud deyil</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">Xəta: Tənzimləmə faylını təhlil etmək mümkün deyil: %1</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">XÆta: %1</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 hələ də təhlükəsiz bağlanmayıb...</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Məbləğ</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
@@ -227,6 +340,14 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Ayarlar faylı oxuna bilmədi</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Ayarlar faylı yazıla bilmədi</translation>
+ </message>
+ <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Ödəniş təxmin edilmədi. Fallbackfee sıradan çıxarıldı. Bir neçə blok gözləyin və ya Fallbackfee-ni fəallaşdırın.</translation>
</message>
@@ -254,17 +375,226 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<context>
<name>BitcoinGUI</name>
<message>
+ <source>&amp;Overview</source>
+ <translation type="unfinished">&amp;Ä°cmal</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation type="unfinished">Cüzdanın əsas icmalı göstərilsin</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation type="unfinished">&amp;Köçürmələr</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation type="unfinished">Köçürmə tarixçəsinə baxış</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation type="unfinished">Çı&amp;xış</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation type="unfinished">Tətbiqdən çıxış</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation type="unfinished">%1 h&amp;aqqında</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation type="unfinished">%1 haqqında məlumatlar göstərilsin</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation type="unfinished">&amp;Qt haqqında</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation type="unfinished">Qt haqqında məlumatlar göstərilsin</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation type="unfinished">%1 üçün tənzimləmə seçimlərini dəyişin</translation>
+ </message>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Yeni cüzdan yaradın</translation>
+ </message>
+ <message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Yığın</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Cüzdan:</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">İnternet bağlantısı söndürülüb.</translation>
+ </message>
+ <message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation type="unfinished">Proksi &lt;b&gt;işə salınıb&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation type="unfinished">Pulları Bitcoin ünvanına göndərin</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation type="unfinished">Cüzdanın ehtiyyat nüsxəsini başqa yerdə saxlayın</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation type="unfinished">Cüzdanın şifrələnməsi üçün istifadə olunan şifrəli sözü dəyişin</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation type="unfinished">&amp;Göndərin</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation type="unfinished">&amp;Qəbul edin</translation>
+ </message>
+ <message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Parametrlər</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;Cüzdanı şifrələyin...</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">Cüzdanınıza aid məxfi açarları şifrələyin</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;Cüzdanın ehtiyyat nüsxəsini saxlayın...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;Şifrəli sözü dəyişin...</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">İs&amp;marıcı imzalayın...</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">Bitcoin ünvanlarınızın sahibi olduğunuzu sübut etmək üçün ismarıcları imzalayın</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;İsmarıcı doğrulayın...</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">Göstərilmiş Bitcoin ünvanları ilə imzalandıqlarına əmin olmaq üçün ismarıcları doğrulayın</translation>
+ </message>
+ <message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">PSBT-i fayldan yük&amp;ləyin...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">&amp;URI-ni açın...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">Cüzdanı bağlayın...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">Cüzdan yaradın...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">Bütün cüzdanları bağlayın...</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation type="unfinished">&amp;Fayl</translation>
+ </message>
+ <message>
<source>&amp;Settings</source>
<translation type="unfinished">&amp;Tənzimləmələr</translation>
</message>
+ <message>
+ <source>&amp;Help</source>
+ <translation type="unfinished">&amp;Kömək</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation type="unfinished">Vərəq alətlər zolağı</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Başlıqlar eyniləşdirilir (%1%)...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">İnternet şəbəkəsi ilə eyniləşdirmə...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Bloklar diskdə indekslənir...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Bloklar diskdÉ™ icra olunur...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Bloklar diskdə təkrar indekslənir...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">İştirakçılara qoşulur...</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation type="unfinished">Ödəmə tələbi (QR-kodlar və Bitcoin URI-ləri yaradılır):</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation type="unfinished">İstifadə olunmuş göndərmə ünvanlarının və etiketlərin siyahısını göstərmək </translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation type="unfinished">İstifadə edilmiş qəbuletmə ünvanlarının və etiketlərin siyahısını göstərmək</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation type="unfinished">Æmr &amp;sÉ™tri parametrlÉ™ri</translation>
+ </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Köçürmə tarixçəsinin %n bloku işləndi.</numerusform>
+ <numerusform>Köçürmə tarixçəsinin %n bloku işləndi.</numerusform>
</translation>
</message>
<message>
+ <source>%1 behind</source>
+ <translation type="unfinished">%1 geridə qalır</translation>
+ </message>
+ <message>
+ <source>Catching up…</source>
+ <translation type="unfinished">Eyniləşir...</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation type="unfinished">Sonuncu qəbul edilmiş blok %1 əvvəl yaradılıb.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation type="unfinished">Bundan sonrakı köçürmələr hələlik görünməyəcək.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">Xəta</translation>
</message>
@@ -277,36 +607,637 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<translation type="unfinished">Məlumat</translation>
</message>
<message>
+ <source>Up to date</source>
+ <translation type="unfinished">Eyniləşdirildi</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">Qismən imzalanmış Bitcoin köçürmələrini yükləyin</translation>
+ </message>
+ <message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">PSBT-i &amp;mübadilə yaddaşından yükləyin...</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">Qismən İmzalanmış Bitcoin Köçürməsini (PSBT) mübadilə yaddaşından yükləmək</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">Qovşaq pəncərəsi</translation>
+ </message>
+ <message>
+ <source>Open node debugging and diagnostic console</source>
+ <translation type="unfinished">Qovşaq sazlaması və diaqnostika konsolunu açın</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">&amp;Göndərmək üçün ünvanlar</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">&amp;Qəbul etmək üçün ünvanlar</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI</source>
+ <translation type="unfinished">Bitcoin açın: URI</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <translation type="unfinished">Cüzdanı açın</translation>
+ </message>
+ <message>
<source>Open a wallet</source>
<translation type="unfinished">Bir pulqabı aç</translation>
</message>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">Cüzdanı bağlayın</translation>
+ </message>
+ <message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Cüzdanı bərpa edin...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Cüzdanı ehtiyyat nüsxə faylından bərpa edin</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">Bütün cüzdanları bağlayın</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation type="unfinished">Mümkün Bitcoin əmr sətri əməliyyatları siyahısını almaq üçün %1 kömək ismarıcı göstərilsin</translation>
+ </message>
+ <message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">&amp;Dəyərləri gizlədin</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">İcmal vərəqində dəyərləri gizlədin</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">standart cüzdan</translation>
+ </message>
+ <message>
+ <source>No wallets available</source>
+ <translation type="unfinished">Heç bir cüzdan yoxdur</translation>
+ </message>
+ <message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Cüzdanı verilənləri</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Cüzdan ehtiyyat nesxəsini yüklə</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Cüzdanı bərpa et</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Pulqabının adı</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;Pəncərə</translation>
+ </message>
+ <message>
+ <source>Zoom</source>
+ <translation type="unfinished">Miqyas</translation>
+ </message>
+ <message>
+ <source>Main Window</source>
+ <translation type="unfinished">Æsas pÉ™ncÉ™rÉ™</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation type="unfinished">%1 müştəri</translation>
+ </message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Gizlədin</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">&amp;Göstərin</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Bitcoin şəbəkəsinə %n aktiv bağlantı.</numerusform>
+ <numerusform>Bitcoin şəbəkəsinə %n aktiv bağlantı.</numerusform>
</translation>
</message>
- </context>
+ <message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Daha çıx əməllər üçün vurun.</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">İştirakşılar vərəqini göstərmək</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">Şəbəkə bağlantısını söndürün</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">Şəbəkə bağlantısını açın</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">XÆta: %1</translation>
+ </message>
+ <message>
+ <source>Warning: %1</source>
+ <translation type="unfinished">Xəbərdarlıq: %1</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation type="unfinished">Tarix: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation type="unfinished">Məbləğ: %1
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation type="unfinished">Cüzdan: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation type="unfinished">Növ: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation type="unfinished">Etiket: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation type="unfinished">Ãœnvan: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation type="unfinished">Göndərilmiş köçürmə</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation type="unfinished">Daxil olan köçürmə</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD açar yaradılması &lt;b&gt;aktivdir&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD açar yaradılması &lt;b&gt;söndürülüb&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">Məxfi açar &lt;b&gt;söndürülüb&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 type="unfinished">Cüzdan &lt;b&gt;şifrələnib&lt;/b&gt; və hal-hazırda &lt;b&gt;kiliddən çıxarılıb&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 type="unfinished">Cüzdan &lt;b&gt;şifrələnib&lt;/b&gt; və hal-hazırda &lt;b&gt;kiliddlənib&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">Orijinal ismarıc:</translation>
+ </message>
+</context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">Məbləğin vahidi. Başqa vahidi seçmək üçün vurun.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Coin Selection</source>
+ <translation type="unfinished">Pul seçimi</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">Miqdar:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">Baytlar:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Məbləğ:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">Komissiya:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">Toz:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">Komissiydan sonra:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">Qalıq:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation type="unfinished">seçim</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation type="unfinished">AÄŸac rejimi</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation type="unfinished">Siyahı rejim</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Məbləğ</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation type="unfinished">Etiket ilə alındı</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation type="unfinished">Ünvan ilə alındı</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Tarix</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation type="unfinished">Təsdiqləmələr</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">Təsdiqləndi</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Məbləği kopyalayın</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Ünvanı kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Etiketi kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">&amp;Məbləği kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Köçürmə &amp;İD-sini və çıxış indeksini kopyalayın</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">Xərclənməmiş qalığı &amp;kilidləyin</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">Xərclənməmiş qalığı kilidd'n &amp;çıxarın</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Miqdarı kopyalayın</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Komissiyanı kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Komissyadan sonra kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Baytları koyalayın</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">Tozu kopyalayın</translation>
+ </message>
+ <message>
<source>Copy change</source>
<translation type="unfinished">Dəyişikliyi kopyalayın</translation>
</message>
<message>
+ <source>(%1 locked)</source>
+ <translation type="unfinished">(%1 kilidləndi)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation type="unfinished">bəli</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation type="unfinished">xeyr</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished">ÆgÉ™r alıcı mÉ™bləği cari toz hÉ™ddindÉ™n az alarsa bu etiket qırmızı olur.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation type="unfinished">Hər daxilolmada +/- %1 satoşi dəyişə bilər.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(etiket yoxdur)</translation>
</message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation type="unfinished">bunlardan qalıq: %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation type="unfinished">(qalıq)</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletActivity</name>
+ <message>
+ <source>Create Wallet</source>
+ <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
+ <translation type="unfinished">Cüzdan yaradın</translation>
+ </message>
+ <message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">&lt;b&gt;%1&lt;/b&gt; cüzdanı yaradılır...</translation>
+ </message>
+ <message>
+ <source>Create wallet failed</source>
+ <translation type="unfinished">Cüzdan yaradıla bilmədi</translation>
+ </message>
+ <message>
+ <source>Create wallet warning</source>
+ <translation type="unfinished">Cüzdan yaradılma xəbərdarlığı</translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">İmzalaynları göstərmək mümkün deyil</translation>
+ </message>
+ </context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">Cüzdanları yükləyin</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">Pulqabılar yüklənir...</translation>
+ </message>
+</context>
+<context>
+ <name>OpenWalletActivity</name>
+ <message>
+ <source>Open wallet failed</source>
+ <translation type="unfinished">Pulqabı açıla bilmədi</translation>
+ </message>
+ <message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">Pulqabının açılması xəbərdarlığı</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">standart cüzdan</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
+ <translation type="unfinished">Cüzdanı açın</translation>
+ </message>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">&lt;b&gt;%1&lt;/b&gt; pulqabı açılır...</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Cüzdanı bərpa et</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">&lt;b&gt;%1&lt;/b&gt; cüzdanı bərpa olunur...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Cüzdan bərpa oluna bilmədi</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Cüzdanın bərpa olunması xəbərdarlığı</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Cüzdanın bərpası ismarıcı</translation>
+ </message>
+</context>
+<context>
+ <name>WalletController</name>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">Cüzdanı bağlayın</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">&lt;i&gt;%1&lt;/i&gt; pulqabını bağlamaq istədiyinizə əminsiniz?</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">Pulqabının uzun müddət bağlı qaldıqda əgər budama (azalma) aktiv olarsa bu, bütün zəncirin təkrar eyniləşditrilməsi ilə nəticələnə bilər.</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">Bütün cüzdanları bağlayın</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">Bütün pulqabılarını bağlamaq istədiyinizə əminsiniz?</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletDialog</name>
+ <message>
+ <source>Create Wallet</source>
+ <translation type="unfinished">Cüzdan yaradın</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <translation type="unfinished">Pulqabının adı</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation type="unfinished">Pulqabı</translation>
+ </message>
+ <message>
+ <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
+ <translation type="unfinished">Pulqabının şifrələnməsi. Pulqabı sizin seçdiyiniz şifrəli söz ilə şifrələnəcək.</translation>
+ </message>
+ <message>
+ <source>Encrypt Wallet</source>
+ <translation type="unfinished">Pulqabını şifrələyin</translation>
+ </message>
+ <message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">ÆlavÉ™ parametrlÉ™r</translation>
+ </message>
+ <message>
+ <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
+ <translation type="unfinished">Bu pulqabının məxfi açarını söndürün. Məxfi açarı söndürülmüş pulqabılarında məxfi açarlar saxlanılmır, onlarda HD məxfi açarlar yaradıla bilıməz və məxfi açarlar idxal edilə bilməz. Bu sadəcə müşahidə edən pulqabıları üçün ideal variantdır.</translation>
+ </message>
+ <message>
+ <source>Disable Private Keys</source>
+ <translation type="unfinished">Məxfi açarları söndürün</translation>
+ </message>
+ <message>
+ <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
+ <translation type="unfinished">Boş pulqabı yaradın. Boş pulqabında ilkin olaraq açarlar və skriptlər yoxdur. Sonra məxfi açarlar və ünvanlar idxal edilə bilər və ya HD məxfi açarlar təyin edilə bilər.</translation>
+ </message>
+ <message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">Boş pulqabı yaradın</translation>
+ </message>
+ <message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">Publik açar skripti (scriptPubKey) idarəetməsi üçün deskreptorlardan itifadə edin</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">Deskriptor pulqabı</translation>
+ </message>
+ <message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Aparat cüzdanı kimi xarici imzalama cihazından istifadÉ™ edin. ÆvvÉ™lcÉ™ cüzdan seçimlÉ™rindÉ™ xarici imzalayan skriptini konfiqurasiya edin.</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">Xarici imzalayıcı</translation>
+ </message>
+ <message>
+ <source>Create</source>
+ <translation type="unfinished">Yarat</translation>
+ </message>
+ </context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation type="unfinished">Ünvanda düzəliş et</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation type="unfinished">&amp;Etiket</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation type="unfinished">&amp;Ãœnvan</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation type="unfinished">Yeni göndərilmə ünvanı</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation type="unfinished">Qəbul ünvanını düzəliş et</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation type="unfinished">Göndərilmə ünvanını düzəliş et</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation type="unfinished">Yeni açar yaradılma uğursuz oldu.</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>name</source>
+ <translation type="unfinished">ad</translation>
+ </message>
</context>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -319,13 +1250,71 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<translation type="unfinished">Xəta</translation>
</message>
<message>
+ <source>Welcome</source>
+ <translation type="unfinished">Xoş gəlmisiniz</translation>
+ </message>
+ <message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">Bu tÉ™nzimlÉ™mÉ™ni geri almaq bütün blok zÉ™ncirinin yenidÉ™n endirilmÉ™sini tÉ™lÉ™b edÉ™cÉ™k. ÆvvÉ™lcÉ™ tam zÉ™nciri endirmÉ™k vÉ™ sonra budamaq daha sürÉ™tlidir. BÉ™zi qabaqcıl özÉ™lliklÉ™ri sıradan çıxarar.</translation>
</message>
+ <message>
+ <source> GB</source>
+ <translation type="unfinished">QB</translation>
+ </message>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation type="unfinished">versiya</translation>
+ </message>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Number of blocks left</source>
+ <translation type="unfinished">Qalan blokların sayı</translation>
+ </message>
+ <message>
+ <source>Unknown…</source>
+ <translation type="unfinished">Bilinməyən...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">hesablanır...</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">GizlÉ™</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
<message>
+ <source>Options</source>
+ <translation type="unfinished">Seçimlər</translation>
+ </message>
+ <message>
+ <source>&amp;Main</source>
+ <translation type="unfinished">&amp;Æsas</translation>
+ </message>
+ <message>
+ <source>Open Configuration File</source>
+ <translation type="unfinished">Konfiqurasiya Faylını Aç</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation type="unfinished">&amp;Seçimləri Sıfırla</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation type="unfinished">&amp;Şəbəkə</translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <translation type="unfinished">QB</translation>
+ </message>
+ <message>
<source>Reverting this setting requires re-downloading the entire blockchain.</source>
<translation type="unfinished">Bu tənzimləməni geri almaq bütün blok zəncirinin yenidən endirilməsini tələb edəcək. </translation>
</message>
@@ -334,32 +1323,146 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<translation type="unfinished">&amp;UPnP istifadə edən xəritə portu</translation>
</message>
<message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;Pəncərə</translation>
+ </message>
+ <message>
<source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
<translation type="unfinished">İstifadəçi interfeys dili burada tənzimlənə bilər. Bu tənzimləmə %1 yenidən başladıldıqdan sonra təsirli olacaq.</translation>
</message>
<message>
+ <source>&amp;Cancel</source>
+ <translation type="unfinished">&amp;Ləğv et</translation>
+ </message>
+ <message>
+ <source>Configuration options</source>
+ <extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
+ <translation type="unfinished">Konfiqurasiya seçimləri</translation>
+ </message>
+ <message>
+ <source>Continue</source>
+ <translation type="unfinished">Davam et</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">Ləğv et</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">Xəta</translation>
</message>
</context>
<context>
+ <name>OverviewPage</name>
+ <message>
+ <source>Total:</source>
+ <translation type="unfinished">Ãœmumi:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation type="unfinished">Son əməliyyatlar</translation>
+ </message>
+ </context>
+<context>
+ <name>PSBTOperationsDialog</name>
+ <message>
+ <source>Copy to Clipboard</source>
+ <translation type="unfinished">BuferÉ™ kopyala</translation>
+ </message>
+ <message>
+ <source>Save…</source>
+ <translation type="unfinished">Yadda saxla...</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished">BaÄŸla</translation>
+ </message>
+ <message>
+ <source>Failed to load transaction: %1</source>
+ <translation type="unfinished">ÆmÉ™liyyatı yüklÉ™mÉ™k alınmadı:%1</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">Ãœmumi Miqdar</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">vÉ™ ya</translation>
+ </message>
+ </context>
+<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation type="unfinished">Ödəmə tələbinin xətası</translation>
+ </message>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>Address</source>
<extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
<translation type="unfinished">Ãœnvan</translation>
</message>
+ <message>
+ <source>Network</source>
+ <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment>
+ <translation type="unfinished">Şəbəkə</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
<message>
+ <source>Network</source>
+ <translation type="unfinished">Şəbəkə</translation>
+ </message>
+ <message>
<source>&amp;Reset</source>
<translation type="unfinished">&amp;Sıfırla</translation>
</message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">Qovşaq pəncərəsi</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Ünvanı kopyalayın</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Ünvanı kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Etiketi kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">&amp;Məbləği kopyalayın</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Məbləğ:</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Cüzdan:</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation type="unfinished">Tarix</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">Etiket</translation>
</message>
@@ -371,13 +1474,73 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<context>
<name>SendCoinsDialog</name>
<message>
+ <source>Quantity:</source>
+ <translation type="unfinished">Miqdar:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">Baytlar:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Məbləğ:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">Komissiya:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">Komissiydan sonra:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">Qalıq:</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">GizlÉ™</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">Toz:</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Miqdarı kopyalayın</translation>
</message>
<message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Məbləği kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Komissiyanı kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Komissyadan sonra kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Baytları koyalayın</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">Tozu kopyalayın</translation>
+ </message>
+ <message>
<source>Copy change</source>
<translation type="unfinished">Dəyişikliyi kopyalayın</translation>
</message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">vÉ™ ya</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">Ãœmumi Miqdar</translation>
+ </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -392,6 +1555,10 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
</context>
<context>
<name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Tarix</translation>
+ </message>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
@@ -399,10 +1566,18 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<numerusform />
</translation>
</message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Məbləğ</translation>
+ </message>
</context>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation type="unfinished">Tarix</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">Etiket</translation>
</message>
@@ -418,6 +1593,31 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<translation type="unfinished">BaÅŸqa</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Ünvanı kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Etiketi kopyalayın</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">&amp;Məbləği kopyalayın</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Vergüllə ayrılmış fayl</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">Təsdiqləndi</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Tarix</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">Etiket</translation>
</message>
@@ -433,11 +1633,22 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<context>
<name>WalletFrame</name>
<message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Yeni cüzdan yaradın</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">Xəta</translation>
</message>
</context>
<context>
+ <name>WalletModel</name>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">standart cüzdan</translation>
+ </message>
+</context>
+<context>
<name>WalletView</name>
<message>
<source>&amp;Export</source>
@@ -447,5 +1658,14 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilə mümkündür.</translation>
<source>Export the data in the current tab to a file</source>
<translation type="unfinished">Hazırki vərəqdəki verilənləri fayla ixrac edin</translation>
</message>
- </context>
+ <message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Cüzdanı verilənləri</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">Ləğv et</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_be.ts b/src/qt/locale/bitcoin_be.ts
index 8fa9499138..d242a54544 100644
--- a/src/qt/locale/bitcoin_be.ts
+++ b/src/qt/locale/bitcoin_be.ts
@@ -660,6 +660,30 @@
<translation type="unfinished">Біткойн</translation>
</message>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -903,15 +927,7 @@
<source>Message:</source>
<translation type="unfinished">Паведамленне:</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Заплаціць да:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">ПамÑтка:</translation>
- </message>
-</context>
+ </context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
@@ -923,10 +939,12 @@
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/непацверджана</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 пацверджаннÑÑž</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts
index eeaabd47c2..7276e4707f 100644
--- a/src/qt/locale/bitcoin_bg.ts
+++ b/src/qt/locale/bitcoin_bg.ts
@@ -87,6 +87,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ИзнеÑи лиÑÑ‚ Ñ Ð°Ð´Ñ€ÐµÑи</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Файл, разделен ÑÑŠÑ Ð·Ð°Ð¿ÐµÑ‚Ð°Ñ</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">Получи Ñе грешка при запазването на лиÑта Ñ Ð°Ð´Ñ€ÐµÑи към %1. ÐœÐ¾Ð»Ñ Ð¾Ð¿Ð¸Ñ‚Ð°Ð¹Ñ‚Ðµ пак.</translation>
@@ -174,6 +179,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Въведете Ñтарата и новата паролна фраза за портфейла.</translation>
</message>
<message>
+ <source>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>
<source>Wallet to be encrypted</source>
<translation type="unfinished">Портфейл за криптиране</translation>
</message>
@@ -232,6 +241,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Файлът Ñ Ð½Ð°Ñтройки %1 може да е повреден или невалиден.</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">Изключи бÑгащите</translation>
+ </message>
+ <message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
<translation type="unfinished">Фатална грешка Ñе поÑви. %1 не може да продължи безопаÑтно и ще Ñе затвори.</translation>
</message>
@@ -239,7 +256,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Internal error</source>
<translation type="unfinished">Вътрешна грешка.</translation>
</message>
- </context>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Възникна вътрешна грешка. %1 ще Ñе опита да продължи безопаÑно. Това е неочакван бъг, който може да бъде докладван, както е опиÑано по-долу.</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -257,6 +278,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Грешка:Избраната "%1" Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ðµ ÑъщеÑтвува.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">Грешка: Ðе може да Ñе анализира ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»: %1.</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Грешка: %1</translation>
</message>
@@ -439,7 +464,31 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Transaction too large</source>
<translation type="unfinished">ТранзакциÑта е твърде голÑма</translation>
</message>
- </context>
+ <message>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished">Ðктивирани Ñа неизвеÑтни нови правила (versionbit %i)</translation>
+ </message>
+ <message>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Ðеподдържана logging категориÑ%s=%s.</translation>
+ </message>
+ <message>
+ <source>User Agent comment (%s) contains unsafe characters.</source>
+ <translation type="unfinished">Коментар потребителÑки агент (%s) Ñъдържа не безопаÑни знаци. </translation>
+ </message>
+ <message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">Секторите Ñе проверÑват...</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)…</source>
+ <translation type="unfinished">Потвърждаване на портфейл(и)...</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation type="unfinished">Портфейлът Ñ‚Ñ€Ñбва да бъде презапиÑан : реÑтартирай %s , за да завърши</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
@@ -568,6 +617,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Зареди PSBT от файл…</translation>
</message>
<message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">Отвори &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">Затвори Портфейл...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">Създай Портфейл...</translation>
+ </message>
+ <message>
<source>Close All Wallets…</source>
<translation type="unfinished">Затвори вÑички уолети</translation>
</message>
@@ -588,10 +649,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Лентата Ñ Ð¸Ð½Ñтрументи</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Синхронизиране на хедъри (%1%)</translation>
+ </message>
+ <message>
<source>Synchronizing with network…</source>
<translation type="unfinished">Синхронизиране Ñ Ð¼Ñ€ÐµÐ¶Ð°</translation>
</message>
<message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">ИндекÑиране на блокове от диÑка...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Обработват Ñе блокове на диÑка...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">ПреиндекÑиране на блоково от диÑка...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Свързване Ñ Ñ€Ð¾Ñк...</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">ИзиÑкване на плащаниÑ(генерира QR кодове и биткойн: URIs)</translation>
</message>
@@ -610,8 +691,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Обработени %n Ñектори от иÑториÑта Ñ Ñ‚Ñ€Ð°Ð½Ñакции.</numerusform>
+ <numerusform>Обработени %n Ñектори от иÑториÑта Ñ Ñ‚Ñ€Ð°Ð½Ñакции.</numerusform>
</translation>
</message>
<message>
@@ -619,6 +700,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1 зад</translation>
</message>
<message>
+ <source>Catching up…</source>
+ <translation type="unfinished">ÐавакÑвам...</translation>
+ </message>
+ <message>
<source>Last received block was generated %1 ago.</source>
<translation type="unfinished">ПоÑÐ»ÐµÐ´Ð½Ð¸Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½ блок е генериран преди %1.</translation>
</message>
@@ -643,10 +728,42 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðктуално</translation>
</message>
<message>
+ <source>Ctrl+Q</source>
+ <translation type="unfinished">Ctrl+Q </translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">Заредете чаÑтично подпиÑана Bitcoin транÑакциÑ</translation>
+ </message>
+ <message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">Заредете PSBT (чаÑтично подпиÑана Bitcoin транÑакциÑ) от &amp;клипборд...</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">Заредете чаÑтично подпиÑана Bitcoin транÑÐ°ÐºÑ†Ð¸Ñ Ð¾Ñ‚ клипборд</translation>
+ </message>
+ <message>
<source>Node window</source>
<translation type="unfinished">Прозорец на възела</translation>
</message>
<message>
+ <source>Open node debugging and diagnostic console</source>
+ <translation type="unfinished">Отвори конзола за отÑтранÑване на грешки и диагноÑтика на възела</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">&amp;Изпращане на адреÑи</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">&amp;Получаване на адреÑи</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI</source>
+ <translation type="unfinished">Отвори bitcoin: URI</translation>
+ </message>
+ <message>
<source>Open Wallet</source>
<translation type="unfinished">Отворете портфейл</translation>
</message>
@@ -659,6 +776,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Затвори портфейла</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">ВъзÑтановÑване на Портфейл...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">ВъзÑтанови портфейла от резервен файл</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Затвори вÑички портфейли</translation>
</message>
@@ -667,6 +794,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Покажи %1 помощно Ñъобщение за да получиш лиÑÑ‚ Ñ Ð²ÑŠÐ·Ð¼Ð¾Ð¶Ð½Ð¸ Биткойн команди</translation>
</message>
<message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">§МаÑкирай ÑтойноÑтите</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">МаÑкирай ÑтойноÑтите в раздела Преглед</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">Портфейл по подразбиране</translation>
</message>
@@ -675,10 +810,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ÐÑма доÑтъпни портфейли</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Данни от портфейла</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Зареди резервно копие на портфейл</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">ВъзÑтановÑване на Портфейл</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Име на портфейл</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Прозорец</translation>
</message>
<message>
+ <source>Ctrl+M</source>
+ <translation type="unfinished">Ctrl+M </translation>
+ </message>
+ <message>
<source>Zoom</source>
<translation type="unfinished">Увеличи</translation>
</message>
@@ -690,12 +849,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 клиент</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Скрий</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">&amp;Покажи</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n Ñвързани активно към Bitcoin мрежата.</numerusform>
+ <numerusform>%n активно Ñвързани към Биткойн мрежата. </numerusform>
</translation>
</message>
<message>
@@ -704,6 +871,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Клик за повече дейÑтвиÑ</translation>
</message>
<message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Показване на раздела Ñ ÐŸÐ¸ÑŠÑ€Ð¸</translation>
+ </message>
+ <message>
<source>Disable network activity</source>
<extracomment>A context menu item.</extracomment>
<translation type="unfinished">Блокирай мрежова активноÑÑ‚</translation>
@@ -791,6 +963,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">Елемент за показване на Ñуми. Щракнете, за да изберете друга единица.</translation>
+ </message>
+</context>
+<context>
<name>CoinControlDialog</name>
<message>
<source>Coin Selection</source>
@@ -869,10 +1048,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Копирай адреÑ</translation>
</message>
<message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Копиране на етикет</translation>
+ </message>
+ <message>
<source>Copy &amp;amount</source>
<translation type="unfinished">Копирай Ñума</translation>
</message>
<message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Копирайте идентификатора &amp;ID на транÑакциÑта и Ð¸Ð·Ñ…Ð¾Ð´Ð½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑ</translation>
+ </message>
+ <message>
<source>L&amp;ock unspent</source>
<translation type="unfinished">Заключи неизхарчено</translation>
</message>
@@ -953,7 +1140,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Create wallet failed</source>
<translation type="unfinished">Създаването на портфейл не бе уÑпешен</translation>
</message>
- </context>
+ <message>
+ <source>Create wallet warning</source>
+ <translation type="unfinished">Създайте предупредителен портфейл </translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Ðе мога да Ð¸Ð·Ð±Ñ€Ð¾Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñите</translation>
+ </message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Ðамерени Ñа твърде много външни подпиÑващи</translation>
+ </message>
+</context>
<context>
<name>LoadWalletsActivity</name>
<message>
@@ -974,6 +1173,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ОтварÑнето на уолет неупÑешно</translation>
</message>
<message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">Внимание, отворен портфейл</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">Портфейл по подразбиране</translation>
</message>
@@ -982,7 +1185,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">Отворете портфейл</translation>
</message>
- </context>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">ОтварÑне на портфейл &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">ВъзÑтановÑване на Портфейл</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">ВъзÑтановÑването на портфейла не бе уÑпешно</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Съобщение портфейлът е възÑтановен</translation>
+ </message>
+</context>
<context>
<name>WalletController</name>
<message>
@@ -990,10 +1216,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Затвори портфейла</translation>
</message>
<message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">Сигурни ли Ñте, че иÑкате да затворите портфейла&lt;i&gt;%1&lt;/i&gt;?</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">ЗатварÑнето на портфейла за твърде дълго може да доведе до необходимоÑÑ‚ от повторно Ñинхронизиране на цÑлата верига, ако Ñъкращаването е активирано.</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Затвори вÑички портфейли</translation>
</message>
- </context>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">Сигурни ли Ñте, че иÑкате да затворите вÑички портфейли?</translation>
+ </message>
+</context>
<context>
<name>CreateWalletDialog</name>
<message>
@@ -1009,14 +1247,63 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">портфейл</translation>
</message>
<message>
+ <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
+ <translation type="unfinished">Кодиране на портфейла. Портфейлът ще бъде криптиран Ñ Ð¿Ð°Ñ€Ð¾Ð»Ð° по ваш избор.</translation>
+ </message>
+ <message>
<source>Encrypt Wallet</source>
<translation type="unfinished">Криптирай портфейла</translation>
</message>
<message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">Разширени наÑтройки</translation>
+ </message>
+ <message>
+ <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
+ <translation type="unfinished">Деактивирайте чаÑтните ключове за този портфейл. Портфейлите Ñ Ð´ÐµÐ°ÐºÑ‚Ð¸Ð²Ð¸Ñ€Ð°Ð½Ð¸ чаÑтни ключове нÑма да имат чаÑтни ключове и не могат да имат HD seed или импортирани чаÑтни ключове. Това е идеално за портфейли, които Ñлужат Ñамо за наблюдение на баланÑа.</translation>
+ </message>
+ <message>
+ <source>Disable Private Keys</source>
+ <translation type="unfinished">Изключете чаÑтните (тайните) ключове</translation>
+ </message>
+ <message>
+ <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
+ <translation type="unfinished">Създайте празен портфейл. Празните портфейли първоначално нÑмат чаÑтни ключове или Ñкриптове. ЧаÑтните ключове и адреÑи могат да бъдат импортирани или може да Ñе зададе HD seed по-къÑно. </translation>
+ </message>
+ <message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">Създайте празен портфейл</translation>
+ </message>
+ <message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">Използвайте декодери за управление на scriptPubKey</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">Декодер за портфейл</translation>
+ </message>
+ <message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Използвайте външно уÑтройÑтво за подпиÑване, като хардуерен портфейл. Конфигурирайте първо Ð²ÑŠÐ½ÑˆÐ½Ð¸Ñ Ñкрипт на подпиÑа в Ð¿Ñ€ÐµÐ´Ð¿Ð¾Ñ‡Ð¸Ñ‚Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñ€Ñ‚Ñ„ÐµÐ¹Ð».</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">Външен подпиÑ</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">Създай</translation>
</message>
- </context>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished">Компилиран без поддръжка на sqlite (изиÑква Ñе за декодер на портфейли)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Компилиран без поддръжка на външни подпиÑи (изиÑква Ñе за външно подпиÑване)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -1056,6 +1343,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">"%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 type="unfinished">ÐдреÑÑŠÑ‚ "%1" вече ÑъщеÑтвува като Ð°Ð´Ñ€ÐµÑ Ð·Ð° получаване Ñ ÐµÑ‚Ð¸ÐºÐµÑ‚ "%2" и затова не може да бъде добавен като Ð°Ð´Ñ€ÐµÑ Ð·Ð° изпращане.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation type="unfinished">ВъведениÑÑ‚ Ð°Ð´Ñ€ÐµÑ "%1" вече е в адреÑната книга Ñ ÐµÑ‚Ð¸ÐºÐµÑ‚ "%2".</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">Ðе може да отключите портфейла.</translation>
</message>
@@ -1093,6 +1388,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Bitcoin</source>
<translation type="unfinished">Биткоин</translation>
</message>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>фе</numerusform>
+ <numerusform>(от %n гигабайта Ñа нужни)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Ðай малко %1 GB данни ще бъдат запаметени в тази директориÑ, и ще нараÑтват през времето.</translation>
@@ -1105,8 +1421,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(доÑтатъчно за възÑтановÑване на резервните ÐºÐ¾Ð¿Ð¸Ñ %n от преди дни)</numerusform>
+ <numerusform>(доÑтатъчно за възÑтановÑване на резервните ÐºÐ¾Ð¿Ð¸Ñ %n от преди дни)</numerusform>
</translation>
</message>
<message>
@@ -1114,6 +1430,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1 ще Ñвали и Ñъхрани копие на биткойн блокчейна.</translation>
</message>
<message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished">Портфейлът ще Ñе ÑъхранÑва и в тази директориÑ.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation type="unfinished">Грешка: Ðе може да Ñе Ñъздаде поÑочената Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð·Ð° данни "%1"</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">грешка</translation>
</message>
@@ -1130,10 +1454,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Програмата Ñе Ñтартира за първи път вие може да изберете къде %1 ще Ñе запаметÑÑ‚ данните.</translation>
</message>
<message>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">Ограничете блокчейнното Ñъхранение</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
+ <translation type="unfinished">Връщането на тази наÑтройка изиÑква повторно изтеглÑне на цÑлата Ñекторна верига. По-бързо е първо да изтеглите пълната верига и да Ñ Ð¿Ð¾Ð´Ñ€Ñзвате по-къÑно. Деактивира нÑкои разширени функции.</translation>
+ </message>
+ <message>
+ <source> GB</source>
+ <translation type="unfinished">ГБ</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 type="unfinished">Първоначалната ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ðµ изключително взиÑкателна, и може да разкрие хардуерни проблеми Ñ Ð²Ð°ÑˆÐ¸Ñ ÐºÐ¾Ð¼Ð¿ÑŽÑ‚ÑŠÑ€, които до Ñега Ñа били незабелÑзани. Ð’Ñеки път, когато включите %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 type="unfinished">Ðко Ñте избрали да ограничите Ñъхранението на блокови вериги (подрÑзване), иÑторичеÑките данни вÑе още Ñ‚Ñ€Ñбва да бъдат изтеглени и обработени, но ще бъдат изтрити Ñлед това, за да поддържате използването на Ð²Ð°ÑˆÐ¸Ñ Ð´Ð¸Ñк.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation type="unfinished">Използване на Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð¿Ð¾ подразбиране</translation>
</message>
@@ -1160,6 +1500,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 изключва Ñе...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation type="unfinished">Ðе изключвайте компютъра докато този прозорец не изчезне.</translation>
</message>
@@ -1171,6 +1515,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">форма</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 type="unfinished">ПоÑледните транÑакции вÑе още не могат да Ñе виждат и Ñледователно баланÑÑŠÑ‚ на портфейла ви може да бъде неправилен. Тази Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‰Ðµ бъде правилна, Ñлед като портфейлът ви приключи Ñинхронизирането Ñ 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 type="unfinished">Опитът да Ñе изразходват биткойни, които Ñа заÑегнати от вÑе още показаните транÑакции, нÑма да бъдат приети от мрежата.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation type="unfinished">Брой оÑтанали блокове</translation>
+ </message>
+ <message>
+ <source>Unknown…</source>
+ <translation type="unfinished">ÐеизвеÑтно...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">изчиÑлÑване...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation type="unfinished">Време на поÑÐ»ÐµÐ´Ð½Ð¸Ñ Ð±Ð»Ð¾Ðº</translation>
</message>
@@ -1179,13 +1543,37 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">прогреÑ</translation>
</message>
<message>
+ <source>Progress increase per hour</source>
+ <translation type="unfinished">Увеличаване на напредъка на чаÑ</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation type="unfinished">Прогнозираното време оÑтава до Ñинхронизиране</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation type="unfinished">Скрий</translation>
</message>
+ <message>
+ <source>Esc</source>
+ <translation type="unfinished">избÑгай</translation>
+ </message>
+ <message>
+ <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
+ <translation type="unfinished">%1 в момента Ñинхронизира. Той ще Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ Ð·Ð°Ð³Ð»Ð°Ð²Ð¸Ñ Ð¸ блокове от роÑка и ще ги утвърди, докато доÑтигне върха на Ñекторната верига.</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">ÐеизвеÑтно. Синхронизиране на Глави (%1, %2%)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
<message>
+ <source>Open bitcoin URI</source>
+ <translation type="unfinished">Отвори bitcoin URI </translation>
+ </message>
+ <message>
<source>Paste address from clipboard</source>
<extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
<translation type="unfinished">Вмъкни от клипборда</translation>
@@ -1202,6 +1590,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;ОÑновни</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation type="unfinished">Ðвтоматично Ñтартиране %1 Ñлед влизане в ÑиÑтемата.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation type="unfinished">&amp;Стартиране %1 при влизане в ÑиÑтемата</translation>
+ </message>
+ <message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Ðктивирането на подрÑзването значително намалÑва диÑковото проÑтранÑтво, необходимо за ÑъхранÑване на транÑакции. Ð’Ñички блокове вÑе още Ñа напълно валидирани. Връщането на тази наÑтройка изиÑква повторно изтеглÑне на Ñ†ÐµÐ»Ð¸Ñ Ð±Ð»Ð¾ÐºÑ‡ÐµÐ¹Ð½.</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation type="unfinished">Размер на кеша в &amp;базата данни</translation>
</message>
@@ -1214,6 +1614,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">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 type="unfinished">Показва дали предоÑтавениÑÑ‚ proxy по подразбиране Socks5 Ñе използва за доÑтигане до роÑк чрез този тип мрежа.</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 type="unfinished">Минимизиране вмеÑто излизане от приложението, когато прозорецът е затворен. Когато тази Ð¾Ð¿Ñ†Ð¸Ñ Ðµ активирана, приложението ще Ñе затвори Ñамо Ñлед избиране на Изход от менюто.</translation>
+ </message>
+ <message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Опциите, зададени в този диалогов прозорец, Ñе заменÑÑ‚ от ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¸Ñ Ñ€ÐµÐ´:</translation>
+ </message>
+ <message>
<source>Open Configuration File</source>
<translation type="unfinished">Отворете ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»</translation>
</message>
@@ -1230,14 +1642,56 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Мрежа</translation>
</message>
<message>
+ <source>Prune &amp;block storage to</source>
+ <translation type="unfinished">Съкратете &amp;блоковото хранилище до</translation>
+ </message>
+ <message>
<source>GB</source>
<translation type="unfinished">ГБ</translation>
</message>
<message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Връщането на тази наÑтройка изиÑква повторно изтеглÑне на цÑлата блокова верига.</translation>
+ </message>
+ <message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">МакÑимален размер кеш за базата данни. По-големиÑÑ‚ кеш може да допринеÑе за по-бърза ÑинхронизациÑ, Ñлед което ползата е по-малко изразена за повечето Ñлучаи на употреба. ÐамалÑването на размера на кеша ще намали използването на паметта. Ðеизползваната mempool памет Ñе ÑÐ¿Ð¾Ð´ÐµÐ»Ñ Ð·Ð° този кеш.</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Задайте Ð±Ñ€Ð¾Ñ Ð½Ð° нишките за проверка на Ñкрипта. Отрицателните ÑтойноÑти ÑъответÑтват на Ð±Ñ€Ð¾Ñ Ñдра, които иÑкате да оÑтавите Ñвободни за ÑиÑтемата.</translation>
+ </message>
+ <message>
+ <source>(0 = auto, &lt;0 = leave that many cores free)</source>
+ <translation type="unfinished">(0 = авто, &lt;0 = оÑтавете толкова Ñвободни Ñдра) </translation>
+ </message>
+ <message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Това позволÑва на Ð²Ð°Ñ Ð¸Ð»Ð¸ на инÑтрумент на трета Ñтрана да комуникирате Ñ Ð²ÑŠÐ·ÐµÐ»Ð° чрез команден ред и JSON-RPC команди.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Ðктивиране на R&amp;PC Ñървър</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">По&amp;ртфейл</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Дали да зададете изваждане на такÑа от Ñумата по подразбиране или не.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Изваждане &amp;такÑа от Ñума по подразбиране</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">ЕкÑперт</translation>
</message>
@@ -1246,10 +1700,36 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ПозволÑване на монетите и &amp;техните възможноÑти</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 type="unfinished">Ðко деактивирате разходите за непотвърдена промÑна, промÑната от транÑÐ°ÐºÑ†Ð¸Ñ Ð½Ðµ може да Ñе използва, докато тази Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ Ð½Ñма поне едно потвърждение. Това Ñе отразÑва и на това как Ñе изчиÑлÑва вашиÑÑ‚ баланÑ.</translation>
+ </message>
+ <message>
<source>&amp;Spend unconfirmed change</source>
<translation type="unfinished">&amp;Похарчете непотвърденото реÑто</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Ðктивиране &amp;PSBT контроли</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Дали да покажа PSBT контроли.</translation>
+ </message>
+ <message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">Външен Ð¿Ð¾Ð´Ð¿Ð¸Ñ (например хардуерен портфейл)</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;Външен път на Ñкрипта на подпиÑващиÑ</translation>
+ </message>
+ <message>
+ <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished">Пълен път към ÑъвмеÑтим Ñ Ð±Ð¸Ñ‚ÐºÐ¾Ð¹Ð½ оÑновен Ñкрипт (например C: \ Downloads \ hwi.exe или /users/you/downloads/hwi.py). Внимавайте: злонамерен Ñофтуер може да открадне вашите монети!</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 type="unfinished">Ðвтоматично отварÑне на входÑÑ‰Ð¸Ñ Bitcoin порт. Работи Ñамо Ñ Ñ€ÑƒÑ‚ÐµÑ€Ð¸ поддържащи UPnP.</translation>
</message>
@@ -1326,6 +1806,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Дали да покаже възможноÑтите за контрол на монетите или не.</translation>
</message>
<message>
+ <source>Monospaced font in the Overview tab:</source>
+ <translation type="unfinished">Моноширинен шрифт в раздела Общ преглед:</translation>
+ </message>
+ <message>
<source>&amp;OK</source>
<translation type="unfinished">ОК</translation>
</message>
@@ -1334,6 +1818,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Отказ</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Компилиран без поддръжка на външни подпиÑи (изиÑква Ñе за външно подпиÑване)</translation>
+ </message>
+ <message>
<source>default</source>
<translation type="unfinished">подразбиране</translation>
</message>
@@ -1343,14 +1832,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Потвърдете опциите за нулиране</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">ИзиÑква Ñе реÑтартиране на клиента за активиране на извършените промени.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Клиентът ще бъде изключен. ИÑкате ли да продължите?</translation>
</message>
<message>
@@ -1429,6 +1921,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>PSBTOperationsDialog</name>
<message>
+ <source>Save…</source>
+ <translation type="unfinished">Запази...</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished">Затвори</translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">или</translation>
</message>
@@ -1751,6 +2251,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Копирай адреÑ</translation>
</message>
<message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Копиране на етикет</translation>
+ </message>
+ <message>
<source>Copy &amp;amount</source>
<translation type="unfinished">Копирай Ñума</translation>
</message>
@@ -1971,10 +2475,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Transaction creation failed!</source>
<translation type="unfinished">Грешка при Ñъздаването на транзакциÑ!</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">ЗаÑвката за плащане е изтекла.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2029,15 +2529,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Message:</source>
<translation type="unfinished">Съобщение:</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Плащане на:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Бележка:</translation>
- </message>
-</context>
+ </context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
@@ -2148,15 +2640,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>TransactionDesc</name>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/непотвърдено, %1</translation>
- </message>
- <message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/непотвърдени</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">включена в %1 блока</translation>
</message>
<message>
@@ -2412,6 +2902,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Копирай адреÑ</translation>
</message>
<message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Копиране на етикет</translation>
+ </message>
+ <message>
<source>Copy &amp;amount</source>
<translation type="unfinished">Копирай Ñума</translation>
</message>
@@ -2420,6 +2914,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ИзнаÑÑне иÑториÑта на транзакциите</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Файл, разделен ÑÑŠÑ Ð·Ð°Ð¿ÐµÑ‚Ð°Ñ</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">Потвърдено</translation>
</message>
@@ -2509,6 +3008,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Запазване на портфейла</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Данни от портфейла</translation>
+ </message>
+ <message>
<source>Backup Failed</source>
<translation type="unfinished">ÐеуÑпешно запазване на портфейла</translation>
</message>
diff --git a/src/qt/locale/bitcoin_bn.ts b/src/qt/locale/bitcoin_bn.ts
index b76dbb3bee..e12935ea1c 100644
--- a/src/qt/locale/bitcoin_bn.ts
+++ b/src/qt/locale/bitcoin_bn.ts
@@ -55,6 +55,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">1%1 সেটিংস ফাইল টি সমà§à¦­à¦¬à¦¤ নষà§à¦Ÿ বা করাপà§à¦Ÿ</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">পলাতক বà§à¦¯à¦¤à¦¿à¦•à§à¦°à¦®</translation>
</message>
@@ -74,6 +78,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">আপনি কি সেটিংস পà§à¦¨à¦°à¦¾à¦¯à¦¼ ডিফলà§à¦Ÿ করতে,অথবা কোনো পরিবরà§à¦¤à¦¨ ছাড়াই ফিরে যেতে চান? </translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">à¦à¦•à¦Ÿà¦¿ জটিল তà§à¦°à§à¦Ÿà¦¿ হয়েছে। সেটিং ফাইল টি রাইটেবল কিনা চেক করà§à¦¨, অথবা -nosettings দিয়ে রান করার চেষà§à¦Ÿà¦¾ করà§à¦¨</translation>
+ </message>
+ <message>
<source>%1 didn't yet exit safely…</source>
<translation type="unfinished">%1 à¦à¦–নো নিরাপদে বের হয়নি</translation>
</message>
@@ -168,6 +182,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">à¦à¦•à¦Ÿà¦¿ নতà§à¦¨ ওয়ালেট তৈরি করà§à¦¨</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">ছোট করà§à¦¨</translation>
+ </message>
+ <message>
<source>&amp;Options…</source>
<translation type="unfinished">&amp;বিকলà§à¦ª...</translation>
</message>
@@ -246,7 +264,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<numerusform />
</translation>
</message>
- </context>
+ <message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">আরো করà§à¦®à§‡à¦° জনà§à¦¯ চাপ দিন</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">নেটওয়ারà§à¦• কারà§à¦¯à¦•à¦²à¦¾à¦ª বনà§à¦§ করà§à¦¨</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">নেটওয়ারà§à¦• কারà§à¦¯à¦•à¦²à¦¾à¦ª চালৠকরà§à¦¨</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation type="unfinished">লেনদেন পাঠানো হয়েছে</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation type="unfinished">লেনদেন আসছে</translation>
+ </message>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">আসল বারà§à¦¤à¦¾:</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -257,6 +302,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Coin Selection</source>
+ <translation type="unfinished">মà§à¦¦à§à¦°à¦¾ নিরà§à¦¬à¦¾à¦šà¦¨</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">পরিমাণ</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">পারিশà§à¦°à¦®à¦¿à¦•</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">পরিবরà§à¦¤à¦¨</translation>
+ </message>
+ <message>
<source>Date</source>
<translation type="unfinished">তারিখ</translation>
</message>
@@ -264,14 +325,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Confirmed</source>
<translation type="unfinished">নিশà§à¦šà¦¿à¦¤ করা হয়েছে</translation>
</message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">ঠিকানা কপি করà§à¦¨</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">কপি লেবেল</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">কপি পরিমাণ</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">লেনদেন আইডি à¦à¦¬à¦‚ আউটপà§à¦Ÿ সূচক কপি করà§à¦¨</translation>
+ </message>
</context>
<context>
<name>WalletController</name>
<message>
- <source>Close wallet</source>
- <translation type="unfinished">ওয়ালেট বনà§à¦§ করà§à¦¨</translation>
- </message>
- <message>
<source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
<translation type="unfinished">আপনি কি নিশà§à¦šà¦¿à¦¤ যে আপনি ওয়ালেট বনà§à¦§ করতে চান&lt;i&gt;%1&lt;/i&gt;?</translation>
</message>
@@ -311,6 +384,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -322,11 +416,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>PeerTableModel</name>
<message>
- <source>Address</source>
- <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
- <translation type="unfinished">ঠিকানা</translation>
- </message>
- <message>
<source>Type</source>
<extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment>
<translation type="unfinished">টাইপ</translation>
@@ -345,6 +434,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>RPCConsole</name>
<message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">ঠিকানা কপি করà§à¦¨</translation>
+ </message>
+ <message>
<source>Unknown</source>
<translation type="unfinished">অজানা</translation>
</message>
@@ -363,6 +457,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>&amp;Message:</source>
<translation type="unfinished">&amp;বারà§à¦¤à¦¾à¦ƒ</translation>
</message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">ঠিকানা কপি করà§à¦¨</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">কপি লেবেল</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">কপি পরিমাণ</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -370,10 +476,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Date</source>
<translation type="unfinished">তারিখ</translation>
</message>
- <message>
- <source>Label</source>
- <translation type="unfinished">লেবেল</translation>
- </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -416,14 +518,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Type</source>
<translation type="unfinished">টাইপ</translation>
</message>
- <message>
- <source>Label</source>
- <translation type="unfinished">লেবেল</translation>
- </message>
</context>
<context>
<name>TransactionView</name>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">ঠিকানা কপি করà§à¦¨</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">কপি লেবেল</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">কপি পরিমাণ</translation>
+ </message>
+ <message>
<source>Comma separated file</source>
<extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
<translation type="unfinished">কমা দিয়ে আলাদা করা ফাইল</translation>
@@ -445,14 +555,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">টাইপ</translation>
</message>
<message>
- <source>Label</source>
- <translation type="unfinished">লেবেল</translation>
- </message>
- <message>
- <source>Address</source>
- <translation type="unfinished">ঠিকানা</translation>
- </message>
- <message>
<source>ID</source>
<translation type="unfinished">আইডি</translation>
</message>
diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts
index f0268f6ade..b306a22830 100644
--- a/src/qt/locale/bitcoin_bs.ts
+++ b/src/qt/locale/bitcoin_bs.ts
@@ -260,6 +260,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Želite li resetirati postavke na zadane vrijednosti ili prekinuti bez unošenja promjena?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Došlo je do fatalne greške. Provjerite da li se u datoteku postavki može pisati ili pokušajte pokrenuti s -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Greška: Navedeni direktorij podataka "%1" ne postoji.</translation>
</message>
@@ -335,6 +345,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Nije moguće proÄitati fajl postavki</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Nije moguće upisati datoteku postavki</translation>
+ </message>
+ <message>
<source>Replaying blocks…</source>
<translation type="unfinished">Reprodukcija blokova…</translation>
</message>
@@ -487,10 +505,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nepodržana kategorija logivanja %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Nadogradnja UTXO baze podataka</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Komentar korisniÄkog agenta (%s) sadrži nesigurne znakove.</translation>
</message>
@@ -558,6 +572,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kreirajte novi novÄanik</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimiziraj</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">NovÄanik:</translation>
</message>
@@ -599,6 +617,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Å ifrirajte privatne kljuÄeve koji pripadaju vaÅ¡em novÄaniku</translation>
</message>
<message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">Potpiši &amp;poruku…</translation>
+ </message>
+ <message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
<translation type="unfinished">Potpišite poruke sa svojim Bitcoin adresama da biste dokazali da ste njihov vlasnik</translation>
</message>
@@ -607,6 +629,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Potvrdite poruke kako biste bili sigurni da su potpisane navedenim Bitcoin adresama</translation>
</message>
<message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">Otvori &amp;URI…</translation>
+ </message>
+ <message>
<source>Close Wallet…</source>
<translation type="unfinished">Zatvori novÄanik...</translation>
</message>
@@ -767,6 +793,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nema dostupnih novÄanika</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Ime NovÄanika</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Prozor</translation>
</message>
@@ -1182,6 +1213,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Najmanje %1 GB podataka bit će pohranjeno u ovom direktoriju i vremenom će rasti.</translation>
@@ -1228,10 +1283,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Zato Å¡to je ovo prvi put da se program pokreće, možete odabrati gdje će %1 Äuvati 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 type="unfinished">Kada kliknete OK, %1 će poÄeti preuzimati i obraÄ‘ivati ​​puni lanac blokova %4 (%2GB), poÄevÅ¡i od najranijih transakcija u %3 kada je %4 prvi put pokrenut.</translation>
- </message>
- <message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">Vraćanje ove postavke zahtijeva ponovno preuzimanje cijelog lanca blokova. Brže je prvo preuzeti Äitav lanac i kasnije ga obrezati. Onemogućava neke napredne funkcije.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts
index 22a5ab2ca3..908de3c082 100644
--- a/src/qt/locale/bitcoin_ca.ts
+++ b/src/qt/locale/bitcoin_ca.ts
@@ -257,14 +257,20 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<source>Internal error</source>
<translation type="unfinished">Error intern</translation>
</message>
- <message>
- <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
- <translation type="unfinished">S'ha produït un error intern. %1 intentarà continuar amb seguretat. Es pot informar sobre aquest error inesperat com es descriu a continuació.</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Voleu restablir la configuració als valors predeterminats o sortir sense desar els canvis?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Un error fatal s'ha produit. Revisa que l'arxiu de preferències sigui d'escriptura, o torna-ho a intentar amb -nosettings</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Error: El directori de dades especificat «%1» no existeix.</translation>
</message>
@@ -384,6 +390,14 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">El fitxer de configuració no es pot llegir</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">El fitxer de configuració no pot ser escrit</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">Els desenvolupadors %s</translation>
</message>
@@ -432,10 +446,6 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<translation type="unfinished">Error: les carteres heretades només admeten els tipus d'adreces «legacy», «p2sh-segwit» i «bech32»</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Error: ha fallat escoltar les connexions entrants (l'escoltament ha retornat l'error %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">L'estimació de la quota ha fallat. Fallbackfee està desactivat. Espereu uns quants blocs o activeu -fallbackfee.</translation>
</message>
@@ -644,10 +654,6 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<translation type="unfinished">S'ha produït un error en llegir el següent registre de la base de dades de la cartera</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">S'ha produït un error en actualitzar la base de dades de chainstate</translation>
- </message>
- <message>
<source>Error: Couldn't create cursor into database</source>
<translation type="unfinished">Error: No s'ha pogut crear el cursor a la base de dades</translation>
</message>
@@ -781,10 +787,6 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<translation type="unfinished">Cal especificar un port amb -whitebind: «%s»</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">No s'ha especificat cap servidor intermediari. Utilitzeu -proxy =&lt;ip&gt; o -proxy =&lt;ip:port&gt;.</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">No hi ha suficient descriptors de fitxers disponibles.</translation>
</message>
@@ -793,10 +795,6 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<translation type="unfinished">La poda no es pot configurar amb un valor negatiu.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">El mode de poda és incompatible amb -coinstatsindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">El mode de poda és incompatible amb -txindex.</translation>
</message>
@@ -961,10 +959,6 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<translation type="unfinished">Categoria de registre no admesa %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Actualització de la base de dades UTXO</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">El comentari de l'agent d'usuari (%s) conté caràcters insegurs.</translation>
</message>
@@ -1032,6 +1026,10 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<translation type="unfinished">Crear una nova cartera</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimitza</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Moneder:</translation>
</message>
@@ -1090,7 +1088,7 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation type="unfinished">Signa els missatges amb la seva adreça de Bitcoin per a provar que les posseeixes</translation>
+ <translation type="unfinished">Signa el missatges amb la seva adreça de Bitcoin per provar que les poseeixes</translation>
</message>
<message>
<source>&amp;Verify message…</source>
@@ -1098,7 +1096,7 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation type="unfinished">Verifiqueu els missatges per a assegurar-vos que han estat signats amb una adreça Bitcoin específica.</translation>
+ <translation type="unfinished">Verifiqueu els missatges per assegurar-vos que han estat signats amb una adreça Bitcoin específica.</translation>
</message>
<message>
<source>&amp;Load PSBT from file…</source>
@@ -1179,8 +1177,8 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Processat(s) %n bloc(s) de l'historial de transaccions.</numerusform>
+ <numerusform>Processat(s) %n bloc(s) de l'historial de transaccions.</numerusform>
</translation>
</message>
<message>
@@ -1216,6 +1214,10 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<translation type="unfinished">Carrega la transacció Bitcoin signada parcialment</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">Carrega la PSBT des del porta-retalls.</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">Carrega la transacció de Bitcoin signada parcialment des del porta-retalls</translation>
</message>
@@ -1276,6 +1278,16 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<translation type="unfinished">No hi ha cap cartera disponible</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Dades de la cartera</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nom de la cartera</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Finestra</translation>
</message>
@@ -1291,12 +1303,16 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<source>%1 client</source>
<translation type="unfinished">Client de %1</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Amaga</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n connexió activa a la xarxa Bitcoin</numerusform>
+ <numerusform>%n connexions actives a la xarxa Bitcoin</numerusform>
</translation>
</message>
<message>
@@ -1570,7 +1586,7 @@ Només és possible firmar amb adreces del tipus "legacy".</translation>
<source>Can't list signers</source>
<translation type="unfinished">No es poden enumerar signants</translation>
</message>
-</context>
+ </context>
<context>
<name>OpenWalletActivity</name>
<message>
@@ -1772,13 +1788,26 @@ Això és ideal per a carteres de mode només lectura.</translation>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(of %1 GB necessaris)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB necessaris per a la cadena completa)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(Un GB necessari)</numerusform>
+ <numerusform>(de %n GB necessàris)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(Un GB necessari per a la cadena completa)</numerusform>
+ <numerusform>(Un GB necessari per a la cadena completa)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1792,8 +1821,8 @@ Això és ideal per a carteres de mode només lectura.</translation>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(suficient per restaurar les còpies de seguretat de%n dia (s))</numerusform>
+ <numerusform>(suficient per a restaurar les còpies de seguretat de %n die(s))</numerusform>
</translation>
</message>
<message>
@@ -1821,10 +1850,6 @@ Això és ideal per a carteres de mode només lectura.</translation>
<translation type="unfinished">Com és la primera vegada que s'executa el programa, podeu triar on %1 emmagatzemaran les dades.</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 type="unfinished">Quan feu clic a D'acord, %1 començarà a descarregar i processar la cadena de blocs %4 completa (%2 GB) començant per les primeres transaccions de %3, any de llençament inicial de %4.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Limita l’emmagatzematge de la cadena de blocs a</translation>
</message>
@@ -1929,7 +1954,7 @@ Això és ideal per a carteres de mode només lectura.</translation>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Desconegut. Sincronització de les capçaleres (%1, %2%)...</translation>
</message>
-</context>
+ </context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -2157,10 +2182,6 @@ Això és ideal per a carteres de mode només lectura.</translation>
<translation type="unfinished">coincidència més propera "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Opcions configurades en aquest diàleg són sobreescrites per la línia de comandes o el fitxer de configuració:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">&amp;D'acord</translation>
</message>
@@ -2183,14 +2204,17 @@ Això és ideal per a carteres de mode només lectura.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirmeu el reestabliment de les opcions</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Cal reiniciar el client per a activar els canvis.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">S'aturarà el client. Voleu procedir?</translation>
</message>
<message>
@@ -3410,10 +3434,6 @@ Nota: atès que la tarifa es calcula per byte, una tarifa de "100 satoshis per k
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Una tarifa superior a %1 es considera una tarifa absurdament alta.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">La sol·licitud de pagament ha vençut.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -3497,14 +3517,6 @@ Nota: atès que la tarifa es calcula per byte, una tarifa de "100 satoshis per k
<translation type="unfinished">Missatge:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Aquesta és una sol·licitud de pagament no autenticada.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Aquesta és una sol·licitud de pagament autenticada.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Introduïu una etiqueta per a aquesta adreça per afegir-la a la llista d'adreces utilitzades</translation>
</message>
@@ -3512,11 +3524,7 @@ Nota: atès que la tarifa es calcula per byte, una tarifa de "100 satoshis per k
<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 type="unfinished">Un missatge que s'ha adjuntat al bitcoin: URI que s'emmagatzemarà amb la transacció per a la vostra referència. Nota: el missatge no s'enviarà a través de la xarxa Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Paga a:</translation>
- </message>
- </context>
+</context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -3686,30 +3694,22 @@ Nota: atès que la tarifa es calcula per byte, una tarifa de "100 satoshis per k
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">produït un conflicte amb una transacció amb %1 confirmacions</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/no confirmades, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">a la reserva de memòria</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">no a la reserva de memòria</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">abandonada</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/sense confirmar</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 confirmacions</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts
index 497d17b022..9762ef7c84 100644
--- a/src/qt/locale/bitcoin_cs.ts
+++ b/src/qt/locale/bitcoin_cs.ts
@@ -241,6 +241,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Soubor s nastavením %1 může být poškozený nebo neplatný.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">Uprchlá výjimka</translation>
</message>
@@ -260,6 +264,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Přeješ si obnovit výchozí nastavení, nebo odejít bez ukládání změn?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Nastala závažná chyba. Ověř zda-li je možné do souboru s nastavením zapisovat a nebo vyzkoušej aplikaci spustit s parametrem -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Chyba: Zadaný adresář pro data „%1“ neexistuje.</translation>
</message>
@@ -341,41 +355,41 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n sekunda</numerusform>
+ <numerusform>%n sekundy</numerusform>
+ <numerusform>%n sekund</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n minuta</numerusform>
+ <numerusform>%n minuty</numerusform>
+ <numerusform>%n minut</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n hodina</numerusform>
+ <numerusform>%n hodiny</numerusform>
+ <numerusform>%n hodin</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n den</numerusform>
+ <numerusform>%n dny</numerusform>
+ <numerusform>%n dní</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n týden</numerusform>
+ <numerusform>%n týdny</numerusform>
+ <numerusform>%n týdnů</numerusform>
</translation>
</message>
<message>
@@ -385,15 +399,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n rok</numerusform>
+ <numerusform>%n roky</numerusform>
+ <numerusform>%n let</numerusform>
</translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Soubor s nastavením není možné pÅ™eÄíst</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Do souboru s nastavením není možné zapisovat</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">Vývojáři %s</translation>
</message>
@@ -426,6 +448,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">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>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">Chyba pÅ™i Ätení %s! Data o transakci mohou chybÄ›t a nebo být chybná.
+Ověřuji peněženku.</translation>
+ </message>
+ <message>
<source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
<translation type="unfinished">Chyba: záznam formátu souboru výpisu je nesprávný. Získáno "%s", oÄekáváno "format".</translation>
</message>
@@ -442,10 +469,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Chyba: Starší peněženky podporují pouze typy adres "legacy", "p2sh-segwit" a "bech32".</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Chyba: Nelze naslouchat příchozí spojení (listen vrátil chybu %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Odhad poplatku se nepodaÅ™il. Fallbackfee je zakázaný. PoÄkejte nÄ›kolik bloků nebo povolte -fallbackfee.</translation>
</message>
@@ -458,6 +481,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Neplatná Äástka pro -maxtxfee=&lt;amount&gt;: '%s' (musí být alespoň jako poplatek minrelay %s, aby transakce nezůstávaly trÄet)</translation>
</message>
<message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">Neplatný nebo poškozený soubor peers.dat (%s). Pokud věříš, že se jedná o chybu, prosím nahlas ji na %s. Jako řešení lze přesunout soubor (%s) z cesty (přejmenovat, přesunout nebo odstranit), aby se při dalším spuštění vytvořil nový.</translation>
+ </message>
+ <message>
<source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
<translation type="unfinished">Byla zadána více než jedna onion adresa. Použiju %s pro automaticky vytvořenou službu sítě Tor.</translation>
</message>
@@ -486,6 +513,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ProÅ™ezávání je nastaveno pod minimum %d MiB. Použij, prosím, nÄ›jaké vyšší Äíslo.</translation>
</message>
<message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">Režim proÄiÅ¡tÄ›ní je nekompatibilní s parametrem -reindex-chainstate. Místo toho použij plný -reindex.</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 type="unfinished">Prořezávání: poslední synchronizace peněženky proběhla před už prořezanými daty. Je třeba provést -reindex (tedy v případě prořezávacího režimu stáhnout znovu celý blockchain)</translation>
</message>
@@ -498,6 +529,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Databáze bloků obsahuje blok, který vypadá jako z budoucnosti, což může být kvůli Å¡patnÄ› nastavenému datu a Äasu na tvém poÄítaÄi. Nech databázi bloků pÅ™estavÄ›t pouze v případÄ›, že si jsi jistý, že máš na poÄítaÄi správný datum a Äas</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">Databáze indexu bloků obsahuje starší 'txindex'. Pro vyÄiÅ¡tÄ›ní obsazeného místa na disku, spusÅ¥te úplný -reindex, v opaÄném případÄ› tuto chybu ignorujte. Tato chybová zpráva nebude znovu zobrazena.</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished">Částka v transakci po odeÄtení poplatku je příliÅ¡ malá na odeslání</translation>
</message>
@@ -534,6 +569,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Byl poskytnut neznámý formát souboru peněženky "%s". Poskytněte prosím "bdb" nebo "sqlite".</translation>
</message>
<message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">Nalezen nepodporovaný formát databáze řetězců. Restartujte prosím aplikaci s parametrem -reindex-chainstate. Tím dojde k opětovného sestavení databáze řetězců.</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Peněženka úspěšnÄ› vytvoÅ™ena. Starší typ peněženek je oznaÄen za zastaralý a podpora pro vytváření a otevÅ™ení starých peněženek bude v budoucnu odebrána.</translation>
+ </message>
+ <message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
<translation type="unfinished">Varování: formát výpisu peněženky "%s" se neshoduje s formátem "%s", který byl urÄen příkazem.</translation>
</message>
@@ -570,6 +613,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nemohu přeložit -%s adresu: '%s'</translation>
</message>
<message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">Nelze nastavit -forcednsseed na hodnotu true, když je nastaveno -dnsseed na hodnotu false.</translation>
+ </message>
+ <message>
<source>Cannot set -peerblockfilters without -blockfilterindex.</source>
<translation type="unfinished">Nelze nastavit -peerblockfilters bez -blockfilterindex.</translation>
</message>
@@ -578,6 +625,98 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Není možné zapisovat do adresáře ' %s'; zkontrolujte oprávnění.</translation>
</message>
<message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">Aktualizaci -txindex zahájenou pÅ™edchozí verzí není možné dokonÄit. Restartujte s pÅ™edchozí verzí a nebo spusÅ¥te úplný -reindex.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s požadavek pro naslouchání na portu %u. Tento port je považován za "špatný" a z tohoto důvodu je nepravděpodobné, že by se k němu připojovali některé uzly Bitcoin Core. Podrobnosti a úplný seznam špatných portů nalezneš v dokumentu doc/p2p-bad-ports.md.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Parametr -reindex-chainstate není kompatibilní s parametrem -blockfilterindex. PÅ™i použití -reindex-chainstate doÄasnÄ› zakažte parametr -blockfilterindex nebo nahraÄte parametr -reindex-chainstate parametrem -reindex pro úplné opÄ›tovné sestavení vÅ¡ech indexů.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Parametr -reindex-chainstate není kompatibilní s parametrem -coinstatsindex. PÅ™i použití -reindex-chainstate doÄasnÄ› zakažte parametr -coinstatsindex nebo nahraÄte parametr -reindex-chainstate parametrem -reindex pro úplné opÄ›tovné sestavení vÅ¡ech indexů.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Parametr -reindex-chainstate není kompatibilní s parametrem -txindex. PÅ™i použití -reindex-chainstate doÄasnÄ› zakažte parametr -txindex nebo nahraÄte parametr -reindex-chainstate parametrem -reindex pro úplné opÄ›tovné sestavení vÅ¡ech indexů.</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">PÅ™edpokládaná platnost: poslední synchronizace peněženky pÅ™esahuje dostupná data bloků. Je potÅ™eba poÄkat až ověření Å™etÄ›zců v pozadí stáhne další bloky.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Nelze poskytovat konkrétní spojení a zároveň mít vyhledávání addrman odchozích spojení ve stejný Äas.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Chyba pÅ™i naÄtení %s: Externí podepisovací peněženka se naÄítá bez zkompilované podpory externího podpisovatele.</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Chyba: Data adres v peněžence není možné identifikovat jako data patřící k migrovaným peněženkám.</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">Chyba: Duplicitní popisovaÄe vytvoÅ™ené bÄ›hem migrace. VaÅ¡e peněženka může být poÅ¡kozena.</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Chyba: Transakce %s v peněžence nemůže být identifikována jako transakce patřící k migrovaným peněženkám.</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">Chyba: Nelze vytvoÅ™it popisovaÄe pro tuto starší peněženku. Nejprve se ujistÄ›te, že je peněženka odemÄená.</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Nelze přejmenovat neplatný peers.dat soubor. Prosím přesuňte jej, nebo odstraňte a zkuste znovu.</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">Nekompatibilní možnost: -dnsseed=1 byla explicitně zadána, ale -onlynet zakazuje připojení k IPv4/IPv6</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">Odchozí spojení omezená do sítě Tor (-onlynet=onion), ale proxy pro dosažení sítě Tor je výslovně zakázána: -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">Odchozí spojení omezená do sítě Tor (-onlynet=onion), ale není zadán žádný proxy server pro přístup do sítě Tor: není zadán žádný z parametrů: -proxy, -onion, nebo -listenonion</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">Nalezen nerozpoznatelný popisovaÄ. NaÄítaní peněženky %s
+
+Peněženka mohla být vytvořena v novější verzi.
+Zkuste prosím spustit nejnovější verzi softwaru.
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">Nepodporovaná úroveň pro logování úrovnÄ› -loglevel=%s. OÄekávaný parametr -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Platné kategorie: %s. Platné úrovnÄ› logování: %s.</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+NepodaÅ™ilo se vyÄistit nepovedenou migraci</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Nelze obnovit zálohu peněženky.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">Nastavení pro %s je nastaveno pouze na síťi %s pokud jste v sekci [%s]</translation>
</message>
@@ -658,8 +797,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Chyba pÅ™i Ätení následujícího záznamu z databáze peněženky</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Chyba při aktualizaci stavové databáze blockchainu</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">Chyba: Nelze pÅ™idat pouze-sledovací tx do peněženky pro Ätení</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">Chyba: Nelze odstranit transakce které jsou pouze pro Ätení</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
@@ -674,6 +817,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Chyba: kontrolní souÄet souboru výpisu se neshoduje. VypoÄteno %s, oÄekáváno %s</translation>
</message>
<message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">Chyba: Nelze vytvoÅ™it novou peněženku pouze pro Ätení</translation>
+ </message>
+ <message>
<source>Error: Got key that was not hex: %s</source>
<translation type="unfinished">Chyba: obdržený klÃ­Ä nebyl hexadecimální: %s</translation>
</message>
@@ -694,10 +841,38 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Chyba: Žádné %s adresy nejsou dostupné.</translation>
</message>
<message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">Chyba: Ne všechny pouze-sledovací tx bylo možné smazat</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">Chyba: Tato peněženka již používá SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">Chyba: Tato peněženka je již popisovaÄná peněženka</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">Chyba: Nelze zahájit Ätení vÅ¡ech záznamů v databázi</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">Chyba: Nelze vytvořit zálohu tvojí peněženky</translation>
+ </message>
+ <message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">Chyba: nelze zpracovat verzi %u jako uint32_t</translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">Chyba: Nelze pÅ™eÄíst vÅ¡echny záznamy v databázi</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">Chyba: Nelze odstranit data z adresáře pouze pro sledování</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
<translation type="unfinished">Chyba: nelze zapsat záznam do nové peněženky</translation>
</message>
@@ -734,6 +909,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Selhala úvodní zevrubná provÄ›rka. %s se ukonÄuje.</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Vstup nenalezen a nebo je již utracen</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">Nedostatek prostředků</translation>
</message>
@@ -774,6 +953,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ve -whitelist byla zadána neplatná podsíť: '%s'</translation>
</message>
<message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">Chyba: Nelze naslouchat příchozí spojení (naslouchaÄ vrátil chybu %s)</translation>
+ </message>
+ <message>
<source>Loading P2P addresses…</source>
<translation type="unfinished">NaÄítám P2P adresy…</translation>
</message>
@@ -790,12 +973,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">NaÄítám peněženku...</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">ChybÄ›jící Äástka</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">Chybí data pro vyřešení odhadnutí velikosti transakce</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">V rámci -whitebind je třeba specifikovat i port: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Není specifikován proxy server. Použijte -proxy=&lt;ip&gt; nebo -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Není k dispozici žádná adresa</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -806,10 +997,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Prořezávání nemůže být zkonfigurováno s negativní hodnotou.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Prořezávací režim je nekompatibilní s -coinstatsindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">Prořezávací režim není kompatibilní s -txindex.</translation>
</message>
@@ -910,6 +1097,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Částky v transakci nemohou být záporné</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">Výstupní index změny transakce mimo rozsah</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">Transakce má v transakÄním zásobníku příliÅ¡ dlouhý Å™etÄ›zec</translation>
</message>
@@ -918,10 +1109,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transakce musí mít alespoň jednoho příjemce</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">Transakce potřebuje změnu adresy, ale ta se nepodařila vygenerovat.</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">Transakce je příliš velká</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">Není možné alokovat paměť pro -maxsigcachesize '%s' MiB</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation type="unfinished">Nedaří se mi pÅ™ipojit na %s na tomhle poÄítaÄi (operace bind vrátila chybu %s)</translation>
</message>
@@ -934,6 +1133,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nebylo možné vytvořit soubor PID '%s': %s</translation>
</message>
<message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">Nelze najít UTXO pro externí vstup</translation>
+ </message>
+ <message>
<source>Unable to generate initial keys</source>
<translation type="unfinished">NepodaÅ™ilo se mi vygenerovat poÄáteÄní klíÄe</translation>
</message>
@@ -946,10 +1149,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nelze otevřít %s pro zápis</translation>
</message>
<message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">Nelze rozebrat -maxuploadtarget: '%s'</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">Nemohu spustit HTTP server. Detaily viz v debug.log.</translation>
</message>
<message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">PÅ™ed migrací není možné peněženku odnaÄíst</translation>
+ </message>
+ <message>
<source>Unknown -blockfilterindex value %s.</source>
<translation type="unfinished">Neznámá -blockfilterindex hodnota %s.</translation>
</message>
@@ -970,12 +1181,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Neznámá nová pravidla aktivována (verzový bit %i)</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">Nepodporovaná logovací kategorie %s=%s.</translation>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">Nepodporovaný globální logovací úroveň -loglevel=%s. Možné hodnoty: %s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Aktualizuji databázi neutracených výstupů (UTXO)</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Nepodporovaná logovací kategorie %s=%s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
@@ -1045,6 +1256,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Vytvoř novou peněženku</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimalizovat</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Peněženka:</translation>
</message>
@@ -1192,9 +1407,9 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Zpracován %n blok transakÄní historie.</numerusform>
+ <numerusform>Zpracovány %n bloky transakÄní historie.</numerusform>
+ <numerusform>Zpracováno %n bloků transakÄní historie</numerusform>
</translation>
</message>
<message>
@@ -1234,6 +1449,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">NaÄíst ÄásteÄnÄ› podepsanou Bitcoinovou transakci</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">NaÄíst PSBT ze &amp;schránky</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">NaÄíst ÄásteÄnÄ› podepsanou Bitcoinovou transakci ze schránky</translation>
</message>
@@ -1270,6 +1489,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Zavřít peněženku</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Obnovit peněženku...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Obnovit peněženku ze záložního souboru</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Zavřít všechny peněženky</translation>
</message>
@@ -1294,6 +1523,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nejsou dostupné žádné peněženky</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Data peněženky</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Nahrát zálohu peněženky</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Obnovit peněženku</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Název peněženky</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">O&amp;kno</translation>
</message>
@@ -1309,13 +1558,21 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 klient</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">Skryj</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">Zobraz</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n aktivní spojení s Bitcoinovou sítí.</numerusform>
+ <numerusform>%n aktivní spojení s Bitcoinovou sítí.</numerusform>
+ <numerusform>%n aktivních spojení s Bitcoinovou sítí.</numerusform>
</translation>
</message>
<message>
@@ -1339,6 +1596,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Zapnout síťovou aktivitu</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">PÅ™edběžná synchronizace hlaviÄky bloků (%1 %)...</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Chyba: %1</translation>
</message>
@@ -1509,6 +1770,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Zkopírovat &amp;Äástku</translation>
</message>
<message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Zkopíruj &amp;ID transakce a výstupní index</translation>
+ </message>
+ <message>
<source>L&amp;ock unspent</source>
<translation type="unfinished">&amp;zamknout neutracené</translation>
</message>
@@ -1597,6 +1862,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">Nelze vypsat podepisovatele</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Nalezeno mnoho externích podpisovatelů</translation>
+ </message>
+</context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">NaÄíst peněženky</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">NaÄítám peněženky...</translation>
+ </message>
</context>
<context>
<name>OpenWalletActivity</name>
@@ -1624,6 +1906,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Obnovit peněženku</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Obnovuji peněženku &lt;b&gt;%1&lt;/b&gt; ...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Obnovení peněženky selhalo</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Varování při obnovení peněženky</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Obnovení peněženky</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1798,9 +2108,29 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(z požadovaných %1 GB )</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB místa k dispozici</numerusform>
+ <numerusform>%n GB místa k dispozici</numerusform>
+ <numerusform>%n GB místa k dispozici</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(z %n GB požadovaných)</numerusform>
+ <numerusform>(z %n GB požadovaných)</numerusform>
+ <numerusform>(z %n GB požadovaných)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB požadovaných pro plný řetězec)</numerusform>
+ <numerusform>(%n GB požadovaných pro plný řetězec)</numerusform>
+ <numerusform>(%n GB požadovaných pro plný řetězec)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1814,9 +2144,9 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>(DostaÄující k obnovení zálohy %n dne staré)</numerusform>
+ <numerusform>(DostaÄující k obnovení záloh %n dnů staré)</numerusform>
+ <numerusform>(DostaÄující k obnovení záloh %n dnů staré)</numerusform>
</translation>
</message>
<message>
@@ -1848,10 +2178,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tohle je poprvé, co spouštíš %1, takže si můžeš zvolit, kam bude ukládat svá data.</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 type="unfinished">Jakmile stiskneÅ¡ OK, %1 zaÄne stahovat a zpracovávat celý %4ový blockchain (%2 GB), poÄínaje nejstaršími transakcemi z roku %3, kdy byl %4 spuÅ¡tÄ›n.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Omezit uložiště blokového řetězce na</translation>
</message>
@@ -1868,6 +2194,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Prvotní synchronizace je velice nároÄná, a mohou se tak díky ní zaÄít na tvém poÄítaÄi projevovat dosud skryté hardwarové problémy. Pokaždé, když spustíš %1, bude stahování pokraÄovat tam, kde skonÄilo.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Jakmile stiskneÅ¡ OK, %1 zaÄne stahovat a zpracovávat celý %4ový blockchain (%2 GB), poÄínaje nejstaršími transakcemi z roku %3, kdy byl %4 spuÅ¡tÄ›n.</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 type="unfinished">Pokud jsi omezil úložný prostor pro blockchain (tj. povolil jeho prořezávání), tak se historická data sice stáhnou a zpracují, ale následně zase smažou, aby nezabírala na disku místo.</translation>
</message>
@@ -1964,6 +2294,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Neznámé. Synchronizace hlaviÄek bloků (%1, %2%)...</translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Neznámé. PÅ™edběžná synchronizace hlaviÄky bloků (%1, %2%)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -2020,6 +2354,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ZavÅ™ením se aplikace minimalizuje. Pokud je tato volba zaÅ¡krtnuta, tak se aplikace ukonÄí pouze zvolením Konec v menu.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Nastavení v tomto dialogu jsou přepsány příkazovým řádkem:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">OtevÅ™e konfiguraÄní soubor %1 z pracovního adresáře.</translation>
</message>
@@ -2048,14 +2386,44 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Obnovení tohoto nastavení vyžaduje opětovné stažení celého blockchainu.</translation>
</message>
<message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">Maximální velikost vyrovnávací paměti databáze. Větší vyrovnávací paměť může přispět k rychlejší synchronizaci, avšak přínos pro většinu případů použití je méně výrazný. Snížení velikosti vyrovnávací paměti sníží využití paměti. Nevyužívaná paměť mempoolu je pro tuto vyrovnávací paměť sdílená.</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Nastaví poÄet vláken pro ověřování skriptů. Negativní hodnota odpovídá poÄtu jader procesoru, které chcete ponechat volné pro systém. </translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = automaticky, &lt;0 = nechat daný poÄet jader volný, výchozí: 0)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Toto povolí tobě nebo nástrojům třetích stran komunikovat pomocí uzlu skrz příkazový řádek a JSON-RPC příkazy.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Povolit R&amp;PC server</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">P&amp;eněženka</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Zda nastavit odeÄtení poplatku od Äástky jako výchozí Äi nikoliv.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">OdeÄíst &amp;poplatek od výchozí Äástky</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">PokroÄilá nastavení</translation>
</message>
@@ -2072,6 +2440,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Utrácet i ještě nepotvrzené drobné</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Povolit &amp;PSBT kontrolu</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Zobrazit ovládací prvky PSBT.</translation>
+ </message>
+ <message>
<source>External Signer (e.g. hardware wallet)</source>
<translation type="unfinished">Externí podepisovatel (například hardwarová peněženka)</translation>
</message>
@@ -2176,6 +2554,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Zvol výchozí podjednotku, která se bude zobrazovat v programu a při posílání mincí.</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 type="unfinished">URL třetích stran (např. block exploreru), která se zobrazí v kontextovém menu v záložce Transakce. %s v URL se nahradí hashem transakce. Více URL odděl svislítkem |.</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;URL třetích stran pro transakce</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">Zda ukazovat možnosti pro ruÄní správu mincí nebo ne.</translation>
</message>
@@ -2200,10 +2586,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">nejbližší shoda "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Nastavení v tomto dialogu jsou pÅ™epsány konzolí nebo konfiguraÄním souborem:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">&amp;Budiž</translation>
</message>
@@ -2226,14 +2608,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Potvrzení obnovení nastavení</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">K aktivaci změn je potřeba restartovat klienta.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Aktuální nastavení bude uloženo v "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Klient se vypne, chceÅ¡ pokraÄovat?</translation>
</message>
<message>
@@ -2247,6 +2637,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">KonfiguraÄní soubor slouží k nastavování uživatelsky pokroÄilých možností, které mají pÅ™ednost pÅ™ed konfigurací z GUI. Parametry z příkazové řádky vÅ¡ak mají pÅ™ed konfiguraÄním souborem pÅ™ednost.</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">PokraÄovat</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">Zrušit</translation>
</message>
@@ -2268,6 +2662,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Nelze pÅ™eÄíst nastavení "%1", %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2377,6 +2778,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nepodařilo se podepsat transakci: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">Nelze podepsat vstup, když je peněženka uzamÄena.</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">Nelze podepsat další vstupy.</translation>
</message>
@@ -2450,6 +2855,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transakce stále potřebuje podpis(y).</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Ale žádná peněženka není naÄtená.)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Ale tato peněženka nemůže podepisovat transakce.)</translation>
</message>
@@ -2519,6 +2928,11 @@ Pokud vidíte tuto chybu, měli byste požádat, aby obchodník poskytl adresu k
<translation type="unfinished">Protějšek</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Trvání</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Směr</translation>
@@ -2702,6 +3116,10 @@ Pokud vidíte tuto chybu, měli byste požádat, aby obchodník poskytl adresu k
<translation type="unfinished">Aktuálně bloků</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Poslední transakce</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">Mapovaný nezávislý - Autonomní Systém používaný pro rozšírení vzájemného výběru protějsků.</translation>
</message>
@@ -2710,6 +3128,36 @@ Pokud vidíte tuto chybu, měli byste požádat, aby obchodník poskytl adresu k
<translation type="unfinished">Mapovaný AS</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Zda předáváme adresy tomuto uzlu.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Přenášení adres</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Celkový poÄet adres obdržených od tohoto uzlu, které byly zpracovány (nezahrnuje adresy, které byly zahozeny díky omezení ovládání toku provozu)</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Celkový poÄet adres obdržených od tohoto uzlu, který byly zahozeny (nebyly zpracovány) díky omezení ovládání toku provozu.</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Zpracováno adres</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Adresy s omezením poÄtu pÅ™ijatých adres</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">Typ klienta</translation>
</message>
@@ -2918,6 +3366,11 @@ Pokud vidíte tuto chybu, měli byste požádat, aby obchodník poskytl adresu k
<translation type="unfinished">1 &amp;rok</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Zkopíruj IP/Masku</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Odblokuj</translation>
</message>
@@ -3425,6 +3878,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">Zkontrolujte prosím svůj návrh transakce. Výsledkem bude ÄásteÄnÄ› podepsaná bitcoinová transakce (PSBT), kterou můžete uložit nebo kopírovat a poté podepsat napÅ™. pomocí offline %1 peněženky nebo hardwarové peněženky kompatibilní s PSBT.</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Přejete si vytvořit tuto transakci?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Prosím ověř svojí transakci. MůžeÅ¡ vytvoÅ™it a odeslat tuto transakci nebo vytvoÅ™it ČásteÄnÄ› Podepsanou Bitcoinovou Transakci (PSBT), kterou můžeÅ¡ uložit nebo zkopírovat a poté podepsat napÅ™. v offline %1 peněžence, nebo hardwarové peněžence kompatibilní s PSBT.</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Prosím, zkontrolujte vaši transakci.</translation>
@@ -3477,16 +3940,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Poplatek vyšší než %1 je považován za absurdně vysoký.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Platební požadavek vypršel.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Potvrzování by podle odhadu mÄ›lo zaÄít bÄ›hem %n bloku.</numerusform>
+ <numerusform>Potvrzování by podle odhadu mÄ›lo zaÄít bÄ›hem %n bloků.</numerusform>
+ <numerusform>Potvrzování by podle odhadu mÄ›lo zaÄít bÄ›hem %n bloků.</numerusform>
</translation>
</message>
<message>
@@ -3561,14 +4020,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">Zpráva:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Tohle je neověřený platební požadavek.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Tohle je ověřený platební požadavek.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Zadej oznaÄení této adresy; obojí se ti pak uloží do adresáře</translation>
</message>
@@ -3576,14 +4027,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<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 type="unfinished">Zpráva, která byla připojena k bitcoin: URI a která se ti pro přehled uloží k transakci. Poznámka: Tahle zpráva se neposílá s platbou po bitcoinové síti.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Komu:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Poznámka:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3745,35 +4188,41 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>(press q to shutdown and continue later)</source>
<translation type="unfinished">(stiskni q pro ukonÄení a pokraÄování pozdÄ›ji)</translation>
</message>
- </context>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">stiskněte q pro vypnutí</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">koliduje s transakcí o %1 konfirmacích</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/nepotvrzeno, %1</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/nepotvrzené, je v transakÄním zásobníku</translation>
</message>
<message>
- <source>in memory pool</source>
- <translation type="unfinished">v transakÄním zásobníku</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">není ani v transakÄním zásobníku</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/nepotvrzené, není v transakÄním zásobníku</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">zanechaná</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/nepotvrzeno</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 potvrzení</translation>
</message>
<message>
@@ -3823,9 +4272,9 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>dozraje za %n další blok</numerusform>
+ <numerusform>dozraje za %n další bloky</numerusform>
+ <numerusform>dozraje za %n dalších bloků</numerusform>
</translation>
</message>
<message>
@@ -4110,6 +4559,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">&amp;Upravit oznaÄení adresy</translation>
</message>
<message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Zobraz v %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Exportuj transakÄní historii</translation>
</message>
diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts
index 6d8ee73324..ccff0580fd 100644
--- a/src/qt/locale/bitcoin_cy.ts
+++ b/src/qt/locale/bitcoin_cy.ts
@@ -660,6 +660,36 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts
index 53a7eae7d2..8c64ee84a5 100644
--- a/src/qt/locale/bitcoin_da.ts
+++ b/src/qt/locale/bitcoin_da.ts
@@ -245,6 +245,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Indstillings filen 1%1 kan være korrupt eller invalid.</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">Runaway undtagelse</translation>
+ </message>
+ <message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
<translation type="unfinished">Der skete en fatal fejl. %1 kan ikke længere fortsætte sikkert og vil afslutte.</translation>
</message>
@@ -252,10 +260,24 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Internal error</source>
<translation type="unfinished">Intern fejl</translation>
</message>
- </context>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Der skete en intern fejl. %1 vil prøve at forsætte på sikker vis. Dette er en uventet fejl som kan reporteres som beskrevet under. </translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Vil du nulstille indstillinger til standardværdier eller afbryde uden at foretage ændringer?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Der opstod en fatal fejl. Tjek at indstillingsfilen er skrivbar, eller prøv at anvend -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Fejl: Angivet datamappe “%1†eksisterer ikke.</translation>
</message>
@@ -268,6 +290,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Fejl: %1</translation>
</message>
<message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 har endnu ikke afsluttet på sikker vis…</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">ukendt</translation>
</message>
@@ -280,6 +306,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Indtast en Bitcoin-adresse (fx %1)</translation>
</message>
<message>
+ <source>Unroutable</source>
+ <translation type="unfinished">Urutebar</translation>
+ </message>
+ <message>
<source>Internal</source>
<translation type="unfinished">Intern</translation>
</message>
@@ -294,11 +324,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Udgående</translation>
</message>
<message>
+ <source>Full Relay</source>
+ <extracomment>Peer connection type that relays all network information.</extracomment>
+ <translation type="unfinished">Fuld Videresend</translation>
+ </message>
+ <message>
+ <source>Block Relay</source>
+ <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Blok Vidersend</translation>
+ </message>
+ <message>
<source>Manual</source>
<extracomment>Peer connection type established manually through one of several methods.</extracomment>
<translation type="unfinished">Brugervejledning</translation>
</message>
<message>
+ <source>Feeler</source>
+ <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Føler</translation>
+ </message>
+ <message>
<source>Address Fetch</source>
<extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
<translation type="unfinished">Adresse Indhentning</translation>
@@ -314,36 +359,36 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n sekund(er)</numerusform>
+ <numerusform>%n sekund(er)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minut(er)</numerusform>
+ <numerusform>%n minut(er)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n time(r)</numerusform>
+ <numerusform>%n time(r)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n dag(e)</numerusform>
+ <numerusform>%n dag(e)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n uge(r)</numerusform>
+ <numerusform>%n uge(r)</numerusform>
</translation>
</message>
<message>
@@ -353,14 +398,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n år</numerusform>
+ <numerusform>%n år</numerusform>
</translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Indstillingsfilen kunne ikke læses</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Indstillingsfilen kunne ikke skrives</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">Udviklerne af %s</translation>
</message>
@@ -373,10 +426,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">-maxtxfee er sat meget højt! Gebyrer så store risikeres betalt på en enkelt transaktion.</translation>
</message>
<message>
+ <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
+ <translation type="unfinished">Kan ikke nedgradere tegnebogen fra version %i til version %i. Wallet-versionen uændret.</translation>
+ </message>
+ <message>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<translation type="unfinished">Kan ikke opnå en lås på datamappe %s. %s kører sansynligvis allerede.</translation>
</message>
<message>
+ <source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
+ <translation type="unfinished">Kan ikke opgradere en ikke-HD split wallet fra version %i til version %i uden at opgradere til at understøtte pre-split keypool. Brug venligst version %i eller ingen version angivet.</translation>
+ </message>
+ <message>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished">Distribueret under MIT-softwarelicensen; se den vedlagte fil %s eller %s</translation>
</message>
@@ -385,22 +446,58 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">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>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Fejl: Lytning efter indkommende forbindelser mislykkedes (lytning resultarede i fejl %s)</translation>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">Fejl ved læsning %s! Transaktionsdata kan mangle eller være forkerte. Genscanner tegnebogen.</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
+ <translation type="unfinished">Fejl: Dumpfilformat dokument er forkert. Fik "%s", forventet "format".</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source>
+ <translation type="unfinished">Fejl: Dumpfilformat dokument er forkert. Fik "%s", forventet "%s".</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
+ <translation type="unfinished">Fejl: Dumpfil-versionen understøttes ikke. Denne version af bitcoin-tegnebog understøtter kun version 1 dumpfiler. Fik dumpfil med version %s</translation>
+ </message>
+ <message>
+ <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
+ <translation type="unfinished">Fejl: Ældre tegnebøger understøtter kun adressetyperne "legacy", "p2sh-segwit" og "bech32"</translation>
</message>
<message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Estimering af gebyr mislykkedes. Tilbagefaldsgebyr er deaktiveret. Vent et par blokke eller aktiver -fallbackfee.</translation>
</message>
<message>
+ <source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
+ <translation type="unfinished">Fil %s eksisterer allerede. Hvis du er sikker på, at det er det, du vil have, så flyt det af vejen først.</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 type="unfinished">Ugyldigt beløb for -maxtxfee=&lt;beløb&gt;: “%s†(skal være på mindst minrelay-gebyret på %s for at undgå hængende transaktioner)</translation>
</message>
<message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">Ugyldige eller korrupte peers.dat (%s). Hvis du mener, at dette er en fejl, bedes du rapportere det til %s. Som en løsning kan du flytte filen (%s) ud af vejen (omdøbe, flytte eller slette) for at få oprettet en ny ved næste start.</translation>
+ </message>
+ <message>
<source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
<translation type="unfinished">Mere end én onion-bindingsadresse er opgivet. Bruger %s til den automatiske oprettelse af Tor-onion-tjeneste.</translation>
</message>
<message>
+ <source>No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">Der er ikke angivet nogen dumpfil. For at bruge createfromdump skal -dumpfile= &lt;filename&gt; angives.</translation>
+ </message>
+ <message>
+ <source>No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">Der er ikke angivet nogen dumpfil. For at bruge dump skal -dumpfile=&lt;filename&gt; angives.</translation>
+ </message>
+ <message>
+ <source>No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
+ <translation type="unfinished">Der er ikke angivet noget tegnebogsfilformat. For at bruge createfromdump skal -format=&lt;format&gt; angives.</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 type="unfinished">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>
@@ -425,6 +522,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Blokdatabasen indeholder en blok, som ser ud til at være fra fremtiden. Dette kan skyldes, at din computers dato og tid ikke er sat korrekt. Genopbyg kun blokdatabasen, hvis du er sikker på, at din computers dato og tid er korrekt</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">Blokindekset db indeholder et ældre 'txindex'. For at rydde den optagede diskplads skal du køre en fuld -reindex, ellers ignorere denne fejl. Denne fejlmeddelelse vil ikke blive vist igen.</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished">Transaktionsbeløbet er for lille til at sende, når gebyret er trukket fra</translation>
</message>
@@ -457,6 +558,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kan ikke genafspille blokke. Du er nødt til at genopbytte databasen ved hjælp af -reindex-chainstate.</translation>
</message>
<message>
+ <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source>
+ <translation type="unfinished">Ukendt tegnebogsfilformat "%s" angivet. Angiv en af "bdb" eller "sqlite".</translation>
+ </message>
+ <message>
+ <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
+ <translation type="unfinished">Advarsel: Dumpfile tegnebogsformatet "%s" matcher ikke kommandolinjens specificerede format "%s".</translation>
+ </message>
+ <message>
<source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
<translation type="unfinished">Advarsel: Private nøgler opdaget i tegnebog {%s} med deaktiverede private nøgler</translation>
</message>
@@ -465,6 +574,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Advarsel: Vi ser ikke ud til at være fuldt ud enige med andre knuder! Du kan være nødt til at opgradere, eller andre knuder kan være nødt til at opgradere.</translation>
</message>
<message>
+ <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
+ <translation type="unfinished">Vidnedata for blokke efter højde %d kræver validering. Genstart venligst med -reindex.</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 type="unfinished">Du er nødt til at genopbygge databasen ved hjælp af -reindex for at gå tilbage til ikke-beskåret tilstand. Dette vil downloade hele blokkæden igen</translation>
</message>
@@ -485,6 +598,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kan ikke finde -%s-adressen: “%sâ€</translation>
</message>
<message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">Kan ikke indstille -forcednsseed til true, når -dnsseed indstilles til false.</translation>
+ </message>
+ <message>
<source>Cannot set -peerblockfilters without -blockfilterindex.</source>
<translation type="unfinished">Kan ikke indstille -peerblockfilters uden -blockfilterindex.</translation>
</message>
@@ -493,6 +610,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kan ikke skrive til datamappe '%s'; tjek tilladelser.</translation>
</message>
<message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">Opgraderingen af -txindex som er startet af en tidligere version kan ikke fuldføres. Genstart med den tidligere version eller kør en fuld -reindex.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%sanmodning om st lytte på havn%uDenne port betragtes som „dårlig“, og det er derfor usandsynligt, at nogen Bitcoin Core-jævnaldrende opretter forbindelse til den. Se doc/p2p-bad-ports.md for detaljer og en komplet liste.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Kan ikke levere specifikke forbindelser og få adrman til at finde udgående forbindelser på samme tid.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Fejlindlæsning %s: Ekstern underskriver-tegnebog indlæses uden ekstern underskriverunderstøttelse kompileret</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Kunne ikke omdøbe ugyldig peers.dat fil. Flyt eller slet den venligst og prøv igen.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">Opsætningen af %s bliver kun udført på %s-netværk under [%s]-sektionen.</translation>
</message>
@@ -525,6 +662,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Indlæsning gennemført</translation>
</message>
<message>
+ <source>Dump file %s does not exist.</source>
+ <translation type="unfinished">Dumpfil %s findes ikke.</translation>
+ </message>
+ <message>
+ <source>Error creating %s</source>
+ <translation type="unfinished">Fejl skaber %s</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
<translation type="unfinished">Klargøring af blokdatabase mislykkedes</translation>
</message>
@@ -561,18 +706,50 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Fejl under læsning fra database; lukker ned.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Fejl under opgradering af kædetilstandsdatabase</translation>
+ <source>Error reading next record from wallet database</source>
+ <translation type="unfinished">Fejl ved læsning af næste post fra tegnebogsdatabase</translation>
+ </message>
+ <message>
+ <source>Error: Couldn't create cursor into database</source>
+ <translation type="unfinished">Fejl: Kunne ikke oprette markøren i databasen</translation>
</message>
<message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Fejl: Disk plads er lavt for %s</translation>
</message>
<message>
+ <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
+ <translation type="unfinished">Fejl: Dumpfil kontrolsum stemmer ikke overens. Beregnet %s, forventet %s</translation>
+ </message>
+ <message>
+ <source>Error: Got key that was not hex: %s</source>
+ <translation type="unfinished">Fejl: Fik nøgle, der ikke var hex: %s</translation>
+ </message>
+ <message>
+ <source>Error: Got value that was not hex: %s</source>
+ <translation type="unfinished">Fejl: Fik værdi, der ikke var hex: %s</translation>
+ </message>
+ <message>
<source>Error: Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished">Fejl: Nøglepøl løb tør, tilkald venligst keypoolrefill først</translation>
</message>
<message>
+ <source>Error: Missing checksum</source>
+ <translation type="unfinished">Fejl: Manglende kontrolsum</translation>
+ </message>
+ <message>
+ <source>Error: No %s addresses available.</source>
+ <translation type="unfinished">Fejl: Ingen tilgængelige %s adresser.</translation>
+ </message>
+ <message>
+ <source>Error: Unable to parse version %u as a uint32_t</source>
+ <translation type="unfinished">Fejl: Kan ikke parse version %u som en uint32_t</translation>
+ </message>
+ <message>
+ <source>Error: Unable to write record to new wallet</source>
+ <translation type="unfinished">Fejl: Kan ikke skrive post til ny tegnebog</translation>
+ </message>
+ <message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation type="unfinished">Lytning på enhver port mislykkedes. Brug -listen=0, hvis du ønsker dette.</translation>
</message>
@@ -605,10 +782,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Sundhedstjek under initialisering mislykkedes. %s lukker ned.</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Input ikke fundet eller allerede brugt</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">Manglende dækning</translation>
</message>
<message>
+ <source>Invalid -i2psam address or hostname: '%s'</source>
+ <translation type="unfinished">Ugyldig -i2psam-adresse eller værtsnavn: '%s'</translation>
+ </message>
+ <message>
<source>Invalid -onion address or hostname: '%s'</source>
<translation type="unfinished">Ugyldig -onion-adresse eller værtsnavn: “%sâ€</translation>
</message>
@@ -657,12 +842,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Indlæser tegnebog...</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Manglende beløb</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">Manglende løsningsdata til estimering af transaktionsstørrelse</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">Nødt til at angive en port med -whitebinde: “%sâ€</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Ingen proxyserver specificeret. Brug -proxy=&lt;ip&gt; eller -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Ingen adresser tilgængelige</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -685,6 +878,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Reducerer -maxconnections fra %d til %d på grund af systembegrænsninger.</translation>
</message>
<message>
+ <source>Replaying blocks…</source>
+ <translation type="unfinished">Genafspiller blokke...</translation>
+ </message>
+ <message>
<source>Rescanning…</source>
<translation type="unfinished">Genindlæser…</translation>
</message>
@@ -729,10 +926,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Angivet blokmappe “%s†eksisterer ikke.</translation>
</message>
<message>
+ <source>Starting network threads…</source>
+ <translation type="unfinished">Starter netværkstråde...</translation>
+ </message>
+ <message>
<source>The source code is available from %s.</source>
<translation type="unfinished">Kildekoden er tilgængelig fra %s.</translation>
</message>
<message>
+ <source>The specified config file %s does not exist</source>
+ <translation type="unfinished">Den angivne konfigurationsfil %s findes ikke</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to pay the fee</source>
<translation type="unfinished">Transaktionsbeløbet er for lille til at betale gebyret</translation>
</message>
@@ -761,6 +966,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transaktionsbeløb må ikke være negative</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">Transaktions byttepenge outputindeks uden for intervallet</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">Transaktionen har en for lang hukommelsespuljekæde</translation>
</message>
@@ -769,6 +978,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transaktionen skal have mindst én modtager</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">Transaktionen behøver en byttepenge adresse, men vi kan ikke generere den.</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">Transaktionen er for stor</translation>
</message>
@@ -793,6 +1006,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">U-istand til at generere nøgler</translation>
</message>
<message>
+ <source>Unable to open %s for writing</source>
+ <translation type="unfinished">Kan ikke åbne %s til skrivning</translation>
+ </message>
+ <message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">Kan ikke parse -maxuploadtarget: '%s'</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">Kunne ikke starte HTTP-server. Se fejlretningslog for detaljer.</translation>
</message>
@@ -813,18 +1034,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ukendt netværk anført i -onlynet: “%sâ€</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">Ikke understøttet logningskategori %s=%s.</translation>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished">Ukendte nye regler aktiveret (versionsbit %i)</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Opgraderer UTXO-database</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Ikke understøttet logningskategori %s=%s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Brugeragent-kommentar (%s) indeholder usikre tegn.</translation>
</message>
<message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">Verificerer blokke…</translation>
+ </message>
+ <message>
<source>Verifying wallet(s)…</source>
<translation type="unfinished">Bekræfter tegnebog (/bøger)...</translation>
</message>
@@ -884,6 +1109,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Opret en ny tegnebog</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimér</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Tegnebog:</translation>
</message>
@@ -929,6 +1158,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Sikkerhedskopiér Tegnebog</translation>
</message>
<message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;Skift adgangskode</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">Signér &amp;besked</translation>
+ </message>
+ <message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
<translation type="unfinished">Signér beskeder med dine Bitcoin-adresser for at bevise, at de tilhører dig</translation>
</message>
@@ -941,6 +1178,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Verificér beskeder for at sikre, at de er signeret med de angivne Bitcoin-adresser</translation>
</message>
<message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;Indlæs PSBT fra fil...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">Ã…ben &amp;URI...</translation>
+ </message>
+ <message>
<source>Close Wallet…</source>
<translation type="unfinished">Luk Tegnebog...</translation>
</message>
@@ -969,10 +1214,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Faneværktøjslinje</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Synkroniserer hoveder (%1%)…</translation>
+ </message>
+ <message>
<source>Synchronizing with network…</source>
<translation type="unfinished">Synkroniserer med netværk …</translation>
</message>
<message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Indekserer blokke på disken…</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Bearbejder blokke på disken…</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Genindekserer blokke på disken…</translation>
+ </message>
+ <message>
<source>Connecting to peers…</source>
<translation type="unfinished">Forbinder til knuder...</translation>
</message>
@@ -995,8 +1256,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Behandlede %n blok(e) af transaktionshistorik.</numerusform>
+ <numerusform>Behandlede %n blok(e) af transaktionshistorik.</numerusform>
</translation>
</message>
<message>
@@ -1032,6 +1293,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Indlæs Partvist Signeret Bitcoin-Transaktion</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">Indlæs PSBT fra &amp;clipboard</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">Indlæs Partvist Signeret Bitcoin-Transaktion fra udklipsholder</translation>
</message>
@@ -1068,6 +1333,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Luk tegnebog</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Gendan pung</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Gendan en pung, fra en backup fil. </translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Luk alle tegnebøgerne </translation>
</message>
@@ -1092,6 +1367,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ingen tegnebøger tilgængelige</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Tegnebogsdata</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Navn på tegnebog</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Vindue</translation>
</message>
@@ -1103,15 +1388,28 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1-klient</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Skjul</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">&amp;Vis</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n aktiv(e) forbindelse(r) til Bitcoin-netværket.</numerusform>
+ <numerusform>%n aktiv(e) forbindelse(r) til Bitcoin-netværket.</numerusform>
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Click for flere aktioner.</translation>
+ </message>
+ <message>
<source>Show Peers tab</source>
<extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
<translation type="unfinished">Vis værktøjslinjeknuder</translation>
@@ -1279,6 +1577,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kopiér beløb</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopiér adresse</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiér &amp;mærkat</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopiér &amp;beløb</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Kopiér transaktion &amp;ID og outputindeks</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">&amp;Fastlås ubrugte</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;LÃ¥s ubrugte op</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Kopiér mængde</translation>
</message>
@@ -1355,8 +1677,25 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Create wallet warning</source>
<translation type="unfinished">Advarsel for oprettelse af tegnebog</translation>
</message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Kan ikke liste underskrivere</translation>
+ </message>
</context>
<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">Indlæs Tegnebøger</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">Indlæser tegnebøger...</translation>
+ </message>
+</context>
+<context>
<name>OpenWalletActivity</name>
<message>
<source>Open wallet failed</source>
@@ -1375,7 +1714,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">Ã…ben Tegnebog</translation>
</message>
- </context>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">Ã…bner Tegnebog &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
<context>
<name>WalletController</name>
<message>
@@ -1450,6 +1794,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Beskriver-Pung</translation>
</message>
<message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Brug en ekstern signeringsenhed som en hardwaretegnebog. Konfigurer den eksterne underskriver skript i tegnebogspræferencerne først.</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">Ekstern underskriver</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">Opret</translation>
</message>
@@ -1457,7 +1809,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Compiled without sqlite support (required for descriptor wallets)</source>
<translation type="unfinished">Kompileret uden sqlite-understøttelse (krævet til beskriver-punge)</translation>
</message>
- </context>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Kompileret uden ekstern underskriver understøttelse (nødvendig for ekstern underskriver)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -1538,6 +1895,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(ud af %n GB nødvendig)</numerusform>
+ <numerusform>(ud af %n GB nødvendig)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB nødvendig for komplet kæde)</numerusform>
+ <numerusform>(%n GB nødvendig for komplet kæde)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Mindst %1 GB data vil blive gemt i denne mappe, og det vil vokse over tid.</translation>
@@ -1550,8 +1928,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(tilstrækkelig for at gendanne backups %n dag(e) gammel)</numerusform>
+ <numerusform>(tilstrækkelig for at gendanne backups %n dag(e) gammel)</numerusform>
</translation>
</message>
<message>
@@ -1583,14 +1961,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Siden dette er første gang, programmet startes, kan du vælge, hvor %1 skal gemme sin data.</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 type="unfinished">Når du klikker OK, vil %1 begynde at downloade og bearbejde den fulde %4-blokkæde (%2 GB), startende med de tidligste transaktioner i %3, da %4 først startede.</translation>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">Begræns blokkæde opbevaring til</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">Ændring af denne indstilling senere kræver gendownload af hele blokkæden. Det er hurtigere at downloade den komplette kæde først og beskære den senere. Slår nogle avancerede funktioner fra.</translation>
</message>
<message>
+ <source> GB</source>
+ <translation type="unfinished">GB</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 type="unfinished">Denne indledningsvise synkronisering er meget krævende, og den kan potentielt afsløre hardwareproblemer med din computer, som du ellers ikke har lagt mærke til. Hver gang, du kører %1, vil den fortsætte med at downloade, hvor den sidst slap.</translation>
</message>
@@ -1621,6 +2003,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 lukker ned…</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation type="unfinished">Luk ikke computeren ned, før dette vindue forsvinder.</translation>
</message>
@@ -1675,6 +2061,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
<translation type="unfinished">%1 synkroniserer lige nu. Hoveder og blokke bliver downloadet og valideret fra andre knuder. Processen fortsætter indtil den seneste blok nås.</translation>
</message>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Ukendt. Synkroniserer Hoveder (%1, %2%)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -1707,6 +2097,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Start %1 ved systemlogin</translation>
</message>
<message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Aktivering af beskæring reducerer betydeligt den diskplads, der kræves til at gemme transaktioner. Alle blokke er stadig fuldt validerede. Gendannelse af denne indstilling kræver gendownload af hele blokkæden.</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation type="unfinished">Størrelsen på &amp;databasens cache</translation>
</message>
@@ -1755,14 +2149,44 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ændring af denne indstilling senere kræver download af hele blokkæden igen.</translation>
</message>
<message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">Maksimal størrelse på databasecache. En større cache kan bidrage til hurtigere synkronisering, hvorefter fordelen er mindre synlig i de fleste tilfælde. Sænkning af cachestørrelsen vil reducere hukommelsesforbruget. Ubrugt mempool-hukommelse deles for denne cache.</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Indstil antallet af scriptbekræftelsestråde. Negative værdier svarer til antallet af kerner, du ønsker at lade være frie til systemet.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = auto, &lt;0 = efterlad så mange kerner fri)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Dette giver dig eller et tredjepartsværktøj mulighed for at kommunikere med knuden gennem kommandolinje- og JSON-RPC-kommandoer.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Aktiver &amp;RPC-server</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">&amp;Tegnebog</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Hvorvidt der skal trækkes gebyr fra beløb som standard eller ej.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Træk &amp;gebyr fra beløbet som standard</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">Ekspert</translation>
</message>
@@ -1779,6 +2203,28 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Brug ubekræftede byttepenge</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Aktiver &amp;PSBT styring</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Om PSBT styring skal vises.</translation>
+ </message>
+ <message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">Ekstern underskriver (f.eks. hardwaretegnebog)</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;Ekstern underskrivers scriptsti</translation>
+ </message>
+ <message>
+ <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished">Fuld sti til et Bitcoin Core-kompatibelt script (f.eks. C:\Downloads\hwi.exe eller /Users/you/Downloads/hwi.py). Pas på: malware kan stjæle dine mønter!</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 type="unfinished">Åbn automatisk Bitcoin-klientens port på routeren. Dette virker kun, når din router understøtter UPnP, og UPnP er aktiveret.</translation>
</message>
@@ -1787,6 +2233,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Konfigurér port vha. &amp;UPnP</translation>
</message>
<message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
+ <translation type="unfinished">Åbn automatisk Bitcoin-klientporten på routeren. Dette virker kun, når din router understøtter NAT-PMP, og den er aktiveret. Den eksterne port kan være tilfældig.</translation>
+ </message>
+ <message>
+ <source>Map port using NA&amp;T-PMP</source>
+ <translation type="unfinished">Kortport ved hjælp af NA&amp;T-PMP</translation>
+ </message>
+ <message>
<source>Accept connections from outside.</source>
<translation type="unfinished">Acceptér forbindelser udefra.</translation>
</message>
@@ -1819,6 +2273,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Vindue</translation>
</message>
<message>
+ <source>Show the icon in the system tray.</source>
+ <translation type="unfinished">Vis ikonet i proceslinjen.</translation>
+ </message>
+ <message>
+ <source>&amp;Show tray icon</source>
+ <translation type="unfinished">&amp;Vis bakkeikon</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation type="unfinished">Vis kun et statusikon efter minimering af vinduet.</translation>
</message>
@@ -1851,6 +2313,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Vælg standard for underopdeling af enhed, som skal vises i brugergrænsefladen og ved afsendelse af bitcoins.</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 type="unfinished">Tredjeparts-URL'er (f.eks. en blokudforsker), der vises på fanen Transaktioner som genvejsmenupunkter. %s i URL'en erstattes af transaktions-hash. Flere URL'er er adskilt af lodret streg |.</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;Tredjeparts transaktions-URL'er</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">Hvorvidt egenskaber for coin-styring skal vises eller ej.</translation>
</message>
@@ -1863,8 +2333,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Brug separate SOCKS&amp;5 proxy, for at nå fælle via Tor-onion-tjenester:</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Valgmuligheder sat i denne dialog er overskrevet af kommandolinjen eller i konfigurationsfilen:</translation>
+ <source>Monospaced font in the Overview tab:</source>
+ <translation type="unfinished">Monospaced skrifttype på fanen Oversigt:</translation>
+ </message>
+ <message>
+ <source>embedded "%1"</source>
+ <translation type="unfinished">indlejret "%1"</translation>
+ </message>
+ <message>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">tættest matchende "%1"</translation>
</message>
<message>
<source>&amp;OK</source>
@@ -1875,6 +2353,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Annullér</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Kompileret uden ekstern underskriver understøttelse (nødvendig for ekstern underskriver)</translation>
+ </message>
+ <message>
<source>default</source>
<translation type="unfinished">standard</translation>
</message>
@@ -1884,14 +2367,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Bekræft nulstilling af indstillinger</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Genstart af klienten er nødvendig for at aktivere ændringer.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Klienten vil lukke ned. Vil du fortsætte?</translation>
</message>
<message>
@@ -1905,6 +2391,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Konfigurationsfilen bruges til at opsætte avancerede brugerindstillinger, som tilsidesætter indstillingerne i den grafiske brugerflade. Derudover vil eventuelle kommandolinjetilvalg tilsidesætte denne konfigurationsfil.</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">Forsæt</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">Fortryd</translation>
</message>
@@ -2031,6 +2521,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kunne ikke signere transaktion: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">Kan ikke signere inputs, mens tegnebogen er låst.</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">Kunne ikke signere flere input.</translation>
</message>
@@ -2063,6 +2557,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Gem Transaktionsdata</translation>
</message>
<message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">Delvist underskrevet transaktion (Binær)</translation>
+ </message>
+ <message>
<source>PSBT saved to disk.</source>
<translation type="unfinished">PSBT gemt på disk.</translation>
</message>
@@ -2099,6 +2598,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transaktion mangler stadig signatur(er).</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Men ingen tegnebog er indlæst.)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Men denne tegnebog kan ikke signere transaktioner.)</translation>
</message>
@@ -2134,6 +2637,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">'bitcoin://' er ikke et gyldigt URI. Brug 'bitcoin:' istedet.</translation>
</message>
<message>
+ <source>Cannot process payment request because BIP70 is not supported.
+Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
+If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
+ <translation type="unfinished">Kan ikke behandle betalingsanmodning, fordi BIP70 ikke understøttes.
+På grund af udbredte sikkerhedsfejl i BIP70 anbefales det på det kraftigste, at enhver købmands instruktioner om at skifte tegnebog ignoreres.
+Hvis du modtager denne fejl, skal du anmode forhandleren om en BIP21-kompatibel URI.</translation>
+ </message>
+ <message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<translation type="unfinished">URI kan ikke tolkes! Dette kan skyldes en ugyldig Bitcoin-adresse eller forkert udformede URL-parametre.</translation>
</message>
@@ -2325,6 +2836,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Synkroniserede blokke</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Sidste transaktion</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">Afbildning fra Autonome Systemer (et Internet-Protocol-rutefindingsprefiks) til IP-adresser som bruges til at diversificere knudeforbindelser. Den engelske betegnelse er "asmap".</translation>
</message>
@@ -2333,6 +2848,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Autonomt-System-afbildning</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Om vi videresender adresser til denne peer.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Adresserelæ</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Adresser Behandlet</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Adresser Hastighedsbegrænset</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">Brugeragent</translation>
</message>
@@ -2361,18 +2896,55 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tilladelser</translation>
</message>
<message>
+ <source>The direction and type of peer connection: %1</source>
+ <translation type="unfinished">Retningen og typen af peer-forbindelse: %1</translation>
+ </message>
+ <message>
+ <source>Direction/Type</source>
+ <translation type="unfinished">Retning/Type</translation>
+ </message>
+ <message>
+ <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
+ <translation type="unfinished">Netværksprotokollen, som denne peer er forbundet via: IPv4, IPv6, Onion, I2P eller CJDNS.</translation>
+ </message>
+ <message>
<source>Services</source>
<translation type="unfinished">Tjenester</translation>
</message>
<message>
+ <source>Whether the peer requested us to relay transactions.</source>
+ <translation type="unfinished">Om peeren anmodede os om at videresende transaktioner.</translation>
+ </message>
+ <message>
+ <source>Wants Tx Relay</source>
+ <translation type="unfinished">Vil have transaktion videresend</translation>
+ </message>
+ <message>
+ <source>High bandwidth BIP152 compact block relay: %1</source>
+ <translation type="unfinished">BIP152 kompakt blokrelæ med høj bredbånd: %1</translation>
+ </message>
+ <message>
+ <source>High Bandwidth</source>
+ <translation type="unfinished">Højt Bredbånd</translation>
+ </message>
+ <message>
<source>Connection Time</source>
<translation type="unfinished">Forbindelsestid</translation>
</message>
<message>
+ <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
+ <translation type="unfinished">Forløbet tid siden en ny blok, der bestod indledende gyldighedstjek, blev modtaget fra denne peer.</translation>
+ </message>
+ <message>
<source>Last Block</source>
<translation type="unfinished">Sidste Blok</translation>
</message>
<message>
+ <source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
+ <extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
+ <translation type="unfinished">Forløbet tid siden en ny transaktion, der blev accepteret i vores mempool, blev modtaget fra denne peer.</translation>
+ </message>
+ <message>
<source>Last Send</source>
<translation type="unfinished">Seneste afsendelse</translation>
</message>
@@ -2437,6 +3009,53 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Udgående:</translation>
</message>
<message>
+ <source>Inbound: initiated by peer</source>
+ <extracomment>Explanatory text for an inbound peer connection.</extracomment>
+ <translation type="unfinished">Indgående: initieret af peer</translation>
+ </message>
+ <message>
+ <source>Outbound Full Relay: default</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment>
+ <translation type="unfinished">Udgående fuld relæ: standard</translation>
+ </message>
+ <message>
+ <source>Outbound Block Relay: does not relay transactions or addresses</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Udgående blokrelæ: videresender ikke transaktioner eller adresser</translation>
+ </message>
+ <message>
+ <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
+ <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment>
+ <translation type="unfinished">Udgående manual: tilføjet ved hjælp af RPC %1 eller %2/%3 konfigurationsmuligheder</translation>
+ </message>
+ <message>
+ <source>Outbound Feeler: short-lived, for testing addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Udgående fejl: kortvarig, til test af adresser</translation>
+ </message>
+ <message>
+ <source>Outbound Address Fetch: short-lived, for soliciting addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment>
+ <translation type="unfinished">Udgående adressehentning: kortvarig, til at anmode om adresser</translation>
+ </message>
+ <message>
+ <source>we selected the peer for high bandwidth relay</source>
+ <translation type="unfinished">vi valgte denne peer for høj bredbånd relæ</translation>
+ </message>
+ <message>
+ <source>the peer selected us for high bandwidth relay</source>
+ <translation type="unfinished">peeren valgte os til høj bredbånd relæ</translation>
+ </message>
+ <message>
+ <source>no high bandwidth relay selected</source>
+ <translation type="unfinished">ingen høj bredbånd relæ valgt</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Kopiér adresse</translation>
+ </message>
+ <message>
<source>&amp;Disconnect</source>
<translation type="unfinished">&amp;Afbryd forbindelse</translation>
</message>
@@ -2445,6 +3064,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">1 &amp;time</translation>
</message>
<message>
+ <source>1 d&amp;ay</source>
+ <translation type="unfinished">1 &amp;dag</translation>
+ </message>
+ <message>
<source>1 &amp;week</source>
<translation type="unfinished">1 &amp;uge</translation>
</message>
@@ -2453,6 +3076,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">1 &amp;Ã¥r</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Kopiér IP/Netmask</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Fjern bandlysning</translation>
</message>
@@ -2469,6 +3097,28 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Eksekverer kommando ved brug af "%1" tegnebog</translation>
</message>
<message>
+ <source>Welcome to the %1 RPC console.
+Use up and down arrows to navigate history, and %2 to clear screen.
+Use %3 and %4 to increase or decrease the font size.
+Type %5 for an overview of available commands.
+For more information on using this console, type %6.
+
+%7WARNING: 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.%8</source>
+ <extracomment>RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</extracomment>
+ <translation type="unfinished">Velkommen til %1 RPC-konsollen.
+Brug op- og nedpilene til at navigere i historikken og %2 til at rydde skærmen.
+Brug %3 og %4 til at øge eller formindske skriftstørrelsen.
+Skriv %5 for at få en oversigt over tilgængelige kommandoer.
+For mere information om brug af denne konsol, skriv %6.
+
+%7 ADVARSEL: Svindlere har været aktive og bedt brugerne om at skrive kommandoer her og stjæle deres tegnebogsindhold. Brug ikke denne konsol uden fuldt ud at forstå konsekvenserne af en kommando.%8</translation>
+ </message>
+ <message>
+ <source>Executing…</source>
+ <extracomment>A console message indicating an entered command is currently being executed.</extracomment>
+ <translation type="unfinished">Udfører...</translation>
+ </message>
+ <message>
<source>Yes</source>
<translation type="unfinished">Ja</translation>
</message>
@@ -2572,6 +3222,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kopiér &amp;URI</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopiér adresse</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiér &amp;mærkat</translation>
+ </message>
+ <message>
+ <source>Copy &amp;message</source>
+ <translation type="unfinished">Kopiér &amp;besked</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopiér &amp;beløb</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">Kunne ikke låse tegnebog op.</translation>
</message>
@@ -2615,6 +3281,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kopiér &amp;adresse</translation>
</message>
<message>
+ <source>&amp;Verify</source>
+ <translation type="unfinished">&amp;Bekræft</translation>
+ </message>
+ <message>
+ <source>Verify this address on e.g. a hardware wallet screen</source>
+ <translation type="unfinished">Bekræft denne adresse på f.eks. en hardwaretegnebogs skærm</translation>
+ </message>
+ <message>
<source>&amp;Save Image…</source>
<translation type="unfinished">&amp;Gem billede...</translation>
</message>
@@ -2765,6 +3439,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Skjul indstillinger for transaktionsgebyr</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 rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation type="unfinished">Angiv et brugerdefineret gebyr pr. kB (1.000 bytes) af transaktionens virtuelle størrelse.
+
+Bemærk: Da gebyret beregnes på per-byte-basis, ville en gebyrsats på "100 satoshis pr. kvB" for en transaktionsstørrelse på 500 virtuelle bytes (halvdelen af 1 kvB) i sidste ende kun give et gebyr på 50 satoshis.</translation>
+ </message>
+ <message>
<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">På tidspunkter, hvor der er færre transaktioner, end der er plads til i nye blokke, kan minere og videresendende knuder gennemtvinge et minimumsgebyr. Du kan vælge kun at betale dette minimumsgebyr, men vær opmærksom på, at det kan resultere i en transaktion, der aldrig bliver bekræftet, hvis mængden af nye bitcoin-transaktioner stiger til mere, end hvad netværket kan behandle ad gangen.</translation>
</message>
@@ -2773,6 +3455,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Et for lavt gebyr kan resultere i en transaktion, der aldrig bekræftes (læs værktøjstippet)</translation>
</message>
<message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source>
+ <translation type="unfinished">(Smart gebyr er ikke initialiseret endnu. Dette tager normalt et par blokke...)</translation>
+ </message>
+ <message>
<source>Confirmation time target:</source>
<translation type="unfinished">Mål for bekræftelsestid:</translation>
</message>
@@ -2833,6 +3519,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1 (%2 blokke)</translation>
</message>
<message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">Underskriv på enhed</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">Tilslut din hardwaretegnebog først.</translation>
+ </message>
+ <message>
+ <source>Set external signer script path in Options -&gt; Wallet</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Indstil ekstern underskriver scriptsti i Indstillinger -&gt; Tegnebog</translation>
+ </message>
+ <message>
<source>Cr&amp;eate Unsigned</source>
<translation type="unfinished">L&amp;av usigneret</translation>
</message>
@@ -2849,14 +3549,41 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1 til %2</translation>
</message>
<message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">For at vurdere modtager listen tryk "Vis Detaljer..."</translation>
+ </message>
+ <message>
+ <source>Sign failed</source>
+ <translation type="unfinished">Underskrivningen fejlede</translation>
+ </message>
+ <message>
+ <source>External signer not found</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Ekstern underskriver ikke fundet</translation>
+ </message>
+ <message>
+ <source>External signer failure</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Ekstern underskriver fejl</translation>
+ </message>
+ <message>
<source>Save Transaction Data</source>
<translation type="unfinished">Gem Transaktionsdata</translation>
</message>
<message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">Delvist underskrevet transaktion (Binær)</translation>
+ </message>
+ <message>
<source>PSBT saved</source>
<translation type="unfinished">PSBT gemt</translation>
</message>
<message>
+ <source>External balance:</source>
+ <translation type="unfinished">Ekstern balance:</translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">eller</translation>
</message>
@@ -2870,6 +3597,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Gennemse venligst dit transaktionsforslag. Dette vil producere en Partvist Signeret Bitcoin Transaktion (PSBT), som du kan gemme eller kopiere, og så signere med f.eks. en offline %1 pung, eller en PSBT-kompatibel maskinelpung.</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Vil du oprette denne transaktion?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Gennemgå venligst din transaktion. Du kan oprette og sende denne transaktion eller oprette en delvist underskrevet Bitcoin-transaktion (PSBT), som du kan gemme eller kopiere og derefter underskrive med, f.eks. en offline %1 tegnebog eller en PSBT-kompatibel hardwaretegnebog.</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Venligst, vurder din transaktion.</translation>
@@ -2922,15 +3659,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Et gebyr højere end %1 opfattes som et absurd højt gebyr.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Betalingsanmodning er udløbet.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Anslået at begynde bekræftelse inden for %n blok(e).</numerusform>
+ <numerusform>Anslået at begynde bekræftelse inden for %n blok(e).</numerusform>
</translation>
</message>
<message>
@@ -3005,14 +3738,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Besked:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Dette er en uautentificeret betalingsanmodning.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Dette er en autentificeret betalingsanmodning.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Indtast et mærkat for denne adresse for at føje den til listen over brugte adresser</translation>
</message>
@@ -3020,11 +3745,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<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 type="unfinished">En besked, som blev føjet til “bitcoin:â€-URI'en, som vil gemmes med transaktionen til din reference. Bemærk: Denne besked vil ikke blive sendt over Bitcoin-netværket.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Betal til:</translation>
- </message>
- </context>
+</context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -3185,35 +3906,31 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(press q to shutdown and continue later)</source>
<translation type="unfinished">(tast q for at lukke ned og fortsætte senere)</translation>
</message>
- </context>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">tryk på q for at lukke</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">i konflikt med en transaktion, der har %1 bekræftelser</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/ubekræftet, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">i hukommelsespulje</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">ikke i hukommelsespulje</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">opgivet</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/ubekræftet</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 bekræftelser</translation>
</message>
<message>
@@ -3259,8 +3976,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>modnes i yderligere %n blok(e)</numerusform>
+ <numerusform>modnes i yderligere %n blok(e)</numerusform>
</translation>
</message>
<message>
@@ -3509,6 +4226,51 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Interval...</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopiér adresse</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiér &amp;mærkat</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopiér &amp;beløb</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">Kopiér transaktion &amp;ID</translation>
+ </message>
+ <message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">Kopiér &amp;rå transaktion</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">Kopiér alle transaktion &amp;oplysninger </translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">&amp;Vis transaktionsoplysninger</translation>
+ </message>
+ <message>
+ <source>Increase transaction &amp;fee</source>
+ <translation type="unfinished">Hæv transaktions &amp;gebyr</translation>
+ </message>
+ <message>
+ <source>A&amp;bandon transaction</source>
+ <translation type="unfinished">&amp;Opgiv transaction</translation>
+ </message>
+ <message>
+ <source>&amp;Edit address label</source>
+ <translation type="unfinished">&amp;Rediger adresseetiket</translation>
+ </message>
+ <message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Vis på %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Eksportér transaktionshistorik</translation>
</message>
@@ -3633,6 +4395,10 @@ Gå til Fil &gt; Åbn Pung for, at indlæse en pung.
<translation type="unfinished">Nyt gebyr:</translation>
</message>
<message>
+ <source>Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
+ <translation type="unfinished">Advarsel: Dette kan betale det ekstra gebyr ved at reducere byttepengesoutputs eller tilføje inputs, når det er nødvendigt. Det kan tilføje et nyt byttepengesoutput, hvis et ikke allerede eksisterer. Disse ændringer kan potentielt lække privatlivets fred.</translation>
+ </message>
+ <message>
<source>Confirm fee bump</source>
<translation type="unfinished">Bekræft gebyrforøgelse</translation>
</message>
@@ -3653,6 +4419,10 @@ Gå til Fil &gt; Åbn Pung for, at indlæse en pung.
<translation type="unfinished">Kunne ikke gennemføre transaktionen</translation>
</message>
<message>
+ <source>Can't display address</source>
+ <translation type="unfinished">Adressen kan ikke vises</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">Standard tegnebog</translation>
</message>
diff --git a/src/qt/locale/bitcoin_el.ts b/src/qt/locale/bitcoin_el.ts
index b581c8baca..fc068ea1b6 100644
--- a/src/qt/locale/bitcoin_el.ts
+++ b/src/qt/locale/bitcoin_el.ts
@@ -242,6 +242,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Το αÏχείο Ρυθμίσεων %1 ενδέχεται να είναι κατεστÏαμμένο ή μη έγκυÏο.</translation>
+ </message>
+ <message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
<translation type="unfinished">Συνέβη ενα μοιÏαίο σφάλμα. %1 δε μποÏεί να συνεχιστεί με ασφάλεια και θα σταματήσει</translation>
</message>
@@ -328,6 +332,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ΧειÏοκίνητα</translation>
</message>
<message>
+ <source>Address Fetch</source>
+ <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
+ <translation type="unfinished">Λήψη ΔιεÏθυνσης</translation>
+ </message>
+ <message>
<source>None</source>
<translation type="unfinished">Κανένα</translation>
</message>
@@ -429,10 +438,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Σφάλμα: Η έκδοση του αÏχείου dump δεν υποστηÏίζεται. Αυτή η έκδοση του bitcoin-wallet υποστηÏίζει αÏχεία dump μόνο της έκδοσης 1. Δόθηκε αÏχείο dump έκδοσης %s.</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Σφάλμα: Η ακÏόαση για εισεÏχόμενες συνδέσεις απέτυχε (ακοÏστε επιστÏαμμένο σφάλμα %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Η αποτίμηση του τέλους απέτυχε. Το Fallbackfee είναι απενεÏγοποιημένο. ΠεÏιμένετε λίγα τετÏάγωνα ή ενεÏγοποιήστε το -fallbackfee.</translation>
</message>
@@ -473,6 +478,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Κλάδεμα: ο τελευταίος συγχÏονισμός ποÏÏ„Î¿Ï†Î¿Î»Î¹Î¿Ï Î¾ÎµÏ€ÎµÏνά τα κλαδεμένα δεδομένα. ΠÏέπει να κάνετε -reindex (κατεβάστε ολόκληÏο το blockchain και πάλι σε πεÏίπτωση κλαδέματος κόμβου)</translation>
</message>
<message>
+ <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
+ <translation type="unfinished">SQLiteDatabase: Άγνωστη sqlite έκδοση %d του schema ποÏÏ„Î¿Ï†Î¿Î»Î¹Î¿Ï . ΥποστηÏίζεται μόνο η έκδοση %d.</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 type="unfinished">Η βάση δεδομένων μπλοκ πεÏιέχει ένα μπλοκ που φαίνεται να είναι από το μέλλον. Αυτό μποÏεί να οφείλεται στην εσφαλμένη ÏÏθμιση της ημεÏομηνίας και της ÏŽÏας του υπολογιστή σας. Αποκαταστήστε μόνο τη βάση δεδομένων μπλοκ αν είστε βέβαιοι ότι η ημεÏομηνία και η ÏŽÏα του υπολογιστή σας είναι σωστές</translation>
</message>
@@ -601,10 +610,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Σφάλμα ανάγνωσης από τη βάση δεδομένων, εκτελείται τεÏματισμός.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Σφάλμα κατά την αναβάθμιση της βάσης δεδομένων chainstate</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Σφάλμα: Ο χώÏος στο δίσκο είναι χαμηλός για %s</translation>
</message>
@@ -705,8 +710,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ΠÏέπει να καθοÏίσετε μια θÏÏα με -whitebind: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Δεν οÏίστηκε διακομιστής μεσολάβησης. ΧÏησιμοποιήστε -proxy=&lt;ip&gt; ή -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Καμμία διαθέσιμη διεÏθυνση</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -729,6 +734,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ΣάÏωση εκ νέου...</translation>
</message>
<message>
+ <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source>
+ <translation type="unfinished">SQLite βάση δεδομένων: Απέτυχε η εκτέλεση της δήλωσης για την επαλήθευση της βάσης δεδομένων: %s</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source>
+ <translation type="unfinished">SQLite βάση δεδομένων: Απέτυχε η Ï€Ïοετοιμασία της δήλωσης για την επαλήθευση της βάσης δεδομένων: %s</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Failed to read database verification error: %s</source>
+ <translation type="unfinished">SQLite βάση δεδομένων: Απέτυχε η ανάγνωση της επαλήθευσης του σφάλματος της βάσης δεδομένων: %s</translation>
+ </message>
+ <message>
<source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source>
<translation type="unfinished">SQLiteDatabase: Μη αναμενόμενο αναγνωÏιστικό εφαÏμογής. Αναμενόταν: %u, ελήφθη: %u</translation>
</message>
@@ -757,6 +774,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Δεν υπάÏχει κατάλογος καθοÏισμένων μπλοκ "%s".</translation>
</message>
<message>
+ <source>Starting network threads…</source>
+ <translation type="unfinished">Εκκίνηση των threads δικτÏου...</translation>
+ </message>
+ <message>
<source>The source code is available from %s.</source>
<translation type="unfinished"> Ο πηγαίος κώδικας είναι διαθέσιμος από το %s.</translation>
</message>
@@ -845,18 +866,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Έχει οÏιστεί άγνωστo δίκτυο στο -onlynet: '%s'</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">Μη υποστηÏιζόμενη κατηγοÏία καταγÏαφής %s=%s.</translation>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished">ΕνεÏγοποιήθηκαν άγνωστοι νέοι κανόνες (bit έκδοσης %i)</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Αναβάθμιση της βάσης δεδομένων UTXO</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Μη υποστηÏιζόμενη κατηγοÏία καταγÏαφής %s=%s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Το σχόλιο του παÏάγοντα χÏήστη (%s) πεÏιέχει μη ασφαλείς χαÏακτήÏες.</translation>
</message>
<message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">Επαλήθευση των blocks…</translation>
+ </message>
+ <message>
<source>Verifying wallet(s)…</source>
<translation type="unfinished">Επαλήθευση ποÏτοφολιοÏ/ιών...</translation>
</message>
@@ -986,7 +1011,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation type="unfinished">Ελέγξτε τα μηνÏματα για να βεβαιωθείτε ότι υπογÏάφηκαν με τις καθοÏισμένες διευθÏνσεις Bitcoin</translation>
+ <translation type="unfinished">ΥπογÏάψτε ένα μήνυμα για ν' αποδείξετε πως ανήκει μια συγκεκÏιμένη διεÏθυνση Bitcoin</translation>
</message>
<message>
<source>&amp;Load PSBT from file…</source>
@@ -1067,8 +1092,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>ΕπεξεÏγάστηκε %n των μπλοκ του ιστοÏÎ¹ÎºÎ¿Ï ÏƒÏ…Î½Î±Î»Î»Î±Î³ÏŽÎ½.</numerusform>
+ <numerusform>ΕπεξεÏγάσθηκαν %n μπλοκ του ιστοÏÎ¹ÎºÎ¿Ï ÏƒÏ…Î½Î±Î»Î»Î±Î³ÏŽÎ½.</numerusform>
</translation>
</message>
<message>
@@ -1148,6 +1173,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Κλείσιμο ποÏτοφολιοÏ</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">ΕπαναφοÏά ΠοÏτοφολιοÏ...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">ΕπαναφοÏά ενός ποÏÏ„Î¿Ï†Î¿Î»Î¹Î¿Ï Î±Ï€ÏŒ ένα αÏχείο αντίγÏαφου ασφαλείας</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Κλείσιμο όλων των ποÏτοφολιών</translation>
</message>
@@ -1172,6 +1207,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Κανένα ποÏτοφόλι διαθέσιμο</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Δεδομένα ποÏτοφολιοÏ</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">ΦόÏτωση ΑντίγÏαφου Ασφαλείας ΠοÏτοφολιοÏ</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">ΕπαναφοÏά ΠοÏτοφολιοÏ</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Όνομα ΠοÏτοφολιοÏ</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;ΠαÏάθυÏο</translation>
</message>
@@ -1187,12 +1242,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 πελάτης</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">$ΑπόκÏυψη</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">Ε&amp;μφάνιση</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>1%n ενεÏγές συνδέσεις στο δίκτυο Bitcoin.</numerusform>
+ <numerusform>%n ενεÏγές συνδέσεις στο δίκτυο Bitcoin.</numerusform>
</translation>
</message>
<message>
@@ -1390,6 +1453,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">L&amp;ock διαθέσιμο</translation>
</message>
<message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;Ξεκλείδωμα διαθέσιμου υπολοίπου</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">ΑντιγÏαφή ποσότητας</translation>
</message>
@@ -1470,7 +1537,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">Αδυναμία απαÏίθμησης εγγεγÏαμμένων </translation>
</message>
-</context>
+ </context>
<context>
<name>LoadWalletsActivity</name>
<message>
@@ -1510,6 +1577,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">ΕπαναφοÏά ΠοÏτοφολιοÏ</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">ΕπαναφοÏά ΠοÏÏ„Î¿Ï†Î¿Î»Î¹Î¿Ï &lt;b&gt; %1 &lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Αποτυχία επαναφοÏάς ποÏτοφολιοÏ</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">ΠÏοειδοποίηση επαναφοÏάς ποÏτοφολιοÏ</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">ÎœÏνημα επαναφοÏάς ποÏτοφολιοÏ</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1583,6 +1678,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ΠοÏτοφόλι ΠεÏιγÏαφέα </translation>
</message>
<message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">ΧÏησιμοποιήστε μια εξωτεÏική συσκευή υπογÏαφής, όπως ένα ποÏτοφόλι υλικοÏ. Ρυθμίστε Ï€Ïώτα στις Ï€Ïοτιμήσεις του ποÏÏ„Î¿Ï†Î¿Î»Î¹Î¿Ï Ï„Î¿ εξωτεÏικό script υπογÏαφής.</translation>
+ </message>
+ <message>
<source>External signer</source>
<translation type="unfinished">ΕξωτεÏικός υπογÏάφων</translation>
</message>
@@ -1594,7 +1693,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Compiled without sqlite support (required for descriptor wallets)</source>
<translation type="unfinished">Μεταγλωτίστηκε χωÏίς την υποστήÏιξη sqlite (απαÏαίτητη για πεÏιγÏαφικά ποÏτοφόλια )</translation>
</message>
- </context>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Συντάχθηκε χωÏίς την υποστήÏιξη εξωτεÏικής υπογÏαφής (απαιτείται για εξωτεÏική υπογÏαφή)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -1675,13 +1779,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(από τα %1 GB που απαιτοÏνται)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB απαιτοÏνται για την πλήÏη αλυσίδα)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(από το %n GB που απαιτείται)</numerusform>
+ <numerusform>(από τα %n GB που απαιτοÏνται)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB απαιτοÏνται για την πλήÏη αλυσίδα)</numerusform>
+ <numerusform>(%n GB απαιτοÏνται για την πλήÏη αλυσίδα)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1724,10 +1841,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ΚαλωσήÏθες στο %1.</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 type="unfinished">Όταν κάνετε κλικ στο OK, το %1 θα ξεκινήσει τη λήψη και την επεξεÏγασία της πλήÏους αλυσίδας μπλοκ% 4 (%2GB) αÏχίζοντας από τις Ï€Ïώτες συναλλαγές στο %3 όταν αÏχικά ξεκίνησε το %4.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">ΠεÏιόÏισε την χωÏητικότητα της αλυσίδας block σε</translation>
</message>
@@ -1836,7 +1949,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Άγνωστο. ΣυγχÏονισμός επικεφαλίδων (%1, %2%)...</translation>
</message>
-</context>
+ </context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -1868,6 +1981,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;ΈναÏξη %1 στο σÏστημα σÏνδεσης</translation>
</message>
<message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Η ενεÏγοποίηση του κλαδέματος μειώνει τον απαιτοÏμενο χώÏο για την αποθήκευση συναλλαγών. Όλα τα μπλόκ είναι πλήÏως επαληθευμένα. Η επαναφοÏά αυτής της ÏÏθμισης απαιτεί επανεγκατάσταση ολόκληÏου του blockchain.</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation type="unfinished">Μέγεθος κÏυφής μνήμης βάσης δεδομένων.</translation>
</message>
@@ -1888,6 +2005,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ελαχιστοποίηση αντί για έξοδο κατά το κλείσιμο του παÏαθÏÏου. Όταν αυτή η επιλογή είναι ενεÏγοποιημένη, η εφαÏμογή θα κλείνει μόνο αν επιλεχθεί η Έξοδος στο μενοÏ.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Οι επιλογές που έχουν οÏιστεί σε αυτό το παÏάθυÏο διαλόγου παÏαβλέπονται από τη γÏαμμή εντολών</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Ανοίξτε το %1 αÏχείο διαμόÏφωσης από τον κατάλογο εÏγασίας.</translation>
</message>
@@ -1924,10 +2045,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">(0 = αυτόματο, &lt;0 = ελεÏθεÏοι πυÏήνες)</translation>
</message>
<message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">ΕνεÏγοποίηση R&amp;PC σέÏβεÏ</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">Π&amp;οÏτοφόλι</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Îα τεθεί ο φόÏος αφαίÏεσης από το ποσό στην Ï€ÏοκαθοÏισμένη τιμή ή οχι. </translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">ΈμπειÏος</translation>
</message>
@@ -1944,6 +2075,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Ξόδεμα μη επικυÏωμένων Ïέστων</translation>
</message>
<message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">ΕξωτεÏική συσκευή υπογÏαφής (Ï€.χ. ποÏτοφόλι υλικοÏ)</translation>
+ </message>
+ <message>
<source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
<translation type="unfinished">ΠλήÏης διαδÏομή ενός script ÏƒÏ…Î¼Î²Î±Ï„Î¿Ï Î¼Îµ το Bitcoin Core (Ï€.χ.: C:\Downloads\hwi.exe ή /Users/you/Downloads/hwi.py). ΠÏοσοχή: το κακόβουλο λογισμικό μποÏεί να κλέψει τα νομίσματά σας!</translation>
</message>
@@ -1956,6 +2091,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Απόδοση θυÏών με χÏήση &amp;UPnP</translation>
</message>
<message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
+ <translation type="unfinished">Ανοίξτε αυτόματα τη πόÏτα του Bitcoin client στο router. Αυτό λειτουÏγεί μόνο όταν το router σας υποστηÏίζει NAT-PMP και είναι ενεÏγοποιημένο. Η εξωτεÏική πόÏτα μποÏεί να είναι τυχαία.</translation>
+ </message>
+ <message>
<source>Map port using NA&amp;T-PMP</source>
<translation type="unfinished">ΔÏομολόγηση θÏÏας με χÏήση NA&amp;T-PMP</translation>
</message>
@@ -2052,8 +2191,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ενσωματωμένο "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Οι επιλογές που έχουν οÏιστεί σε αυτό το παÏάθυÏο διαλόγου παÏαβλέπονται από τη γÏαμμή εντολών ή από το αÏχείο διαμόÏφωσης:</translation>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">πλησιέστεÏη αντιστοίχιση "%1"</translation>
</message>
<message>
<source>&amp;OK</source>
@@ -2064,6 +2203,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;ΑκÏÏωση</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Συντάχθηκε χωÏίς την υποστήÏιξη εξωτεÏικής υπογÏαφής (απαιτείται για εξωτεÏική υπογÏαφή)</translation>
+ </message>
+ <message>
<source>default</source>
<translation type="unfinished">Ï€Ïοεπιλογή</translation>
</message>
@@ -2073,14 +2217,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Επιβεβαίωση επαναφοÏάς επιλογών</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">ΧÏειάζεται επανεκκίνηση του Ï€ÏογÏάμματος για να ενεÏγοποιηθοÏν οι αλλαγές.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Ο πελάτης θα τεÏματιστεί. Θέλετε να συνεχίσετε?</translation>
</message>
<message>
@@ -2095,6 +2242,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Το αÏχείο Ïυθμίσεων χÏησιμοποιείται για τον Ï€ÏοσδιοÏισμό των Ï€ÏοχωÏημένων επιλογών χÏηστών που παÏακάμπτουν τις Ïυθμίσεις GUI. Επιπλέον, όλες οι επιλογές γÏαμμής εντολών θα αντικαταστήσουν αυτό το αÏχείο Ïυθμίσεων.</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">Συνεχίστε</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">ΑκÏÏωση</translation>
</message>
@@ -2116,6 +2267,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Δεν μποÏεί να διαβαστεί η ÏÏθμιση "%1", %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2229,6 +2387,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Αποτυχία εκπλήÏωσης συναλλαγής: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">ΑδÏνατη η υπογÏαφή εισδοχών ενώ το ποÏτοφόλι είναι κλειδωμένο</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">Δεν είναι δυνατή η υπογÏαφή πεÏισσότεÏων καταχωÏήσεων.</translation>
</message>
@@ -2303,6 +2465,10 @@ ID Συναλλαγής: %1</translation>
<translation type="unfinished">Η συναλλαγή απαιτεί υπογÏαφή/ές</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Δεν έχει γίνει φόÏτωση ποÏτοφολιοÏ)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Αλλά αυτό το ποÏτοφόλι δεν μποÏεί να υπογÏάψει συναλλαγές.)</translation>
</message>
@@ -2359,6 +2525,11 @@ ID Συναλλαγής: %1</translation>
<translation type="unfinished">ΧÏήστης</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Ηλικία</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">ΚατεÏθυνση</translation>
@@ -2542,6 +2713,10 @@ ID Συναλλαγής: %1</translation>
<translation type="unfinished">ΣυγχÏονισμένα Μπλοκς</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Τελευταία Συναλλαγή</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">Το χαÏτογÏαφημένο Αυτόνομο ΣÏστημα που χÏησιμοποιείται για τη διαφοÏοποίηση της επιλογής ομοτίμων.</translation>
</message>
@@ -2598,6 +2773,10 @@ ID Συναλλαγής: %1</translation>
<translation type="unfinished">ΧÏόνος σÏνδεσης</translation>
</message>
<message>
+ <source>Last Block</source>
+ <translation type="unfinished">Τελευταίο Block</translation>
+ </message>
+ <message>
<source>Last Send</source>
<translation type="unfinished">Τελευταία αποστολή</translation>
</message>
@@ -2662,6 +2841,11 @@ ID Συναλλαγής: %1</translation>
<translation type="unfinished">ΕξεÏχόμενα:</translation>
</message>
<message>
+ <source>Inbound: initiated by peer</source>
+ <extracomment>Explanatory text for an inbound peer connection.</extracomment>
+ <translation type="unfinished">ΕισεÏχόμενo: Ξεκίνησε από peer</translation>
+ </message>
+ <message>
<source>the peer selected us for high bandwidth relay</source>
<translation type="unfinished">ο ομότιμος μας επέλεξε για υψηλής ταχÏτητας αναμετάδοση </translation>
</message>
@@ -2687,6 +2871,11 @@ ID Συναλλαγής: %1</translation>
<translation type="unfinished">1 &amp;χÏόνος</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;ΑντιγÏαφή IP/Netmask</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;ΑκÏÏωση ΑπαγόÏευσης</translation>
</message>
@@ -2699,6 +2888,10 @@ ID Συναλλαγής: %1</translation>
<translation type="unfinished">Εκτέλεση εντολής χωÏίς ποÏτοφόλι</translation>
</message>
<message>
+ <source>Ctrl+I</source>
+ <translation type="unfinished">Ctrl+Ι </translation>
+ </message>
+ <message>
<source>Executing command using "%1" wallet</source>
<translation type="unfinished"> 
Εκτελέστε εντολή χÏησιμοποιώντας το ποÏτοφόλι "%1"</translation>
@@ -3139,6 +3332,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">%1 Ï€Ïος το %2</translation>
</message>
<message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">Για να αναθεωÏήσετε τη λίστα παÏαληπτών, κάντε κλικ στην επιλογή "Εμφάνιση λεπτομεÏειών..."</translation>
+ </message>
+ <message>
<source>Sign failed</source>
<translation type="unfinished">H εγγÏαφή απέτυχε</translation>
</message>
@@ -3161,6 +3358,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">Το PSBT αποθηκεÏτηκε</translation>
</message>
<message>
+ <source>External balance:</source>
+ <translation type="unfinished">ΕξωτεÏικό υπόλοιπο:</translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">ή</translation>
</message>
@@ -3174,6 +3375,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">ΠαÏακαλοÏμε, ελέγξτε την Ï€Ïόταση συναλλαγής. Θα παÏαχθεί μια συναλλαγή Bitcoin με μεÏική υπογÏαφή (PSBT), την οποία μποÏείτε να αντιγÏάψετε και στη συνέχεια να υπογÏάψετε με Ï€.χ. ένα ποÏτοφόλι %1 εκτός σÏνδεσης ή ένα ποÏτοφόλι Ï…Î»Î¹ÎºÎ¿Ï ÏƒÏ…Î¼Î²Î±Ï„ÏŒ με το PSBT.</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Θέλετε να δημιουÏγήσετε αυτήν τη συναλλαγή;</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">ΠαÏακαλοÏμε, ελέγξτε τη συναλλαγή σας.</translation>
@@ -3227,10 +3433,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Ένα τέλος υψηλότεÏο από το %1 θεωÏείται ένα παÏάλογο υψηλό έξοδο.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Η αίτηση πληÏωμής έληξε.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -3306,14 +3508,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">Μήνυμα:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">ΠÏόκειται για αίτημα πληÏωμής χωÏίς έλεγχο ταυτότητας.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">ΠÏόκειται για ένα πιστοποιημένο αίτημα πληÏωμής.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Εισάγετε μία ετικέτα για αυτή την διεÏθυνση για να Ï€Ïοστεθεί στη λίστα με τις χÏησιμοποιημένες διευθÏνσεις</translation>
</message>
@@ -3321,14 +3515,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<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 type="unfinished">Ένα μήνυμα που επισυνάφθηκε στο bitcoin: URI το οποίο θα αποθηκευτεί με τη συναλλαγή για αναφοÏά. Σημείωση: Αυτό το μήνυμα δεν θα σταλεί μέσω του δικτÏου Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">ΠληÏωμή σε:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Σημείωση:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3485,33 +3671,36 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
</context>
<context>
- <name>TransactionDesc</name>
+ <name>SplashScreen</name>
<message>
- <source>conflicted with a transaction with %1 confirmations</source>
- <translation type="unfinished">σε σÏγκÏουση με μια συναλλαγή με %1 επιβεβαιώσεις</translation>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished">(πατήστε q για κλείσιμο και συνεχίστε αÏγότεÏα)</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/ανεπιβεβαίωτο, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">στην πισίνα μνήμης</translation>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">πατήστε q για κλείσιμο</translation>
</message>
+</context>
+<context>
+ <name>TransactionDesc</name>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">όχι στην πισίνα μνήμης</translation>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
+ <translation type="unfinished">σε σÏγκÏουση με μια συναλλαγή με %1 επιβεβαιώσεις</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">εγκαταλελειμμένος</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/μη επιβεβαιωμένο</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 επιβεβαιώσεις</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 586240445e..ebce81b198 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -55,7 +55,7 @@
</message>
<message>
<location line="-30"/>
- <location filename="../addressbookpage.cpp" line="+128"/>
+ <location filename="../addressbookpage.cpp" line="+127"/>
<source>&amp;Delete</source>
<translation>&amp;Delete</translation>
</message>
@@ -179,7 +179,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../askpassphrasedialog.cpp" line="+51"/>
+ <location filename="../askpassphrasedialog.cpp" line="+49"/>
<source>Encrypt wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -199,7 +199,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+48"/>
+ <location line="+47"/>
<source>Confirm wallet encryption</source>
<translation type="unfinished"></translation>
</message>
@@ -215,12 +215,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</message>
<message>
<location line="+18"/>
- <location line="+44"/>
+ <location line="+55"/>
<source>Wallet encrypted</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-125"/>
+ <location line="-135"/>
<source>Enter the new passphrase for 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 type="unfinished"></translation>
</message>
@@ -230,7 +230,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+55"/>
+ <location line="+54"/>
<source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
<translation type="unfinished"></translation>
</message>
@@ -257,41 +257,57 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<message>
<location line="+6"/>
<location line="+8"/>
- <location line="+32"/>
- <location line="+6"/>
+ <location line="+59"/>
<source>Wallet encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-45"/>
+ <location line="-66"/>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
- <location line="+38"/>
+ <location line="+59"/>
<source>The supplied passphrases do not match.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-27"/>
- <location line="+6"/>
+ <location line="-46"/>
+ <location line="+3"/>
+ <location line="+12"/>
<source>Wallet unlock failed</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-5"/>
- <location line="+20"/>
+ <location line="-14"/>
+ <location line="+31"/>
<source>The passphrase entered for the wallet decryption was incorrect.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-6"/>
+ <location line="-28"/>
+ <source>The passphrase entered for the wallet decryption is incorrect. It contains a null character (ie - a zero byte). If the passphrase was set with a version of this software prior to 25.0, please try again with only the characters up to — but not including — the first null character. If this is successful, please set a new passphrase to avoid this issue in the future.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+20"/>
<source>Wallet passphrase was successfully changed.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+46"/>
+ <location line="+7"/>
+ <location line="+3"/>
+ <source>Passphrase change failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>The old passphrase entered for the wallet decryption is incorrect. It contains a null character (ie - a zero byte). If the passphrase was set with a version of this software prior to 25.0, please try again with only the characters up to — but not including — the first null character.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+45"/>
<location line="+33"/>
<source>Warning: The Caps Lock key is on!</source>
<translation type="unfinished"></translation>
@@ -313,7 +329,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>BitcoinApplication</name>
<message>
- <location filename="../bitcoin.cpp" line="+288"/>
+ <location filename="../bitcoin.cpp" line="+283"/>
<source>Settings file %1 might be corrupt or invalid.</source>
<translation type="unfinished"></translation>
</message>
@@ -411,18 +427,18 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+393"/>
+ <location line="+395"/>
<source>Network activity disabled.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+439"/>
+ <location line="+436"/>
<source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1160"/>
+ <location line="-1159"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -537,7 +553,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>Tabs toolbar</translation>
</message>
<message>
- <location line="+457"/>
+ <location line="+459"/>
<source>Syncing Headers (%1%)…</source>
<translation type="unfinished"></translation>
</message>
@@ -557,17 +573,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
- <source>Reindexing blocks on disk…</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+6"/>
+ <location line="+7"/>
<source>Connecting to peers…</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-833"/>
+ <location line="-832"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
@@ -587,7 +598,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+749"/>
+ <location line="+748"/>
<source>Processed %n block(s) of transaction history.</source>
<translation>
<numerusform>Processed %n block of transaction history.</numerusform>
@@ -635,7 +646,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>Up to date</translation>
</message>
<message>
- <location line="-818"/>
+ <location line="-817"/>
<source>Ctrl+Q</source>
<translation type="unfinished"></translation>
</message>
@@ -781,7 +792,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+258"/>
+ <location line="+260"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
@@ -834,7 +845,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+152"/>
+ <location line="+149"/>
<source>Error: %1</source>
<translation type="unfinished"></translation>
</message>
@@ -1266,7 +1277,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>&amp;Address</translation>
</message>
<message>
- <location filename="../editaddressdialog.cpp" line="+29"/>
+ <location filename="../editaddressdialog.cpp" line="+27"/>
<source>New sending address</source>
<translation type="unfinished"></translation>
</message>
@@ -1410,7 +1421,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>Use a custom data directory:</translation>
</message>
<message>
- <location filename="../intro.cpp" line="+32"/>
+ <location filename="../intro.cpp" line="+30"/>
<source>Bitcoin</source>
<translation type="unfinished">Bitcoin</translation>
</message>
@@ -1518,7 +1529,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<message>
<location line="+7"/>
<location line="+26"/>
- <location filename="../modaloverlay.cpp" line="+155"/>
+ <location filename="../modaloverlay.cpp" line="+152"/>
<source>Unknown…</source>
<translation type="unfinished"></translation>
</message>
@@ -1661,7 +1672,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+231"/>
+ <location line="+132"/>
+ <source>Full path to a %1 compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+99"/>
<location line="+187"/>
<source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
<translation type="unfinished"></translation>
@@ -1817,12 +1833,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
- <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+32"/>
+ <location line="+42"/>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
<translation>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</translation>
</message>
@@ -2092,7 +2103,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>OptionsModel</name>
<message>
- <location filename="../optionsmodel.cpp" line="+204"/>
+ <location filename="../optionsmodel.cpp" line="+198"/>
<source>Could not read setting &quot;%1&quot;, %2.</source>
<translation type="unfinished"></translation>
</message>
@@ -2191,7 +2202,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../overviewpage.cpp" line="+185"/>
+ <location filename="../overviewpage.cpp" line="+184"/>
<source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
<translation type="unfinished"></translation>
</message>
@@ -2363,7 +2374,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>PaymentServer</name>
<message>
- <location filename="../paymentserver.cpp" line="+152"/>
+ <location filename="../paymentserver.cpp" line="+149"/>
<source>Payment request error</source>
<translation type="unfinished"></translation>
</message>
@@ -2467,7 +2478,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">Network</translation>
</message>
<message>
- <location filename="../peertablemodel.cpp" line="+78"/>
+ <location filename="../peertablemodel.cpp" line="+77"/>
<source>Inbound</source>
<extracomment>An Inbound Connection from a Peer.</extracomment>
<translation type="unfinished"></translation>
@@ -2497,7 +2508,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+256"/>
+ <location line="+257"/>
<source>Unroutable</source>
<translation type="unfinished"></translation>
</message>
@@ -2663,7 +2674,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="-294"/>
+ <location filename="../bitcoin.cpp" line="-288"/>
<source>Do you want to reset settings to default values, or to abort without making changes?</source>
<extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
<translation type="unfinished"></translation>
@@ -2675,17 +2686,17 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+393"/>
+ <location line="+386"/>
<source>Error: Specified data directory &quot;%1&quot; does not exist.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+9"/>
<source>Error: Cannot parse configuration file: %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+15"/>
+ <location line="+14"/>
<source>Error: %1</source>
<translation type="unfinished"></translation>
</message>
@@ -2908,7 +2919,17 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+124"/>
+ <location line="+72"/>
+ <source>Whether we relay transactions to this peer.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Transaction Relay</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+49"/>
<source>Starting Block</source>
<translation type="unfinished"></translation>
</message>
@@ -3030,17 +3051,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+26"/>
- <source>Whether the peer requested us to relay transactions.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
- <source>Wants Tx Relay</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+23"/>
+ <location line="+52"/>
<source>High bandwidth BIP152 compact block relay: %1</source>
<translation type="unfinished"></translation>
</message>
@@ -3308,7 +3319,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+316"/>
+ <location line="+320"/>
<source>Ctrl+I</source>
<translation type="unfinished"></translation>
</message>
@@ -3328,7 +3339,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-321"/>
+ <location line="-325"/>
<source>Executing command using &quot;%1&quot; wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -3455,7 +3466,7 @@ For more information on using this console, type %6.
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../receivecoinsdialog.cpp" line="+47"/>
+ <location filename="../receivecoinsdialog.cpp" line="+46"/>
<source>Copy &amp;URI</source>
<translation type="unfinished"></translation>
</message>
@@ -3548,7 +3559,7 @@ For more information on using this console, type %6.
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../receiverequestdialog.cpp" line="+49"/>
+ <location filename="../receiverequestdialog.cpp" line="+48"/>
<source>Request payment to %1</source>
<translation type="unfinished"></translation>
</message>
@@ -3633,7 +3644,7 @@ For more information on using this console, type %6.
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+757"/>
+ <location filename="../sendcoinsdialog.cpp" line="+755"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -3820,7 +3831,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-658"/>
+ <location filename="../sendcoinsdialog.cpp" line="-660"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -3887,7 +3898,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+90"/>
+ <location line="+92"/>
<source> from wallet &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -4311,7 +4322,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../signverifymessagedialog.cpp" line="+120"/>
+ <location filename="../signverifymessagedialog.cpp" line="+119"/>
<location line="+99"/>
<source>The entered address is invalid.</source>
<translation type="unfinished"></translation>
@@ -4385,7 +4396,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<context>
<name>SplashScreen</name>
<message>
- <location filename="../splashscreen.cpp" line="+187"/>
+ <location filename="../splashscreen.cpp" line="+177"/>
<source>(press q to shutdown and continue later)</source>
<translation type="unfinished"></translation>
</message>
@@ -4398,7 +4409,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<context>
<name>TrafficGraphWidget</name>
<message>
- <location filename="../trafficgraphwidget.cpp" line="+79"/>
+ <location filename="../trafficgraphwidget.cpp" line="+74"/>
<source>kB/s</source>
<translation type="unfinished"></translation>
</message>
@@ -4640,7 +4651,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<context>
<name>TransactionTableModel</name>
<message>
- <location filename="../transactiontablemodel.cpp" line="+261"/>
+ <location filename="../transactiontablemodel.cpp" line="+257"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -4956,7 +4967,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+172"/>
+ <location line="+169"/>
<source>Range:</source>
<translation type="unfinished"></translation>
</message>
@@ -4969,7 +4980,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
- <location filename="../bitcoingui.cpp" line="+41"/>
+ <location filename="../bitcoingui.cpp" line="+39"/>
<source>Unit to show amounts in. Click to select another unit.</source>
<translation type="unfinished"></translation>
</message>
@@ -5052,20 +5063,21 @@ Go to File &gt; Open Wallet to load a wallet.
<context>
<name>WalletModel</name>
<message>
- <location filename="../walletmodel.cpp" line="+232"/>
+ <location filename="../walletmodel.cpp" line="+228"/>
+ <location line="+13"/>
<source>Send Coins</source>
<translation type="unfinished">Send Coins</translation>
</message>
<message>
- <location line="+263"/>
- <location line="+52"/>
+ <location line="+248"/>
+ <location line="+55"/>
<location line="+15"/>
<location line="+5"/>
<source>Fee bump error</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-72"/>
+ <location line="-75"/>
<source>Increasing transaction fee failed</source>
<translation type="unfinished"></translation>
</message>
@@ -5096,12 +5108,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+5"/>
<source>Confirm fee bump</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+23"/>
<source>Can&apos;t draft transaction.</source>
<translation type="unfinished"></translation>
</message>
@@ -5134,7 +5146,7 @@ Go to File &gt; Open Wallet to load a wallet.
<context>
<name>WalletView</name>
<message>
- <location filename="../walletview.cpp" line="+51"/>
+ <location filename="../walletview.cpp" line="+50"/>
<source>&amp;Export</source>
<translation type="unfinished">&amp;Export</translation>
</message>
@@ -5193,12 +5205,17 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+3"/>
+ <source>%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any peer will connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
<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"/>
+ <location line="+15"/>
<source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
<translation type="unfinished"></translation>
</message>
@@ -5214,11 +5231,21 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+4"/>
+ <source>Disk space for %s may not accommodate the block files. Approximately %u GB of data will be stored in this directory.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
+ <source>Error loading wallet. Wallet requires blocks to be downloaded, and software does not currently support loading wallets while blocks are being downloaded out of order when using assumeutxo snapshots. Wallet should be able to load successfully after node sync reaches height %s</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
<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>
@@ -5248,7 +5275,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+6"/>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet&apos;s passphrase if it is encrypted.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished"></translation>
</message>
@@ -5288,7 +5320,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+16"/>
<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>
@@ -5328,7 +5360,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+11"/>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished"></translation>
</message>
@@ -5368,7 +5400,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+7"/>
<source>Unknown wallet file format &quot;%s&quot; provided. Please provide one of &quot;bdb&quot; or &quot;sqlite&quot;.</source>
<translation type="unfinished"></translation>
</message>
@@ -5443,17 +5475,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-79"/>
+ <location line="-90"/>
<source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-122"/>
- <source>%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+7"/>
+ <location line="-126"/>
<source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
<translation type="unfinished"></translation>
</message>
@@ -5468,22 +5495,17 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
- <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+8"/>
+ <location line="+9"/>
<source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+13"/>
<source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+14"/>
<source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
<translation type="unfinished"></translation>
</message>
@@ -5498,12 +5520,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+6"/>
<source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
<translation type="unfinished"></translation>
</message>
@@ -5514,6 +5531,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+21"/>
+ <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
<translation type="unfinished"></translation>
</message>
@@ -5523,7 +5545,30 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+59"/>
+ <location line="+4"/>
+ <source>Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+32"/>
+ <source>The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet&apos;s UTXOs</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>The preselected coins total amount does not cover the transaction target. Please allow other inputs to be automatically selected or include more coins manually</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+27"/>
+ <source>Unexpected legacy entry in descriptor wallet found. Loading wallet %s
+
+The wallet might have been tampered with or created with malicious intent.
+</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
<source>Unrecognized descriptor found. Loading wallet %s
The wallet might had been created on a newer version.
@@ -5650,6 +5695,11 @@ Unable to restore backup of wallet.</source>
</message>
<message>
<location line="+1"/>
+ <source>Error: Cannot extract destination from the generated scriptpubkey</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Error: Could not add watchonly tx to watchonly wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -5795,6 +5845,11 @@ Unable to restore backup of wallet.</source>
</message>
<message>
<location line="+1"/>
+ <source>Insufficient dbcache for block verification</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Insufficient funds</source>
<translation type="unfinished"></translation>
</message>
@@ -5845,6 +5900,16 @@ Unable to restore backup of wallet.</source>
</message>
<message>
<location line="+1"/>
+ <source>Invalid port specified in %s: &apos;%s&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Invalid pre-selected input %s</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Listening for incoming connections failed (listen returned error %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -5895,6 +5960,16 @@ Unable to restore backup of wallet.</source>
</message>
<message>
<location line="+1"/>
+ <source>Not found pre-selected input %s</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Not solvable pre-selected input %s</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Prune cannot be configured with a negative value.</source>
<translation type="unfinished"></translation>
</message>
@@ -6159,7 +6234,7 @@ Unable to restore backup of wallet.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="-519"/>
+ <location filename="../bitcoin.cpp" line="-514"/>
<source>Settings file could not be read</source>
<translation type="unfinished"></translation>
</message>
diff --git a/src/qt/locale/bitcoin_en.xlf b/src/qt/locale/bitcoin_en.xlf
index a25ccfca72..4920a08d72 100644
--- a/src/qt/locale/bitcoin_en.xlf
+++ b/src/qt/locale/bitcoin_en.xlf
@@ -45,7 +45,7 @@
<trans-unit id="_msg11">
<source xml:space="preserve">&amp;Delete</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
- <context-group purpose="location"><context context-type="sourcefile">../addressbookpage.cpp</context><context context-type="linenumber">128</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../addressbookpage.cpp</context><context context-type="linenumber">127</context></context-group>
</trans-unit>
</group>
</body></file>
@@ -53,62 +53,62 @@
<group restype="x-trolltech-linguist-context" resname="AddressBookPage">
<trans-unit id="_msg12">
<source xml:space="preserve">Choose the address to send coins to</source>
- <context-group purpose="location"><context context-type="linenumber">90</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">89</context></context-group>
</trans-unit>
<trans-unit id="_msg13">
<source xml:space="preserve">Choose the address to receive coins with</source>
- <context-group purpose="location"><context context-type="linenumber">91</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
<trans-unit id="_msg14">
<source xml:space="preserve">C&amp;hoose</source>
- <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
<trans-unit id="_msg15">
<source xml:space="preserve">Sending addresses</source>
- <context-group purpose="location"><context context-type="linenumber">102</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
<trans-unit id="_msg16">
<source xml:space="preserve">Receiving addresses</source>
- <context-group purpose="location"><context context-type="linenumber">103</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">102</context></context-group>
</trans-unit>
<trans-unit id="_msg17">
<source xml:space="preserve">These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
- <context-group purpose="location"><context context-type="linenumber">110</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">109</context></context-group>
</trans-unit>
<trans-unit id="_msg18">
<source xml:space="preserve">These are your Bitcoin addresses for receiving payments. Use the &apos;Create new receiving address&apos; button in the receive tab to create new addresses.
Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
- <context-group purpose="location"><context context-type="linenumber">115</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">114</context></context-group>
</trans-unit>
<trans-unit id="_msg19">
<source xml:space="preserve">&amp;Copy Address</source>
- <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
<trans-unit id="_msg20">
<source xml:space="preserve">Copy &amp;Label</source>
- <context-group purpose="location"><context context-type="linenumber">124</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
<trans-unit id="_msg21">
<source xml:space="preserve">&amp;Edit</source>
- <context-group purpose="location"><context context-type="linenumber">125</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
<trans-unit id="_msg22">
<source xml:space="preserve">Export Address List</source>
- <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
</trans-unit>
<trans-unit id="_msg23">
<source xml:space="preserve">Comma separated file</source>
- <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">291</context></context-group>
<note annotates="source" from="developer">Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</note>
</trans-unit>
<trans-unit id="_msg24">
<source xml:space="preserve">There was an error trying to save the address list to %1. Please try again.</source>
- <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">307</context></context-group>
<note annotates="source" from="developer">An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</note>
</trans-unit>
<trans-unit id="_msg25">
<source xml:space="preserve">Exporting Failed</source>
- <context-group purpose="location"><context context-type="linenumber">305</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
</group>
</body></file>
@@ -156,109 +156,122 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<group restype="x-trolltech-linguist-context" resname="AskPassphraseDialog">
<trans-unit id="_msg34">
<source xml:space="preserve">Encrypt wallet</source>
- <context-group purpose="location"><context context-type="linenumber">51</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
<trans-unit id="_msg35">
<source xml:space="preserve">This operation needs your wallet passphrase to unlock the wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">54</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">52</context></context-group>
</trans-unit>
<trans-unit id="_msg36">
<source xml:space="preserve">Unlock wallet</source>
- <context-group purpose="location"><context context-type="linenumber">59</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">57</context></context-group>
</trans-unit>
<trans-unit id="_msg37">
<source xml:space="preserve">Change passphrase</source>
- <context-group purpose="location"><context context-type="linenumber">62</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
<trans-unit id="_msg38">
<source xml:space="preserve">Confirm wallet encryption</source>
- <context-group purpose="location"><context context-type="linenumber">110</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">107</context></context-group>
</trans-unit>
<trans-unit id="_msg39">
<source xml:space="preserve">Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
- <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
<trans-unit id="_msg40">
<source xml:space="preserve">Are you sure you wish to encrypt your wallet?</source>
- <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
<trans-unit id="_msg41">
<source xml:space="preserve">Wallet encrypted</source>
- <context-group purpose="location"><context context-type="linenumber">129</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">126</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
</trans-unit>
<trans-unit id="_msg42">
<source xml:space="preserve">Enter the new passphrase for 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>
- <context-group purpose="location"><context context-type="linenumber">48</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">46</context></context-group>
</trans-unit>
<trans-unit id="_msg43">
<source xml:space="preserve">Enter the old passphrase and new passphrase for the wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">63</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
<trans-unit id="_msg44">
<source xml:space="preserve">Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
- <context-group purpose="location"><context context-type="linenumber">118</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">115</context></context-group>
</trans-unit>
<trans-unit id="_msg45">
<source xml:space="preserve">Wallet to be encrypted</source>
- <context-group purpose="location"><context context-type="linenumber">122</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">119</context></context-group>
</trans-unit>
<trans-unit id="_msg46">
<source xml:space="preserve">Your wallet is about to be encrypted. </source>
- <context-group purpose="location"><context context-type="linenumber">124</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">121</context></context-group>
</trans-unit>
<trans-unit id="_msg47">
<source xml:space="preserve">Your wallet is now encrypted. </source>
- <context-group purpose="location"><context context-type="linenumber">131</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">128</context></context-group>
</trans-unit>
<trans-unit id="_msg48">
<source xml:space="preserve">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>
- <context-group purpose="location"><context context-type="linenumber">133</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">130</context></context-group>
</trans-unit>
<trans-unit id="_msg49">
<source xml:space="preserve">Wallet encryption failed</source>
- <context-group purpose="location"><context context-type="linenumber">139</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">147</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">179</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">185</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">136</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">144</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">203</context></context-group>
</trans-unit>
<trans-unit id="_msg50">
<source xml:space="preserve">Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
- <context-group purpose="location"><context context-type="linenumber">140</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">137</context></context-group>
</trans-unit>
<trans-unit id="_msg51">
<source xml:space="preserve">The supplied passphrases do not match.</source>
- <context-group purpose="location"><context context-type="linenumber">148</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">186</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">145</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">204</context></context-group>
</trans-unit>
<trans-unit id="_msg52">
<source xml:space="preserve">Wallet unlock failed</source>
- <context-group purpose="location"><context context-type="linenumber">159</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">165</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">158</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
<trans-unit id="_msg53">
<source xml:space="preserve">The passphrase entered for the wallet decryption was incorrect.</source>
- <context-group purpose="location"><context context-type="linenumber">160</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">159</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">190</context></context-group>
</trans-unit>
<trans-unit id="_msg54">
- <source xml:space="preserve">Wallet passphrase was successfully changed.</source>
- <context-group purpose="location"><context context-type="linenumber">174</context></context-group>
+ <source xml:space="preserve">The passphrase entered for the wallet decryption is incorrect. It contains a null character (ie - a zero byte). If the passphrase was set with a version of this software prior to 25.0, please try again with only the characters up to — but not including — the first null character. If this is successful, please set a new passphrase to avoid this issue in the future.</source>
+ <context-group purpose="location"><context context-type="linenumber">162</context></context-group>
</trans-unit>
<trans-unit id="_msg55">
+ <source xml:space="preserve">Wallet passphrase was successfully changed.</source>
+ <context-group purpose="location"><context context-type="linenumber">182</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg56">
+ <source xml:space="preserve">Passphrase change failed</source>
+ <context-group purpose="location"><context context-type="linenumber">189</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">192</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg57">
+ <source xml:space="preserve">The old passphrase entered for the wallet decryption is incorrect. It contains a null character (ie - a zero byte). If the passphrase was set with a version of this software prior to 25.0, please try again with only the characters up to — but not including — the first null character.</source>
+ <context-group purpose="location"><context context-type="linenumber">193</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg58">
<source xml:space="preserve">Warning: The Caps Lock key is on!</source>
- <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">238</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../bantablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="BanTableModel">
- <trans-unit id="_msg56">
+ <trans-unit id="_msg59">
<source xml:space="preserve">IP/Netmask</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg57">
+ <trans-unit id="_msg60">
<source xml:space="preserve">Banned Until</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
@@ -266,615 +279,611 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../bitcoin.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="BitcoinApplication">
- <trans-unit id="_msg58">
+ <trans-unit id="_msg61">
<source xml:space="preserve">Settings file %1 might be corrupt or invalid.</source>
- <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
</trans-unit>
- <trans-unit id="_msg59">
+ <trans-unit id="_msg62">
<source xml:space="preserve">Runaway exception</source>
- <context-group purpose="location"><context context-type="linenumber">466</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">461</context></context-group>
</trans-unit>
- <trans-unit id="_msg60">
+ <trans-unit id="_msg63">
<source xml:space="preserve">A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <context-group purpose="location"><context context-type="linenumber">467</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">462</context></context-group>
</trans-unit>
- <trans-unit id="_msg61">
+ <trans-unit id="_msg64">
<source xml:space="preserve">Internal error</source>
- <context-group purpose="location"><context context-type="linenumber">476</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">471</context></context-group>
</trans-unit>
- <trans-unit id="_msg62">
+ <trans-unit id="_msg65">
<source xml:space="preserve">An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
- <context-group purpose="location"><context context-type="linenumber">477</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">472</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg63">
+ <trans-unit id="_msg66">
<source xml:space="preserve">Do you want to reset settings to default values, or to abort without making changes?</source>
- <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">184</context></context-group>
<note annotates="source" from="developer">Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</note>
</trans-unit>
- <trans-unit id="_msg64">
+ <trans-unit id="_msg67">
<source xml:space="preserve">A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
- <context-group purpose="location"><context context-type="linenumber">207</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">208</context></context-group>
<note annotates="source" from="developer">Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</note>
</trans-unit>
- <trans-unit id="_msg65">
+ <trans-unit id="_msg68">
<source xml:space="preserve">Error: Specified data directory &quot;%1&quot; does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">600</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">594</context></context-group>
</trans-unit>
- <trans-unit id="_msg66">
+ <trans-unit id="_msg69">
<source xml:space="preserve">Error: Cannot parse configuration file: %1.</source>
- <context-group purpose="location"><context context-type="linenumber">606</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">603</context></context-group>
</trans-unit>
- <trans-unit id="_msg67">
+ <trans-unit id="_msg70">
<source xml:space="preserve">Error: %1</source>
- <context-group purpose="location"><context context-type="linenumber">621</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">617</context></context-group>
</trans-unit>
- <trans-unit id="_msg68">
+ <trans-unit id="_msg71">
<source xml:space="preserve">%1 didn&apos;t yet exit safely…</source>
- <context-group purpose="location"><context context-type="linenumber">695</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">691</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="bitcoin-core">
- <trans-unit id="_msg69">
+ <trans-unit id="_msg72">
<source xml:space="preserve">Settings file could not be read</source>
- <context-group purpose="location"><context context-type="linenumber">176</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">177</context></context-group>
</trans-unit>
- <trans-unit id="_msg70">
+ <trans-unit id="_msg73">
<source xml:space="preserve">Settings file could not be written</source>
- <context-group purpose="location"><context context-type="linenumber">199</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">200</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../bitcoingui.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="BitcoinGUI">
- <trans-unit id="_msg71">
+ <trans-unit id="_msg74">
<source xml:space="preserve">&amp;Overview</source>
<context-group purpose="location"><context context-type="linenumber">253</context></context-group>
</trans-unit>
- <trans-unit id="_msg72">
+ <trans-unit id="_msg75">
<source xml:space="preserve">Show general overview of wallet</source>
<context-group purpose="location"><context context-type="linenumber">254</context></context-group>
</trans-unit>
- <trans-unit id="_msg73">
+ <trans-unit id="_msg76">
<source xml:space="preserve">&amp;Transactions</source>
<context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg74">
+ <trans-unit id="_msg77">
<source xml:space="preserve">Browse transaction history</source>
<context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
- <trans-unit id="_msg75">
+ <trans-unit id="_msg78">
<source xml:space="preserve">E&amp;xit</source>
<context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
- <trans-unit id="_msg76">
+ <trans-unit id="_msg79">
<source xml:space="preserve">Quit application</source>
<context-group purpose="location"><context context-type="linenumber">295</context></context-group>
</trans-unit>
- <trans-unit id="_msg77">
+ <trans-unit id="_msg80">
<source xml:space="preserve">&amp;About %1</source>
<context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg78">
+ <trans-unit id="_msg81">
<source xml:space="preserve">Show information about %1</source>
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
</trans-unit>
- <trans-unit id="_msg79">
+ <trans-unit id="_msg82">
<source xml:space="preserve">About &amp;Qt</source>
<context-group purpose="location"><context context-type="linenumber">302</context></context-group>
</trans-unit>
- <trans-unit id="_msg80">
+ <trans-unit id="_msg83">
<source xml:space="preserve">Show information about Qt</source>
<context-group purpose="location"><context context-type="linenumber">303</context></context-group>
</trans-unit>
- <trans-unit id="_msg81">
+ <trans-unit id="_msg84">
<source xml:space="preserve">Modify configuration options for %1</source>
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
- <trans-unit id="_msg82">
+ <trans-unit id="_msg85">
<source xml:space="preserve">Create a new wallet</source>
<context-group purpose="location"><context context-type="linenumber">350</context></context-group>
</trans-unit>
- <trans-unit id="_msg83">
+ <trans-unit id="_msg86">
<source xml:space="preserve">&amp;Minimize</source>
<context-group purpose="location"><context context-type="linenumber">510</context></context-group>
</trans-unit>
- <trans-unit id="_msg84">
+ <trans-unit id="_msg87">
<source xml:space="preserve">Wallet:</source>
<context-group purpose="location"><context context-type="linenumber">589</context></context-group>
</trans-unit>
- <trans-unit id="_msg85">
+ <trans-unit id="_msg88">
<source xml:space="preserve">Network activity disabled.</source>
- <context-group purpose="location"><context context-type="linenumber">982</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">984</context></context-group>
<note annotates="source" from="developer">A substring of the tooltip.</note>
</trans-unit>
- <trans-unit id="_msg86">
+ <trans-unit id="_msg89">
<source xml:space="preserve">Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1421</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1420</context></context-group>
</trans-unit>
- <trans-unit id="_msg87">
+ <trans-unit id="_msg90">
<source xml:space="preserve">Send coins to a Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg88">
+ <trans-unit id="_msg91">
<source xml:space="preserve">Backup wallet to another location</source>
<context-group purpose="location"><context context-type="linenumber">314</context></context-group>
</trans-unit>
- <trans-unit id="_msg89">
+ <trans-unit id="_msg92">
<source xml:space="preserve">Change the passphrase used for wallet encryption</source>
<context-group purpose="location"><context context-type="linenumber">316</context></context-group>
</trans-unit>
- <trans-unit id="_msg90">
+ <trans-unit id="_msg93">
<source xml:space="preserve">&amp;Send</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg91">
+ <trans-unit id="_msg94">
<source xml:space="preserve">&amp;Receive</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg92">
+ <trans-unit id="_msg95">
<source xml:space="preserve">&amp;Options…</source>
<context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
- <trans-unit id="_msg93">
+ <trans-unit id="_msg96">
<source xml:space="preserve">&amp;Encrypt Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">310</context></context-group>
</trans-unit>
- <trans-unit id="_msg94">
+ <trans-unit id="_msg97">
<source xml:space="preserve">Encrypt the private keys that belong to your wallet</source>
<context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
- <trans-unit id="_msg95">
+ <trans-unit id="_msg98">
<source xml:space="preserve">&amp;Backup Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">313</context></context-group>
</trans-unit>
- <trans-unit id="_msg96">
+ <trans-unit id="_msg99">
<source xml:space="preserve">&amp;Change Passphrase…</source>
<context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
- <trans-unit id="_msg97">
+ <trans-unit id="_msg100">
<source xml:space="preserve">Sign &amp;message…</source>
<context-group purpose="location"><context context-type="linenumber">317</context></context-group>
</trans-unit>
- <trans-unit id="_msg98">
+ <trans-unit id="_msg101">
<source xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg99">
+ <trans-unit id="_msg102">
<source xml:space="preserve">&amp;Verify message…</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg100">
+ <trans-unit id="_msg103">
<source xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</source>
<context-group purpose="location"><context context-type="linenumber">320</context></context-group>
</trans-unit>
- <trans-unit id="_msg101">
+ <trans-unit id="_msg104">
<source xml:space="preserve">&amp;Load PSBT from file…</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg102">
+ <trans-unit id="_msg105">
<source xml:space="preserve">Open &amp;URI…</source>
<context-group purpose="location"><context context-type="linenumber">337</context></context-group>
</trans-unit>
- <trans-unit id="_msg103">
+ <trans-unit id="_msg106">
<source xml:space="preserve">Close Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">345</context></context-group>
</trans-unit>
- <trans-unit id="_msg104">
+ <trans-unit id="_msg107">
<source xml:space="preserve">Create Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">348</context></context-group>
</trans-unit>
- <trans-unit id="_msg105">
+ <trans-unit id="_msg108">
<source xml:space="preserve">Close All Wallets…</source>
<context-group purpose="location"><context context-type="linenumber">358</context></context-group>
</trans-unit>
- <trans-unit id="_msg106">
+ <trans-unit id="_msg109">
<source xml:space="preserve">&amp;File</source>
<context-group purpose="location"><context context-type="linenumber">477</context></context-group>
</trans-unit>
- <trans-unit id="_msg107">
+ <trans-unit id="_msg110">
<source xml:space="preserve">&amp;Settings</source>
<context-group purpose="location"><context context-type="linenumber">497</context></context-group>
</trans-unit>
- <trans-unit id="_msg108">
+ <trans-unit id="_msg111">
<source xml:space="preserve">&amp;Help</source>
<context-group purpose="location"><context context-type="linenumber">558</context></context-group>
</trans-unit>
- <trans-unit id="_msg109">
+ <trans-unit id="_msg112">
<source xml:space="preserve">Tabs toolbar</source>
<context-group purpose="location"><context context-type="linenumber">569</context></context-group>
</trans-unit>
- <trans-unit id="_msg110">
+ <trans-unit id="_msg113">
<source xml:space="preserve">Syncing Headers (%1%)…</source>
- <context-group purpose="location"><context context-type="linenumber">1026</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1028</context></context-group>
</trans-unit>
- <trans-unit id="_msg111">
+ <trans-unit id="_msg114">
<source xml:space="preserve">Synchronizing with network…</source>
- <context-group purpose="location"><context context-type="linenumber">1084</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1086</context></context-group>
</trans-unit>
- <trans-unit id="_msg112">
+ <trans-unit id="_msg115">
<source xml:space="preserve">Indexing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1089</context></context-group>
- </trans-unit>
- <trans-unit id="_msg113">
- <source xml:space="preserve">Processing blocks on disk…</source>
<context-group purpose="location"><context context-type="linenumber">1091</context></context-group>
</trans-unit>
- <trans-unit id="_msg114">
- <source xml:space="preserve">Reindexing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1095</context></context-group>
+ <trans-unit id="_msg116">
+ <source xml:space="preserve">Processing blocks on disk…</source>
+ <context-group purpose="location"><context context-type="linenumber">1093</context></context-group>
</trans-unit>
- <trans-unit id="_msg115">
+ <trans-unit id="_msg117">
<source xml:space="preserve">Connecting to peers…</source>
- <context-group purpose="location"><context context-type="linenumber">1101</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1100</context></context-group>
</trans-unit>
- <trans-unit id="_msg116">
+ <trans-unit id="_msg118">
<source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source>
<context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg117">
+ <trans-unit id="_msg119">
<source xml:space="preserve">Show the list of used sending addresses and labels</source>
<context-group purpose="location"><context context-type="linenumber">333</context></context-group>
</trans-unit>
- <trans-unit id="_msg118">
+ <trans-unit id="_msg120">
<source xml:space="preserve">Show the list of used receiving addresses and labels</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg119">
+ <trans-unit id="_msg121">
<source xml:space="preserve">&amp;Command-line options</source>
<context-group purpose="location"><context context-type="linenumber">361</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">1110</context></context-group>
- <trans-unit id="_msg120[0]">
+ <context-group purpose="location"><context context-type="linenumber">1109</context></context-group>
+ <trans-unit id="_msg122[0]">
<source xml:space="preserve">Processed %n block(s) of transaction history.</source>
</trans-unit>
- <trans-unit id="_msg120[1]">
+ <trans-unit id="_msg122[1]">
<source xml:space="preserve">Processed %n block(s) of transaction history.</source>
</trans-unit>
</group>
- <trans-unit id="_msg121">
+ <trans-unit id="_msg123">
<source xml:space="preserve">%1 behind</source>
- <context-group purpose="location"><context context-type="linenumber">1133</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1132</context></context-group>
</trans-unit>
- <trans-unit id="_msg122">
+ <trans-unit id="_msg124">
<source xml:space="preserve">Catching up…</source>
- <context-group purpose="location"><context context-type="linenumber">1138</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1137</context></context-group>
</trans-unit>
- <trans-unit id="_msg123">
+ <trans-unit id="_msg125">
<source xml:space="preserve">Last received block was generated %1 ago.</source>
- <context-group purpose="location"><context context-type="linenumber">1157</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1156</context></context-group>
</trans-unit>
- <trans-unit id="_msg124">
+ <trans-unit id="_msg126">
<source xml:space="preserve">Transactions after this will not yet be visible.</source>
- <context-group purpose="location"><context context-type="linenumber">1159</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1158</context></context-group>
</trans-unit>
- <trans-unit id="_msg125">
+ <trans-unit id="_msg127">
<source xml:space="preserve">Error</source>
- <context-group purpose="location"><context context-type="linenumber">1184</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1183</context></context-group>
</trans-unit>
- <trans-unit id="_msg126">
+ <trans-unit id="_msg128">
<source xml:space="preserve">Warning</source>
- <context-group purpose="location"><context context-type="linenumber">1188</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1187</context></context-group>
</trans-unit>
- <trans-unit id="_msg127">
+ <trans-unit id="_msg129">
<source xml:space="preserve">Information</source>
- <context-group purpose="location"><context context-type="linenumber">1192</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1191</context></context-group>
</trans-unit>
- <trans-unit id="_msg128">
+ <trans-unit id="_msg130">
<source xml:space="preserve">Up to date</source>
- <context-group purpose="location"><context context-type="linenumber">1114</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1113</context></context-group>
</trans-unit>
- <trans-unit id="_msg129">
+ <trans-unit id="_msg131">
<source xml:space="preserve">Ctrl+Q</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
- <trans-unit id="_msg130">
+ <trans-unit id="_msg132">
<source xml:space="preserve">Load Partially Signed Bitcoin Transaction</source>
<context-group purpose="location"><context context-type="linenumber">322</context></context-group>
</trans-unit>
- <trans-unit id="_msg131">
+ <trans-unit id="_msg133">
<source xml:space="preserve">Load PSBT from &amp;clipboard…</source>
<context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg132">
+ <trans-unit id="_msg134">
<source xml:space="preserve">Load Partially Signed Bitcoin Transaction from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg133">
+ <trans-unit id="_msg135">
<source xml:space="preserve">Node window</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg134">
+ <trans-unit id="_msg136">
<source xml:space="preserve">Open node debugging and diagnostic console</source>
<context-group purpose="location"><context context-type="linenumber">327</context></context-group>
</trans-unit>
- <trans-unit id="_msg135">
+ <trans-unit id="_msg137">
<source xml:space="preserve">&amp;Sending addresses</source>
<context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg136">
+ <trans-unit id="_msg138">
<source xml:space="preserve">&amp;Receiving addresses</source>
<context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg137">
+ <trans-unit id="_msg139">
<source xml:space="preserve">Open a bitcoin: URI</source>
<context-group purpose="location"><context context-type="linenumber">338</context></context-group>
</trans-unit>
- <trans-unit id="_msg138">
+ <trans-unit id="_msg140">
<source xml:space="preserve">Open Wallet</source>
<context-group purpose="location"><context context-type="linenumber">340</context></context-group>
</trans-unit>
- <trans-unit id="_msg139">
+ <trans-unit id="_msg141">
<source xml:space="preserve">Open a wallet</source>
<context-group purpose="location"><context context-type="linenumber">342</context></context-group>
</trans-unit>
- <trans-unit id="_msg140">
+ <trans-unit id="_msg142">
<source xml:space="preserve">Close wallet</source>
<context-group purpose="location"><context context-type="linenumber">346</context></context-group>
</trans-unit>
- <trans-unit id="_msg141">
+ <trans-unit id="_msg143">
<source xml:space="preserve">Restore Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">353</context></context-group>
<note annotates="source" from="developer">Name of the menu item that restores wallet from a backup file.</note>
</trans-unit>
- <trans-unit id="_msg142">
+ <trans-unit id="_msg144">
<source xml:space="preserve">Restore a wallet from a backup file</source>
<context-group purpose="location"><context context-type="linenumber">356</context></context-group>
<note annotates="source" from="developer">Status tip for Restore Wallet menu item</note>
</trans-unit>
- <trans-unit id="_msg143">
+ <trans-unit id="_msg145">
<source xml:space="preserve">Close all wallets</source>
<context-group purpose="location"><context context-type="linenumber">359</context></context-group>
</trans-unit>
- <trans-unit id="_msg144">
+ <trans-unit id="_msg146">
<source xml:space="preserve">Show the %1 help message to get a list with possible Bitcoin command-line options</source>
<context-group purpose="location"><context context-type="linenumber">363</context></context-group>
</trans-unit>
- <trans-unit id="_msg145">
+ <trans-unit id="_msg147">
<source xml:space="preserve">&amp;Mask values</source>
<context-group purpose="location"><context context-type="linenumber">365</context></context-group>
</trans-unit>
- <trans-unit id="_msg146">
+ <trans-unit id="_msg148">
<source xml:space="preserve">Mask the values in the Overview tab</source>
<context-group purpose="location"><context context-type="linenumber">367</context></context-group>
</trans-unit>
- <trans-unit id="_msg147">
+ <trans-unit id="_msg149">
<source xml:space="preserve">default wallet</source>
<context-group purpose="location"><context context-type="linenumber">398</context></context-group>
</trans-unit>
- <trans-unit id="_msg148">
+ <trans-unit id="_msg150">
<source xml:space="preserve">No wallets available</source>
<context-group purpose="location"><context context-type="linenumber">418</context></context-group>
</trans-unit>
- <trans-unit id="_msg149">
+ <trans-unit id="_msg151">
<source xml:space="preserve">Wallet Data</source>
<context-group purpose="location"><context context-type="linenumber">424</context></context-group>
<note annotates="source" from="developer">Name of the wallet data file format.</note>
</trans-unit>
- <trans-unit id="_msg150">
+ <trans-unit id="_msg152">
<source xml:space="preserve">Load Wallet Backup</source>
<context-group purpose="location"><context context-type="linenumber">427</context></context-group>
<note annotates="source" from="developer">The title for Restore Wallet File Windows</note>
</trans-unit>
- <trans-unit id="_msg151">
+ <trans-unit id="_msg153">
<source xml:space="preserve">Restore Wallet</source>
<context-group purpose="location"><context context-type="linenumber">435</context></context-group>
<note annotates="source" from="developer">Title of pop-up window shown when the user is attempting to restore a wallet.</note>
</trans-unit>
- <trans-unit id="_msg152">
+ <trans-unit id="_msg154">
<source xml:space="preserve">Wallet Name</source>
<context-group purpose="location"><context context-type="linenumber">437</context></context-group>
<note annotates="source" from="developer">Label of the input field where the name of the wallet is entered.</note>
</trans-unit>
- <trans-unit id="_msg153">
+ <trans-unit id="_msg155">
<source xml:space="preserve">&amp;Window</source>
<context-group purpose="location"><context context-type="linenumber">508</context></context-group>
</trans-unit>
- <trans-unit id="_msg154">
+ <trans-unit id="_msg156">
<source xml:space="preserve">Ctrl+M</source>
<context-group purpose="location"><context context-type="linenumber">511</context></context-group>
</trans-unit>
- <trans-unit id="_msg155">
+ <trans-unit id="_msg157">
<source xml:space="preserve">Zoom</source>
<context-group purpose="location"><context context-type="linenumber">520</context></context-group>
</trans-unit>
- <trans-unit id="_msg156">
+ <trans-unit id="_msg158">
<source xml:space="preserve">Main Window</source>
<context-group purpose="location"><context context-type="linenumber">538</context></context-group>
</trans-unit>
- <trans-unit id="_msg157">
+ <trans-unit id="_msg159">
<source xml:space="preserve">%1 client</source>
- <context-group purpose="location"><context context-type="linenumber">796</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">798</context></context-group>
</trans-unit>
- <trans-unit id="_msg158">
+ <trans-unit id="_msg160">
<source xml:space="preserve">&amp;Hide</source>
- <context-group purpose="location"><context context-type="linenumber">861</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">863</context></context-group>
</trans-unit>
- <trans-unit id="_msg159">
+ <trans-unit id="_msg161">
<source xml:space="preserve">S&amp;how</source>
- <context-group purpose="location"><context context-type="linenumber">862</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">864</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">979</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">981</context></context-group>
<note annotates="source" from="developer">A substring of the tooltip.</note>
- <trans-unit id="_msg160[0]">
+ <trans-unit id="_msg162[0]">
<source xml:space="preserve">%n active connection(s) to Bitcoin network.</source>
</trans-unit>
- <trans-unit id="_msg160[1]">
+ <trans-unit id="_msg162[1]">
<source xml:space="preserve">%n active connection(s) to Bitcoin network.</source>
</trans-unit>
</group>
- <trans-unit id="_msg161">
+ <trans-unit id="_msg163">
<source xml:space="preserve">Click for more actions.</source>
- <context-group purpose="location"><context context-type="linenumber">989</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">991</context></context-group>
<note annotates="source" from="developer">A substring of the tooltip. &quot;More actions&quot; are available via the context menu.</note>
</trans-unit>
- <trans-unit id="_msg162">
+ <trans-unit id="_msg164">
<source xml:space="preserve">Show Peers tab</source>
- <context-group purpose="location"><context context-type="linenumber">1006</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1008</context></context-group>
<note annotates="source" from="developer">A context menu item. The &quot;Peers tab&quot; is an element of the &quot;Node window&quot;.</note>
</trans-unit>
- <trans-unit id="_msg163">
+ <trans-unit id="_msg165">
<source xml:space="preserve">Disable network activity</source>
- <context-group purpose="location"><context context-type="linenumber">1014</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1016</context></context-group>
<note annotates="source" from="developer">A context menu item.</note>
</trans-unit>
- <trans-unit id="_msg164">
+ <trans-unit id="_msg166">
<source xml:space="preserve">Enable network activity</source>
- <context-group purpose="location"><context context-type="linenumber">1016</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1018</context></context-group>
<note annotates="source" from="developer">A context menu item. The network activity was disabled previously.</note>
</trans-unit>
- <trans-unit id="_msg165">
+ <trans-unit id="_msg167">
<source xml:space="preserve">Pre-syncing Headers (%1%)…</source>
- <context-group purpose="location"><context context-type="linenumber">1033</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1035</context></context-group>
</trans-unit>
- <trans-unit id="_msg166">
+ <trans-unit id="_msg168">
<source xml:space="preserve">Error: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1185</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1184</context></context-group>
</trans-unit>
- <trans-unit id="_msg167">
+ <trans-unit id="_msg169">
<source xml:space="preserve">Warning: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1189</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1188</context></context-group>
</trans-unit>
- <trans-unit id="_msg168">
+ <trans-unit id="_msg170">
<source xml:space="preserve">Date: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1297</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1296</context></context-group>
</trans-unit>
- <trans-unit id="_msg169">
+ <trans-unit id="_msg171">
<source xml:space="preserve">Amount: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1298</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1297</context></context-group>
</trans-unit>
- <trans-unit id="_msg170">
+ <trans-unit id="_msg172">
<source xml:space="preserve">Wallet: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1300</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1299</context></context-group>
</trans-unit>
- <trans-unit id="_msg171">
+ <trans-unit id="_msg173">
<source xml:space="preserve">Type: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1302</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1301</context></context-group>
</trans-unit>
- <trans-unit id="_msg172">
+ <trans-unit id="_msg174">
<source xml:space="preserve">Label: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1304</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1303</context></context-group>
</trans-unit>
- <trans-unit id="_msg173">
+ <trans-unit id="_msg175">
<source xml:space="preserve">Address: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1306</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1305</context></context-group>
</trans-unit>
- <trans-unit id="_msg174">
+ <trans-unit id="_msg176">
<source xml:space="preserve">Sent transaction</source>
- <context-group purpose="location"><context context-type="linenumber">1307</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1306</context></context-group>
</trans-unit>
- <trans-unit id="_msg175">
+ <trans-unit id="_msg177">
<source xml:space="preserve">Incoming transaction</source>
- <context-group purpose="location"><context context-type="linenumber">1307</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1306</context></context-group>
</trans-unit>
- <trans-unit id="_msg176">
+ <trans-unit id="_msg178">
<source xml:space="preserve">HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1359</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
</trans-unit>
- <trans-unit id="_msg177">
+ <trans-unit id="_msg179">
<source xml:space="preserve">HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1359</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
</trans-unit>
- <trans-unit id="_msg178">
+ <trans-unit id="_msg180">
<source xml:space="preserve">Private key &lt;b&gt;disabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1359</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
</trans-unit>
- <trans-unit id="_msg179">
+ <trans-unit id="_msg181">
<source xml:space="preserve">Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1382</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1381</context></context-group>
</trans-unit>
- <trans-unit id="_msg180">
+ <trans-unit id="_msg182">
<source xml:space="preserve">Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1390</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1389</context></context-group>
</trans-unit>
- <trans-unit id="_msg181">
+ <trans-unit id="_msg183">
<source xml:space="preserve">Original message:</source>
- <context-group purpose="location"><context context-type="linenumber">1509</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1508</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="UnitDisplayStatusBarControl">
- <trans-unit id="_msg182">
+ <trans-unit id="_msg184">
<source xml:space="preserve">Unit to show amounts in. Click to select another unit.</source>
- <context-group purpose="location"><context context-type="linenumber">1550</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1547</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/coincontroldialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CoinControlDialog">
- <trans-unit id="_msg183">
+ <trans-unit id="_msg185">
<source xml:space="preserve">Coin Selection</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg184">
+ <trans-unit id="_msg186">
<source xml:space="preserve">Quantity:</source>
<context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
- <trans-unit id="_msg185">
+ <trans-unit id="_msg187">
<source xml:space="preserve">Bytes:</source>
<context-group purpose="location"><context context-type="linenumber">77</context></context-group>
</trans-unit>
- <trans-unit id="_msg186">
+ <trans-unit id="_msg188">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg187">
+ <trans-unit id="_msg189">
<source xml:space="preserve">Fee:</source>
<context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
- <trans-unit id="_msg188">
+ <trans-unit id="_msg190">
<source xml:space="preserve">Dust:</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
</trans-unit>
- <trans-unit id="_msg189">
+ <trans-unit id="_msg191">
<source xml:space="preserve">After Fee:</source>
<context-group purpose="location"><context context-type="linenumber">247</context></context-group>
</trans-unit>
- <trans-unit id="_msg190">
+ <trans-unit id="_msg192">
<source xml:space="preserve">Change:</source>
<context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg191">
+ <trans-unit id="_msg193">
<source xml:space="preserve">(un)select all</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg192">
+ <trans-unit id="_msg194">
<source xml:space="preserve">Tree mode</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg193">
+ <trans-unit id="_msg195">
<source xml:space="preserve">List mode</source>
<context-group purpose="location"><context context-type="linenumber">364</context></context-group>
</trans-unit>
- <trans-unit id="_msg194">
+ <trans-unit id="_msg196">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">420</context></context-group>
</trans-unit>
- <trans-unit id="_msg195">
+ <trans-unit id="_msg197">
<source xml:space="preserve">Received with label</source>
<context-group purpose="location"><context context-type="linenumber">425</context></context-group>
</trans-unit>
- <trans-unit id="_msg196">
+ <trans-unit id="_msg198">
<source xml:space="preserve">Received with address</source>
<context-group purpose="location"><context context-type="linenumber">430</context></context-group>
</trans-unit>
- <trans-unit id="_msg197">
+ <trans-unit id="_msg199">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">435</context></context-group>
</trans-unit>
- <trans-unit id="_msg198">
+ <trans-unit id="_msg200">
<source xml:space="preserve">Confirmations</source>
<context-group purpose="location"><context context-type="linenumber">440</context></context-group>
</trans-unit>
- <trans-unit id="_msg199">
+ <trans-unit id="_msg201">
<source xml:space="preserve">Confirmed</source>
<context-group purpose="location"><context context-type="linenumber">443</context></context-group>
</trans-unit>
@@ -882,88 +891,88 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../coincontroldialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CoinControlDialog">
- <trans-unit id="_msg200">
+ <trans-unit id="_msg202">
<source xml:space="preserve">Copy amount</source>
<context-group purpose="location"><context context-type="linenumber">69</context></context-group>
</trans-unit>
- <trans-unit id="_msg201">
+ <trans-unit id="_msg203">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg202">
+ <trans-unit id="_msg204">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">59</context></context-group>
</trans-unit>
- <trans-unit id="_msg203">
+ <trans-unit id="_msg205">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg204">
+ <trans-unit id="_msg206">
<source xml:space="preserve">Copy transaction &amp;ID and output index</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg205">
+ <trans-unit id="_msg207">
<source xml:space="preserve">L&amp;ock unspent</source>
<context-group purpose="location"><context context-type="linenumber">63</context></context-group>
</trans-unit>
- <trans-unit id="_msg206">
+ <trans-unit id="_msg208">
<source xml:space="preserve">&amp;Unlock unspent</source>
<context-group purpose="location"><context context-type="linenumber">64</context></context-group>
</trans-unit>
- <trans-unit id="_msg207">
+ <trans-unit id="_msg209">
<source xml:space="preserve">Copy quantity</source>
<context-group purpose="location"><context context-type="linenumber">68</context></context-group>
</trans-unit>
- <trans-unit id="_msg208">
+ <trans-unit id="_msg210">
<source xml:space="preserve">Copy fee</source>
<context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg209">
+ <trans-unit id="_msg211">
<source xml:space="preserve">Copy after fee</source>
<context-group purpose="location"><context context-type="linenumber">71</context></context-group>
</trans-unit>
- <trans-unit id="_msg210">
+ <trans-unit id="_msg212">
<source xml:space="preserve">Copy bytes</source>
<context-group purpose="location"><context context-type="linenumber">72</context></context-group>
</trans-unit>
- <trans-unit id="_msg211">
+ <trans-unit id="_msg213">
<source xml:space="preserve">Copy dust</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg212">
+ <trans-unit id="_msg214">
<source xml:space="preserve">Copy change</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
- <trans-unit id="_msg213">
+ <trans-unit id="_msg215">
<source xml:space="preserve">(%1 locked)</source>
<context-group purpose="location"><context context-type="linenumber">380</context></context-group>
</trans-unit>
- <trans-unit id="_msg214">
+ <trans-unit id="_msg216">
<source xml:space="preserve">yes</source>
<context-group purpose="location"><context context-type="linenumber">534</context></context-group>
</trans-unit>
- <trans-unit id="_msg215">
+ <trans-unit id="_msg217">
<source xml:space="preserve">no</source>
<context-group purpose="location"><context context-type="linenumber">534</context></context-group>
</trans-unit>
- <trans-unit id="_msg216">
+ <trans-unit id="_msg218">
<source xml:space="preserve">This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
<context-group purpose="location"><context context-type="linenumber">548</context></context-group>
</trans-unit>
- <trans-unit id="_msg217">
+ <trans-unit id="_msg219">
<source xml:space="preserve">Can vary +/- %1 satoshi(s) per input.</source>
<context-group purpose="location"><context context-type="linenumber">553</context></context-group>
</trans-unit>
- <trans-unit id="_msg218">
+ <trans-unit id="_msg220">
<source xml:space="preserve">(no label)</source>
<context-group purpose="location"><context context-type="linenumber">600</context></context-group>
<context-group purpose="location"><context context-type="linenumber">654</context></context-group>
</trans-unit>
- <trans-unit id="_msg219">
+ <trans-unit id="_msg221">
<source xml:space="preserve">change from %1 (%2)</source>
<context-group purpose="location"><context context-type="linenumber">647</context></context-group>
</trans-unit>
- <trans-unit id="_msg220">
+ <trans-unit id="_msg222">
<source xml:space="preserve">(change)</source>
<context-group purpose="location"><context context-type="linenumber">648</context></context-group>
</trans-unit>
@@ -971,114 +980,114 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../walletcontroller.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletActivity">
- <trans-unit id="_msg221">
+ <trans-unit id="_msg223">
<source xml:space="preserve">Create Wallet</source>
<context-group purpose="location"><context context-type="linenumber">244</context></context-group>
<note annotates="source" from="developer">Title of window indicating the progress of creation of a new wallet.</note>
</trans-unit>
- <trans-unit id="_msg222">
+ <trans-unit id="_msg224">
<source xml:space="preserve">Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<context-group purpose="location"><context context-type="linenumber">247</context></context-group>
<note annotates="source" from="developer">Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</note>
</trans-unit>
- <trans-unit id="_msg223">
+ <trans-unit id="_msg225">
<source xml:space="preserve">Create wallet failed</source>
<context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
- <trans-unit id="_msg224">
+ <trans-unit id="_msg226">
<source xml:space="preserve">Create wallet warning</source>
<context-group purpose="location"><context context-type="linenumber">282</context></context-group>
</trans-unit>
- <trans-unit id="_msg225">
+ <trans-unit id="_msg227">
<source xml:space="preserve">Can&apos;t list signers</source>
<context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg226">
+ <trans-unit id="_msg228">
<source xml:space="preserve">Too many external signers found</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="LoadWalletsActivity">
- <trans-unit id="_msg227">
+ <trans-unit id="_msg229">
<source xml:space="preserve">Load Wallets</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
<note annotates="source" from="developer">Title of progress window which is displayed when wallets are being loaded.</note>
</trans-unit>
- <trans-unit id="_msg228">
+ <trans-unit id="_msg230">
<source xml:space="preserve">Loading wallets…</source>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
<note annotates="source" from="developer">Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="OpenWalletActivity">
- <trans-unit id="_msg229">
+ <trans-unit id="_msg231">
<source xml:space="preserve">Open wallet failed</source>
<context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg230">
+ <trans-unit id="_msg232">
<source xml:space="preserve">Open wallet warning</source>
<context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg231">
+ <trans-unit id="_msg233">
<source xml:space="preserve">default wallet</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg232">
+ <trans-unit id="_msg234">
<source xml:space="preserve">Open Wallet</source>
<context-group purpose="location"><context context-type="linenumber">348</context></context-group>
<note annotates="source" from="developer">Title of window indicating the progress of opening of a wallet.</note>
</trans-unit>
- <trans-unit id="_msg233">
+ <trans-unit id="_msg235">
<source xml:space="preserve">Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
<note annotates="source" from="developer">Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="RestoreWalletActivity">
- <trans-unit id="_msg234">
+ <trans-unit id="_msg236">
<source xml:space="preserve">Restore Wallet</source>
<context-group purpose="location"><context context-type="linenumber">400</context></context-group>
<note annotates="source" from="developer">Title of progress window which is displayed when wallets are being restored.</note>
</trans-unit>
- <trans-unit id="_msg235">
+ <trans-unit id="_msg237">
<source xml:space="preserve">Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<context-group purpose="location"><context context-type="linenumber">403</context></context-group>
<note annotates="source" from="developer">Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</note>
</trans-unit>
- <trans-unit id="_msg236">
+ <trans-unit id="_msg238">
<source xml:space="preserve">Restore wallet failed</source>
<context-group purpose="location"><context context-type="linenumber">422</context></context-group>
<note annotates="source" from="developer">Title of message box which is displayed when the wallet could not be restored.</note>
</trans-unit>
- <trans-unit id="_msg237">
+ <trans-unit id="_msg239">
<source xml:space="preserve">Restore wallet warning</source>
<context-group purpose="location"><context context-type="linenumber">425</context></context-group>
<note annotates="source" from="developer">Title of message box which is displayed when the wallet is restored with some warning.</note>
</trans-unit>
- <trans-unit id="_msg238">
+ <trans-unit id="_msg240">
<source xml:space="preserve">Restore wallet message</source>
<context-group purpose="location"><context context-type="linenumber">428</context></context-group>
<note annotates="source" from="developer">Title of message box which is displayed when the wallet is successfully restored.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="WalletController">
- <trans-unit id="_msg239">
+ <trans-unit id="_msg241">
<source xml:space="preserve">Close wallet</source>
<context-group purpose="location"><context context-type="linenumber">84</context></context-group>
</trans-unit>
- <trans-unit id="_msg240">
+ <trans-unit id="_msg242">
<source xml:space="preserve">Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg241">
+ <trans-unit id="_msg243">
<source xml:space="preserve">Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg242">
+ <trans-unit id="_msg244">
<source xml:space="preserve">Close all wallets</source>
<context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg243">
+ <trans-unit id="_msg245">
<source xml:space="preserve">Are you sure you wish to close all wallets?</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
@@ -1086,59 +1095,59 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/createwalletdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletDialog">
- <trans-unit id="_msg244">
+ <trans-unit id="_msg246">
<source xml:space="preserve">Create Wallet</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg245">
+ <trans-unit id="_msg247">
<source xml:space="preserve">Wallet Name</source>
<context-group purpose="location"><context context-type="linenumber">25</context></context-group>
</trans-unit>
- <trans-unit id="_msg246">
+ <trans-unit id="_msg248">
<source xml:space="preserve">Wallet</source>
<context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg247">
+ <trans-unit id="_msg249">
<source xml:space="preserve">Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
<context-group purpose="location"><context context-type="linenumber">47</context></context-group>
</trans-unit>
- <trans-unit id="_msg248">
+ <trans-unit id="_msg250">
<source xml:space="preserve">Encrypt Wallet</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg249">
+ <trans-unit id="_msg251">
<source xml:space="preserve">Advanced Options</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg250">
+ <trans-unit id="_msg252">
<source xml:space="preserve">Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg251">
+ <trans-unit id="_msg253">
<source xml:space="preserve">Disable Private Keys</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
</trans-unit>
- <trans-unit id="_msg252">
+ <trans-unit id="_msg254">
<source xml:space="preserve">Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg253">
+ <trans-unit id="_msg255">
<source xml:space="preserve">Make Blank Wallet</source>
<context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg254">
+ <trans-unit id="_msg256">
<source xml:space="preserve">Use descriptors for scriptPubKey management</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg255">
+ <trans-unit id="_msg257">
<source xml:space="preserve">Descriptor Wallet</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
- <trans-unit id="_msg256">
+ <trans-unit id="_msg258">
<source xml:space="preserve">Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
<context-group purpose="location"><context context-type="linenumber">118</context></context-group>
</trans-unit>
- <trans-unit id="_msg257">
+ <trans-unit id="_msg259">
<source xml:space="preserve">External signer</source>
<context-group purpose="location"><context context-type="linenumber">121</context></context-group>
</trans-unit>
@@ -1146,15 +1155,15 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../createwalletdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletDialog">
- <trans-unit id="_msg258">
+ <trans-unit id="_msg260">
<source xml:space="preserve">Create</source>
<context-group purpose="location"><context context-type="linenumber">22</context></context-group>
</trans-unit>
- <trans-unit id="_msg259">
+ <trans-unit id="_msg261">
<source xml:space="preserve">Compiled without sqlite support (required for descriptor wallets)</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg260">
+ <trans-unit id="_msg262">
<source xml:space="preserve">Compiled without external signing support (required for external signing)</source>
<context-group purpose="location"><context context-type="linenumber">104</context></context-group>
<note annotates="source" from="developer">&quot;External signing&quot; means using devices such as hardware wallets.</note>
@@ -1163,23 +1172,23 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/editaddressdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="EditAddressDialog">
- <trans-unit id="_msg261">
+ <trans-unit id="_msg263">
<source xml:space="preserve">Edit Address</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg262">
+ <trans-unit id="_msg264">
<source xml:space="preserve">&amp;Label</source>
<context-group purpose="location"><context context-type="linenumber">25</context></context-group>
</trans-unit>
- <trans-unit id="_msg263">
+ <trans-unit id="_msg265">
<source xml:space="preserve">The label associated with this address list entry</source>
<context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg264">
+ <trans-unit id="_msg266">
<source xml:space="preserve">The address associated with this address list entry. This can only be modified for sending addresses.</source>
<context-group purpose="location"><context context-type="linenumber">52</context></context-group>
</trans-unit>
- <trans-unit id="_msg265">
+ <trans-unit id="_msg267">
<source xml:space="preserve">&amp;Address</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
@@ -1187,152 +1196,152 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../editaddressdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="EditAddressDialog">
- <trans-unit id="_msg266">
+ <trans-unit id="_msg268">
<source xml:space="preserve">New sending address</source>
- <context-group purpose="location"><context context-type="linenumber">29</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg267">
+ <trans-unit id="_msg269">
<source xml:space="preserve">Edit receiving address</source>
- <context-group purpose="location"><context context-type="linenumber">32</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">30</context></context-group>
</trans-unit>
- <trans-unit id="_msg268">
+ <trans-unit id="_msg270">
<source xml:space="preserve">Edit sending address</source>
- <context-group purpose="location"><context context-type="linenumber">36</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">34</context></context-group>
</trans-unit>
- <trans-unit id="_msg269">
+ <trans-unit id="_msg271">
<source xml:space="preserve">The entered address &quot;%1&quot; is not a valid Bitcoin address.</source>
- <context-group purpose="location"><context context-type="linenumber">113</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg270">
+ <trans-unit id="_msg272">
<source xml:space="preserve">Address &quot;%1&quot; already exists as a receiving address with label &quot;%2&quot; and so cannot be added as a sending address.</source>
- <context-group purpose="location"><context context-type="linenumber">146</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg271">
+ <trans-unit id="_msg273">
<source xml:space="preserve">The entered address &quot;%1&quot; is already in the address book with label &quot;%2&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">151</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">149</context></context-group>
</trans-unit>
- <trans-unit id="_msg272">
+ <trans-unit id="_msg274">
<source xml:space="preserve">Could not unlock wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">121</context></context-group>
</trans-unit>
- <trans-unit id="_msg273">
+ <trans-unit id="_msg275">
<source xml:space="preserve">New key generation failed.</source>
- <context-group purpose="location"><context context-type="linenumber">128</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">126</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../intro.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="FreespaceChecker">
- <trans-unit id="_msg274">
+ <trans-unit id="_msg276">
<source xml:space="preserve">A new data directory will be created.</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg275">
+ <trans-unit id="_msg277">
<source xml:space="preserve">name</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg276">
+ <trans-unit id="_msg278">
<source xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</source>
<context-group purpose="location"><context context-type="linenumber">97</context></context-group>
</trans-unit>
- <trans-unit id="_msg277">
+ <trans-unit id="_msg279">
<source xml:space="preserve">Path already exists, and is not a directory.</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
- <trans-unit id="_msg278">
+ <trans-unit id="_msg280">
<source xml:space="preserve">Cannot create data directory here.</source>
<context-group purpose="location"><context context-type="linenumber">107</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="Intro">
- <trans-unit id="_msg279">
+ <trans-unit id="_msg281">
<source xml:space="preserve">Bitcoin</source>
- <context-group purpose="location"><context context-type="linenumber">139</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">137</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">301</context></context-group>
- <trans-unit id="_msg280[0]">
+ <context-group purpose="location"><context context-type="linenumber">299</context></context-group>
+ <trans-unit id="_msg282[0]">
<source xml:space="preserve">%n GB of space available</source>
</trans-unit>
- <trans-unit id="_msg280[1]">
+ <trans-unit id="_msg282[1]">
<source xml:space="preserve">%n GB of space available</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">303</context></context-group>
- <trans-unit id="_msg281[0]">
+ <context-group purpose="location"><context context-type="linenumber">301</context></context-group>
+ <trans-unit id="_msg283[0]">
<source xml:space="preserve">(of %n GB needed)</source>
</trans-unit>
- <trans-unit id="_msg281[1]">
+ <trans-unit id="_msg283[1]">
<source xml:space="preserve">(of %n GB needed)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">306</context></context-group>
- <trans-unit id="_msg282[0]">
+ <context-group purpose="location"><context context-type="linenumber">304</context></context-group>
+ <trans-unit id="_msg284[0]">
<source xml:space="preserve">(%n GB needed for full chain)</source>
</trans-unit>
- <trans-unit id="_msg282[1]">
+ <trans-unit id="_msg284[1]">
<source xml:space="preserve">(%n GB needed for full chain)</source>
</trans-unit>
</group>
- <trans-unit id="_msg283">
+ <trans-unit id="_msg285">
<source xml:space="preserve">At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
- <context-group purpose="location"><context context-type="linenumber">378</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg284">
+ <trans-unit id="_msg286">
<source xml:space="preserve">Approximately %1 GB of data will be stored in this directory.</source>
- <context-group purpose="location"><context context-type="linenumber">381</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">379</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">390</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">388</context></context-group>
<note annotates="source" from="developer">Explanatory text on the capability of the current prune target.</note>
- <trans-unit id="_msg285[0]">
+ <trans-unit id="_msg287[0]">
<source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source>
</trans-unit>
- <trans-unit id="_msg285[1]">
+ <trans-unit id="_msg287[1]">
<source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source>
</trans-unit>
</group>
- <trans-unit id="_msg286">
+ <trans-unit id="_msg288">
<source xml:space="preserve">%1 will download and store a copy of the Bitcoin block chain.</source>
- <context-group purpose="location"><context context-type="linenumber">392</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">390</context></context-group>
</trans-unit>
- <trans-unit id="_msg287">
+ <trans-unit id="_msg289">
<source xml:space="preserve">The wallet will also be stored in this directory.</source>
- <context-group purpose="location"><context context-type="linenumber">394</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">392</context></context-group>
</trans-unit>
- <trans-unit id="_msg288">
+ <trans-unit id="_msg290">
<source xml:space="preserve">Error: Specified data directory &quot;%1&quot; cannot be created.</source>
- <context-group purpose="location"><context context-type="linenumber">250</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg289">
+ <trans-unit id="_msg291">
<source xml:space="preserve">Error</source>
- <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">278</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../utilitydialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="HelpMessageDialog">
- <trans-unit id="_msg290">
+ <trans-unit id="_msg292">
<source xml:space="preserve">version</source>
<context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg291">
+ <trans-unit id="_msg293">
<source xml:space="preserve">About %1</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
- <trans-unit id="_msg292">
+ <trans-unit id="_msg294">
<source xml:space="preserve">Command-line options</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="ShutdownWindow">
- <trans-unit id="_msg293">
+ <trans-unit id="_msg295">
<source xml:space="preserve">%1 is shutting down…</source>
<context-group purpose="location"><context context-type="linenumber">145</context></context-group>
</trans-unit>
- <trans-unit id="_msg294">
+ <trans-unit id="_msg296">
<source xml:space="preserve">Do not shut down the computer until this window disappears.</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
@@ -1340,47 +1349,47 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/intro.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="Intro">
- <trans-unit id="_msg295">
+ <trans-unit id="_msg297">
<source xml:space="preserve">Welcome</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg296">
+ <trans-unit id="_msg298">
<source xml:space="preserve">Welcome to %1.</source>
<context-group purpose="location"><context context-type="linenumber">23</context></context-group>
</trans-unit>
- <trans-unit id="_msg297">
+ <trans-unit id="_msg299">
<source xml:space="preserve">As this is the first time the program is launched, you can choose where %1 will store its data.</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg298">
+ <trans-unit id="_msg300">
<source xml:space="preserve">Limit block chain storage to</source>
<context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg299">
+ <trans-unit id="_msg301">
<source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg300">
+ <trans-unit id="_msg302">
<source xml:space="preserve"> GB</source>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg301">
+ <trans-unit id="_msg303">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg302">
+ <trans-unit id="_msg304">
<source xml:space="preserve">When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
<context-group purpose="location"><context context-type="linenumber">206</context></context-group>
</trans-unit>
- <trans-unit id="_msg303">
+ <trans-unit id="_msg305">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg304">
+ <trans-unit id="_msg306">
<source xml:space="preserve">Use the default data directory</source>
<context-group purpose="location"><context context-type="linenumber">66</context></context-group>
</trans-unit>
- <trans-unit id="_msg305">
+ <trans-unit id="_msg307">
<source xml:space="preserve">Use a custom data directory:</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
@@ -1388,54 +1397,54 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/modaloverlay.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ModalOverlay">
- <trans-unit id="_msg306">
+ <trans-unit id="_msg308">
<source xml:space="preserve">Form</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg307">
+ <trans-unit id="_msg309">
<source xml:space="preserve">Recent transactions may not yet be visible, and therefore your wallet&apos;s balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
<context-group purpose="location"><context context-type="linenumber">133</context></context-group>
</trans-unit>
- <trans-unit id="_msg308">
+ <trans-unit id="_msg310">
<source xml:space="preserve">Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
<context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg309">
+ <trans-unit id="_msg311">
<source xml:space="preserve">Number of blocks left</source>
<context-group purpose="location"><context context-type="linenumber">215</context></context-group>
</trans-unit>
- <trans-unit id="_msg310">
+ <trans-unit id="_msg312">
<source xml:space="preserve">Unknown…</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
- <context-group purpose="location"><context context-type="sourcefile">../modaloverlay.cpp</context><context context-type="linenumber">155</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../modaloverlay.cpp</context><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg311">
+ <trans-unit id="_msg313">
<source xml:space="preserve">calculating…</source>
<context-group purpose="location"><context context-type="linenumber">292</context></context-group>
<context-group purpose="location"><context context-type="linenumber">312</context></context-group>
</trans-unit>
- <trans-unit id="_msg312">
+ <trans-unit id="_msg314">
<source xml:space="preserve">Last block time</source>
<context-group purpose="location"><context context-type="linenumber">235</context></context-group>
</trans-unit>
- <trans-unit id="_msg313">
+ <trans-unit id="_msg315">
<source xml:space="preserve">Progress</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg314">
+ <trans-unit id="_msg316">
<source xml:space="preserve">Progress increase per hour</source>
<context-group purpose="location"><context context-type="linenumber">285</context></context-group>
</trans-unit>
- <trans-unit id="_msg315">
+ <trans-unit id="_msg317">
<source xml:space="preserve">Estimated time left until synced</source>
<context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
- <trans-unit id="_msg316">
+ <trans-unit id="_msg318">
<source xml:space="preserve">Hide</source>
<context-group purpose="location"><context context-type="linenumber">342</context></context-group>
</trans-unit>
- <trans-unit id="_msg317">
+ <trans-unit id="_msg319">
<source xml:space="preserve">Esc</source>
<context-group purpose="location"><context context-type="linenumber">345</context></context-group>
</trans-unit>
@@ -1443,37 +1452,37 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../modaloverlay.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ModalOverlay">
- <trans-unit id="_msg318">
+ <trans-unit id="_msg320">
<source xml:space="preserve">%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
- <context-group purpose="location"><context context-type="linenumber">34</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">31</context></context-group>
</trans-unit>
- <trans-unit id="_msg319">
+ <trans-unit id="_msg321">
<source xml:space="preserve">Unknown. Syncing Headers (%1, %2%)…</source>
- <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg320">
+ <trans-unit id="_msg322">
<source xml:space="preserve">Unknown. Pre-syncing Headers (%1, %2%)…</source>
- <context-group purpose="location"><context context-type="linenumber">166</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">163</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg321">
+ <trans-unit id="_msg323">
<source xml:space="preserve">unknown</source>
- <context-group purpose="location"><context context-type="linenumber">126</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/openuridialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OpenURIDialog">
- <trans-unit id="_msg322">
+ <trans-unit id="_msg324">
<source xml:space="preserve">Open bitcoin URI</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg323">
+ <trans-unit id="_msg325">
<source xml:space="preserve">URI:</source>
<context-group purpose="location"><context context-type="linenumber">22</context></context-group>
</trans-unit>
- <trans-unit id="_msg324">
+ <trans-unit id="_msg326">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
<note annotates="source" from="developer">Tooltip text for button that allows you to paste an address that is in your clipboard.</note>
@@ -1482,310 +1491,310 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/optionsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsDialog">
- <trans-unit id="_msg325">
+ <trans-unit id="_msg327">
<source xml:space="preserve">Options</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg326">
+ <trans-unit id="_msg328">
<source xml:space="preserve">&amp;Main</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg327">
+ <trans-unit id="_msg329">
<source xml:space="preserve">Automatically start %1 after logging in to the system.</source>
<context-group purpose="location"><context context-type="linenumber">33</context></context-group>
</trans-unit>
- <trans-unit id="_msg328">
+ <trans-unit id="_msg330">
<source xml:space="preserve">&amp;Start %1 on system login</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
</trans-unit>
- <trans-unit id="_msg329">
+ <trans-unit id="_msg331">
<source xml:space="preserve">Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg330">
+ <trans-unit id="_msg332">
<source xml:space="preserve">Size of &amp;database cache</source>
<context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg331">
+ <trans-unit id="_msg333">
<source xml:space="preserve">Number of script &amp;verification threads</source>
<context-group purpose="location"><context context-type="linenumber">157</context></context-group>
</trans-unit>
- <trans-unit id="_msg332">
+ <trans-unit id="_msg334">
+ <source xml:space="preserve">Full path to a %1 compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg335">
<source xml:space="preserve">IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
<context-group purpose="location"><context context-type="linenumber">388</context></context-group>
<context-group purpose="location"><context context-type="linenumber">575</context></context-group>
</trans-unit>
- <trans-unit id="_msg333">
+ <trans-unit id="_msg336">
<source xml:space="preserve">Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
<context-group purpose="location"><context context-type="linenumber">457</context></context-group>
<context-group purpose="location"><context context-type="linenumber">480</context></context-group>
<context-group purpose="location"><context context-type="linenumber">503</context></context-group>
</trans-unit>
- <trans-unit id="_msg334">
+ <trans-unit id="_msg337">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">672</context></context-group>
</trans-unit>
- <trans-unit id="_msg335">
+ <trans-unit id="_msg338">
<source xml:space="preserve">Options set in this dialog are overridden by the command line:</source>
<context-group purpose="location"><context context-type="linenumber">899</context></context-group>
</trans-unit>
- <trans-unit id="_msg336">
+ <trans-unit id="_msg339">
<source xml:space="preserve">Open the %1 configuration file from the working directory.</source>
<context-group purpose="location"><context context-type="linenumber">944</context></context-group>
</trans-unit>
- <trans-unit id="_msg337">
+ <trans-unit id="_msg340">
<source xml:space="preserve">Open Configuration File</source>
<context-group purpose="location"><context context-type="linenumber">947</context></context-group>
</trans-unit>
- <trans-unit id="_msg338">
+ <trans-unit id="_msg341">
<source xml:space="preserve">Reset all client options to default.</source>
<context-group purpose="location"><context context-type="linenumber">957</context></context-group>
</trans-unit>
- <trans-unit id="_msg339">
+ <trans-unit id="_msg342">
<source xml:space="preserve">&amp;Reset Options</source>
<context-group purpose="location"><context context-type="linenumber">960</context></context-group>
</trans-unit>
- <trans-unit id="_msg340">
+ <trans-unit id="_msg343">
<source xml:space="preserve">&amp;Network</source>
<context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
- <trans-unit id="_msg341">
+ <trans-unit id="_msg344">
<source xml:space="preserve">Prune &amp;block storage to</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg342">
+ <trans-unit id="_msg345">
<source xml:space="preserve">GB</source>
<context-group purpose="location"><context context-type="linenumber">71</context></context-group>
</trans-unit>
- <trans-unit id="_msg343">
+ <trans-unit id="_msg346">
<source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg344">
+ <trans-unit id="_msg347">
<source xml:space="preserve">Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</note>
</trans-unit>
- <trans-unit id="_msg345">
+ <trans-unit id="_msg348">
<source xml:space="preserve">MiB</source>
<context-group purpose="location"><context context-type="linenumber">127</context></context-group>
</trans-unit>
- <trans-unit id="_msg346">
+ <trans-unit id="_msg349">
<source xml:space="preserve">Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</note>
</trans-unit>
- <trans-unit id="_msg347">
+ <trans-unit id="_msg350">
<source xml:space="preserve">(0 = auto, &lt;0 = leave that many cores free)</source>
<context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg348">
+ <trans-unit id="_msg351">
<source xml:space="preserve">This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
<context-group purpose="location"><context context-type="linenumber">192</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that enables the RPC server.</note>
</trans-unit>
- <trans-unit id="_msg349">
+ <trans-unit id="_msg352">
<source xml:space="preserve">Enable R&amp;PC server</source>
<context-group purpose="location"><context context-type="linenumber">195</context></context-group>
<note annotates="source" from="developer">An Options window setting to enable the RPC server.</note>
</trans-unit>
- <trans-unit id="_msg350">
+ <trans-unit id="_msg353">
<source xml:space="preserve">W&amp;allet</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg351">
+ <trans-unit id="_msg354">
<source xml:space="preserve">Whether to set subtract fee from amount as default or not.</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</note>
</trans-unit>
- <trans-unit id="_msg352">
+ <trans-unit id="_msg355">
<source xml:space="preserve">Subtract &amp;fee from amount by default</source>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
<note annotates="source" from="developer">An Options window setting to set subtracting the fee from a sending amount as default.</note>
</trans-unit>
- <trans-unit id="_msg353">
+ <trans-unit id="_msg356">
<source xml:space="preserve">Expert</source>
<context-group purpose="location"><context context-type="linenumber">232</context></context-group>
</trans-unit>
- <trans-unit id="_msg354">
+ <trans-unit id="_msg357">
<source xml:space="preserve">Enable coin &amp;control features</source>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg355">
+ <trans-unit id="_msg358">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg356">
+ <trans-unit id="_msg359">
<source xml:space="preserve">&amp;Spend unconfirmed change</source>
<context-group purpose="location"><context context-type="linenumber">251</context></context-group>
</trans-unit>
- <trans-unit id="_msg357">
+ <trans-unit id="_msg360">
<source xml:space="preserve">Enable &amp;PSBT controls</source>
<context-group purpose="location"><context context-type="linenumber">258</context></context-group>
<note annotates="source" from="developer">An options window setting to enable PSBT controls.</note>
</trans-unit>
- <trans-unit id="_msg358">
+ <trans-unit id="_msg361">
<source xml:space="preserve">Whether to show PSBT controls.</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
<note annotates="source" from="developer">Tooltip text for options window setting that enables PSBT controls.</note>
</trans-unit>
- <trans-unit id="_msg359">
+ <trans-unit id="_msg362">
<source xml:space="preserve">External Signer (e.g. hardware wallet)</source>
<context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
- <trans-unit id="_msg360">
+ <trans-unit id="_msg363">
<source xml:space="preserve">&amp;External signer script path</source>
<context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg361">
- <source xml:space="preserve">Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
- <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
- </trans-unit>
- <trans-unit id="_msg362">
+ <trans-unit id="_msg364">
<source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg363">
+ <trans-unit id="_msg365">
<source xml:space="preserve">Map port using &amp;UPnP</source>
<context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg364">
+ <trans-unit id="_msg366">
<source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
<context-group purpose="location"><context context-type="linenumber">331</context></context-group>
</trans-unit>
- <trans-unit id="_msg365">
+ <trans-unit id="_msg367">
<source xml:space="preserve">Map port using NA&amp;T-PMP</source>
<context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg366">
+ <trans-unit id="_msg368">
<source xml:space="preserve">Accept connections from outside.</source>
<context-group purpose="location"><context context-type="linenumber">341</context></context-group>
</trans-unit>
- <trans-unit id="_msg367">
+ <trans-unit id="_msg369">
<source xml:space="preserve">Allow incomin&amp;g connections</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg368">
+ <trans-unit id="_msg370">
<source xml:space="preserve">Connect to the Bitcoin network through a SOCKS5 proxy.</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg369">
+ <trans-unit id="_msg371">
<source xml:space="preserve">&amp;Connect through SOCKS5 proxy (default proxy):</source>
<context-group purpose="location"><context context-type="linenumber">354</context></context-group>
</trans-unit>
- <trans-unit id="_msg370">
+ <trans-unit id="_msg372">
<source xml:space="preserve">Proxy &amp;IP:</source>
<context-group purpose="location"><context context-type="linenumber">363</context></context-group>
<context-group purpose="location"><context context-type="linenumber">550</context></context-group>
</trans-unit>
- <trans-unit id="_msg371">
+ <trans-unit id="_msg373">
<source xml:space="preserve">&amp;Port:</source>
<context-group purpose="location"><context context-type="linenumber">395</context></context-group>
<context-group purpose="location"><context context-type="linenumber">582</context></context-group>
</trans-unit>
- <trans-unit id="_msg372">
+ <trans-unit id="_msg374">
<source xml:space="preserve">Port of the proxy (e.g. 9050)</source>
<context-group purpose="location"><context context-type="linenumber">420</context></context-group>
<context-group purpose="location"><context context-type="linenumber">607</context></context-group>
</trans-unit>
- <trans-unit id="_msg373">
+ <trans-unit id="_msg375">
<source xml:space="preserve">Used for reaching peers via:</source>
<context-group purpose="location"><context context-type="linenumber">444</context></context-group>
</trans-unit>
- <trans-unit id="_msg374">
+ <trans-unit id="_msg376">
<source xml:space="preserve">IPv4</source>
<context-group purpose="location"><context context-type="linenumber">467</context></context-group>
</trans-unit>
- <trans-unit id="_msg375">
+ <trans-unit id="_msg377">
<source xml:space="preserve">IPv6</source>
<context-group purpose="location"><context context-type="linenumber">490</context></context-group>
</trans-unit>
- <trans-unit id="_msg376">
+ <trans-unit id="_msg378">
<source xml:space="preserve">Tor</source>
<context-group purpose="location"><context context-type="linenumber">513</context></context-group>
</trans-unit>
- <trans-unit id="_msg377">
+ <trans-unit id="_msg379">
<source xml:space="preserve">&amp;Window</source>
<context-group purpose="location"><context context-type="linenumber">643</context></context-group>
</trans-unit>
- <trans-unit id="_msg378">
+ <trans-unit id="_msg380">
<source xml:space="preserve">Show the icon in the system tray.</source>
<context-group purpose="location"><context context-type="linenumber">649</context></context-group>
</trans-unit>
- <trans-unit id="_msg379">
+ <trans-unit id="_msg381">
<source xml:space="preserve">&amp;Show tray icon</source>
<context-group purpose="location"><context context-type="linenumber">652</context></context-group>
</trans-unit>
- <trans-unit id="_msg380">
+ <trans-unit id="_msg382">
<source xml:space="preserve">Show only a tray icon after minimizing the window.</source>
<context-group purpose="location"><context context-type="linenumber">662</context></context-group>
</trans-unit>
- <trans-unit id="_msg381">
+ <trans-unit id="_msg383">
<source xml:space="preserve">&amp;Minimize to the tray instead of the taskbar</source>
<context-group purpose="location"><context context-type="linenumber">665</context></context-group>
</trans-unit>
- <trans-unit id="_msg382">
+ <trans-unit id="_msg384">
<source xml:space="preserve">M&amp;inimize on close</source>
<context-group purpose="location"><context context-type="linenumber">675</context></context-group>
</trans-unit>
- <trans-unit id="_msg383">
+ <trans-unit id="_msg385">
<source xml:space="preserve">&amp;Display</source>
<context-group purpose="location"><context context-type="linenumber">696</context></context-group>
</trans-unit>
- <trans-unit id="_msg384">
+ <trans-unit id="_msg386">
<source xml:space="preserve">User Interface &amp;language:</source>
<context-group purpose="location"><context context-type="linenumber">704</context></context-group>
</trans-unit>
- <trans-unit id="_msg385">
+ <trans-unit id="_msg387">
<source xml:space="preserve">The user interface language can be set here. This setting will take effect after restarting %1.</source>
<context-group purpose="location"><context context-type="linenumber">717</context></context-group>
</trans-unit>
- <trans-unit id="_msg386">
+ <trans-unit id="_msg388">
<source xml:space="preserve">&amp;Unit to show amounts in:</source>
<context-group purpose="location"><context context-type="linenumber">728</context></context-group>
</trans-unit>
- <trans-unit id="_msg387">
+ <trans-unit id="_msg389">
<source xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</source>
<context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg388">
+ <trans-unit id="_msg390">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">752</context></context-group>
<context-group purpose="location"><context context-type="linenumber">765</context></context-group>
</trans-unit>
- <trans-unit id="_msg389">
+ <trans-unit id="_msg391">
<source xml:space="preserve">&amp;Third-party transaction URLs</source>
<context-group purpose="location"><context context-type="linenumber">755</context></context-group>
</trans-unit>
- <trans-unit id="_msg390">
+ <trans-unit id="_msg392">
<source xml:space="preserve">Whether to show coin control features or not.</source>
<context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg391">
+ <trans-unit id="_msg393">
<source xml:space="preserve">Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
<context-group purpose="location"><context context-type="linenumber">538</context></context-group>
</trans-unit>
- <trans-unit id="_msg392">
+ <trans-unit id="_msg394">
<source xml:space="preserve">Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
<context-group purpose="location"><context context-type="linenumber">541</context></context-group>
</trans-unit>
- <trans-unit id="_msg393">
+ <trans-unit id="_msg395">
<source xml:space="preserve">Monospaced font in the Overview tab:</source>
<context-group purpose="location"><context context-type="linenumber">777</context></context-group>
</trans-unit>
- <trans-unit id="_msg394">
+ <trans-unit id="_msg396">
<source xml:space="preserve">embedded &quot;%1&quot;</source>
<context-group purpose="location"><context context-type="linenumber">785</context></context-group>
</trans-unit>
- <trans-unit id="_msg395">
+ <trans-unit id="_msg397">
<source xml:space="preserve">closest matching &quot;%1&quot;</source>
<context-group purpose="location"><context context-type="linenumber">834</context></context-group>
</trans-unit>
- <trans-unit id="_msg396">
+ <trans-unit id="_msg398">
<source xml:space="preserve">&amp;OK</source>
<context-group purpose="location"><context context-type="linenumber">1040</context></context-group>
</trans-unit>
- <trans-unit id="_msg397">
+ <trans-unit id="_msg399">
<source xml:space="preserve">&amp;Cancel</source>
<context-group purpose="location"><context context-type="linenumber">1053</context></context-group>
</trans-unit>
@@ -1793,71 +1802,71 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../optionsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsDialog">
- <trans-unit id="_msg398">
+ <trans-unit id="_msg400">
<source xml:space="preserve">Compiled without external signing support (required for external signing)</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
<note annotates="source" from="developer">&quot;External signing&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg399">
+ <trans-unit id="_msg401">
<source xml:space="preserve">default</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
- <trans-unit id="_msg400">
+ <trans-unit id="_msg402">
<source xml:space="preserve">none</source>
<context-group purpose="location"><context context-type="linenumber">194</context></context-group>
</trans-unit>
- <trans-unit id="_msg401">
+ <trans-unit id="_msg403">
<source xml:space="preserve">Confirm options reset</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
<note annotates="source" from="developer">Window title text of pop-up window shown when the user has chosen to reset options.</note>
</trans-unit>
- <trans-unit id="_msg402">
+ <trans-unit id="_msg404">
<source xml:space="preserve">Client restart required to activate changes.</source>
<context-group purpose="location"><context context-type="linenumber">292</context></context-group>
<context-group purpose="location"><context context-type="linenumber">371</context></context-group>
<note annotates="source" from="developer">Text explaining that the settings changed will not come into effect until the client is restarted.</note>
</trans-unit>
- <trans-unit id="_msg403">
+ <trans-unit id="_msg405">
<source xml:space="preserve">Current settings will be backed up at &quot;%1&quot;.</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
<note annotates="source" from="developer">Text explaining to the user that the client&apos;s current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location&apos;s path.</note>
</trans-unit>
- <trans-unit id="_msg404">
+ <trans-unit id="_msg406">
<source xml:space="preserve">Client will be shut down. Do you want to proceed?</source>
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
<note annotates="source" from="developer">Text asking the user to confirm if they would like to proceed with a client shutdown.</note>
</trans-unit>
- <trans-unit id="_msg405">
+ <trans-unit id="_msg407">
<source xml:space="preserve">Configuration options</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
<note annotates="source" from="developer">Window title text of pop-up box that allows opening up of configuration file.</note>
</trans-unit>
- <trans-unit id="_msg406">
+ <trans-unit id="_msg408">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">322</context></context-group>
<note annotates="source" from="developer">Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</note>
</trans-unit>
- <trans-unit id="_msg407">
+ <trans-unit id="_msg409">
<source xml:space="preserve">Continue</source>
<context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg408">
+ <trans-unit id="_msg410">
<source xml:space="preserve">Cancel</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg409">
+ <trans-unit id="_msg411">
<source xml:space="preserve">Error</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg410">
+ <trans-unit id="_msg412">
<source xml:space="preserve">The configuration file could not be opened.</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg411">
+ <trans-unit id="_msg413">
<source xml:space="preserve">This change would require a client restart.</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
</trans-unit>
- <trans-unit id="_msg412">
+ <trans-unit id="_msg414">
<source xml:space="preserve">The supplied proxy address is invalid.</source>
<context-group purpose="location"><context context-type="linenumber">403</context></context-group>
</trans-unit>
@@ -1865,84 +1874,84 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../optionsmodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsModel">
- <trans-unit id="_msg413">
+ <trans-unit id="_msg415">
<source xml:space="preserve">Could not read setting &quot;%1&quot;, %2.</source>
- <context-group purpose="location"><context context-type="linenumber">204</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/overviewpage.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OverviewPage">
- <trans-unit id="_msg414">
+ <trans-unit id="_msg416">
<source xml:space="preserve">Form</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg415">
+ <trans-unit id="_msg417">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
<context-group purpose="location"><context context-type="linenumber">411</context></context-group>
</trans-unit>
- <trans-unit id="_msg416">
+ <trans-unit id="_msg418">
<source xml:space="preserve">Watch-only:</source>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg417">
+ <trans-unit id="_msg419">
<source xml:space="preserve">Available:</source>
<context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
- <trans-unit id="_msg418">
+ <trans-unit id="_msg420">
<source xml:space="preserve">Your current spendable balance</source>
<context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg419">
+ <trans-unit id="_msg421">
<source xml:space="preserve">Pending:</source>
<context-group purpose="location"><context context-type="linenumber">339</context></context-group>
</trans-unit>
- <trans-unit id="_msg420">
+ <trans-unit id="_msg422">
<source xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
- <trans-unit id="_msg421">
+ <trans-unit id="_msg423">
<source xml:space="preserve">Immature:</source>
<context-group purpose="location"><context context-type="linenumber">239</context></context-group>
</trans-unit>
- <trans-unit id="_msg422">
+ <trans-unit id="_msg424">
<source xml:space="preserve">Mined balance that has not yet matured</source>
<context-group purpose="location"><context context-type="linenumber">210</context></context-group>
</trans-unit>
- <trans-unit id="_msg423">
+ <trans-unit id="_msg425">
<source xml:space="preserve">Balances</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg424">
+ <trans-unit id="_msg426">
<source xml:space="preserve">Total:</source>
<context-group purpose="location"><context context-type="linenumber">200</context></context-group>
</trans-unit>
- <trans-unit id="_msg425">
+ <trans-unit id="_msg427">
<source xml:space="preserve">Your current total balance</source>
<context-group purpose="location"><context context-type="linenumber">249</context></context-group>
</trans-unit>
- <trans-unit id="_msg426">
+ <trans-unit id="_msg428">
<source xml:space="preserve">Your current balance in watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg427">
+ <trans-unit id="_msg429">
<source xml:space="preserve">Spendable:</source>
<context-group purpose="location"><context context-type="linenumber">346</context></context-group>
</trans-unit>
- <trans-unit id="_msg428">
+ <trans-unit id="_msg430">
<source xml:space="preserve">Recent transactions</source>
<context-group purpose="location"><context context-type="linenumber">395</context></context-group>
</trans-unit>
- <trans-unit id="_msg429">
+ <trans-unit id="_msg431">
<source xml:space="preserve">Unconfirmed transactions to watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg430">
+ <trans-unit id="_msg432">
<source xml:space="preserve">Mined balance in watch-only addresses that has not yet matured</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg431">
+ <trans-unit id="_msg433">
<source xml:space="preserve">Current total balance in watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
@@ -1950,35 +1959,35 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../overviewpage.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OverviewPage">
- <trans-unit id="_msg432">
+ <trans-unit id="_msg434">
<source xml:space="preserve">Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
- <context-group purpose="location"><context context-type="linenumber">185</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">184</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/psbtoperationsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog">
- <trans-unit id="_msg433">
+ <trans-unit id="_msg435">
<source xml:space="preserve">Dialog</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg434">
+ <trans-unit id="_msg436">
<source xml:space="preserve">Sign Tx</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg435">
+ <trans-unit id="_msg437">
<source xml:space="preserve">Broadcast Tx</source>
<context-group purpose="location"><context context-type="linenumber">102</context></context-group>
</trans-unit>
- <trans-unit id="_msg436">
+ <trans-unit id="_msg438">
<source xml:space="preserve">Copy to Clipboard</source>
<context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg437">
+ <trans-unit id="_msg439">
<source xml:space="preserve">Save…</source>
<context-group purpose="location"><context context-type="linenumber">129</context></context-group>
</trans-unit>
- <trans-unit id="_msg438">
+ <trans-unit id="_msg440">
<source xml:space="preserve">Close</source>
<context-group purpose="location"><context context-type="linenumber">136</context></context-group>
</trans-unit>
@@ -1986,108 +1995,108 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../psbtoperationsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog">
- <trans-unit id="_msg439">
+ <trans-unit id="_msg441">
<source xml:space="preserve">Failed to load transaction: %1</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg440">
+ <trans-unit id="_msg442">
<source xml:space="preserve">Failed to sign transaction: %1</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg441">
+ <trans-unit id="_msg443">
<source xml:space="preserve">Cannot sign inputs while wallet is locked.</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
</trans-unit>
- <trans-unit id="_msg442">
+ <trans-unit id="_msg444">
<source xml:space="preserve">Could not sign any more inputs.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg443">
+ <trans-unit id="_msg445">
<source xml:space="preserve">Signed %1 inputs, but more signatures are still required.</source>
<context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg444">
+ <trans-unit id="_msg446">
<source xml:space="preserve">Signed transaction successfully. Transaction is ready to broadcast.</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg445">
+ <trans-unit id="_msg447">
<source xml:space="preserve">Unknown error processing transaction.</source>
<context-group purpose="location"><context context-type="linenumber">113</context></context-group>
</trans-unit>
- <trans-unit id="_msg446">
+ <trans-unit id="_msg448">
<source xml:space="preserve">Transaction broadcast successfully! Transaction ID: %1</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
- <trans-unit id="_msg447">
+ <trans-unit id="_msg449">
<source xml:space="preserve">Transaction broadcast failed: %1</source>
<context-group purpose="location"><context context-type="linenumber">126</context></context-group>
</trans-unit>
- <trans-unit id="_msg448">
+ <trans-unit id="_msg450">
<source xml:space="preserve">PSBT copied to clipboard.</source>
<context-group purpose="location"><context context-type="linenumber">135</context></context-group>
</trans-unit>
- <trans-unit id="_msg449">
+ <trans-unit id="_msg451">
<source xml:space="preserve">Save Transaction Data</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg450">
+ <trans-unit id="_msg452">
<source xml:space="preserve">Partially Signed Transaction (Binary)</source>
<context-group purpose="location"><context context-type="linenumber">160</context></context-group>
<note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note>
</trans-unit>
- <trans-unit id="_msg451">
+ <trans-unit id="_msg453">
<source xml:space="preserve">PSBT saved to disk.</source>
<context-group purpose="location"><context context-type="linenumber">167</context></context-group>
</trans-unit>
- <trans-unit id="_msg452">
+ <trans-unit id="_msg454">
<source xml:space="preserve"> * Sends %1 to %2</source>
<context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg453">
+ <trans-unit id="_msg455">
<source xml:space="preserve">Unable to calculate transaction fee or total transaction amount.</source>
<context-group purpose="location"><context context-type="linenumber">193</context></context-group>
</trans-unit>
- <trans-unit id="_msg454">
+ <trans-unit id="_msg456">
<source xml:space="preserve">Pays transaction fee: </source>
<context-group purpose="location"><context context-type="linenumber">195</context></context-group>
</trans-unit>
- <trans-unit id="_msg455">
+ <trans-unit id="_msg457">
<source xml:space="preserve">Total Amount</source>
<context-group purpose="location"><context context-type="linenumber">207</context></context-group>
</trans-unit>
- <trans-unit id="_msg456">
+ <trans-unit id="_msg458">
<source xml:space="preserve">or</source>
<context-group purpose="location"><context context-type="linenumber">210</context></context-group>
</trans-unit>
- <trans-unit id="_msg457">
+ <trans-unit id="_msg459">
<source xml:space="preserve">Transaction has %1 unsigned inputs.</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg458">
+ <trans-unit id="_msg460">
<source xml:space="preserve">Transaction is missing some information about inputs.</source>
<context-group purpose="location"><context context-type="linenumber">262</context></context-group>
</trans-unit>
- <trans-unit id="_msg459">
+ <trans-unit id="_msg461">
<source xml:space="preserve">Transaction still needs signature(s).</source>
<context-group purpose="location"><context context-type="linenumber">266</context></context-group>
</trans-unit>
- <trans-unit id="_msg460">
+ <trans-unit id="_msg462">
<source xml:space="preserve">(But no wallet is loaded.)</source>
<context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg461">
+ <trans-unit id="_msg463">
<source xml:space="preserve">(But this wallet cannot sign transactions.)</source>
<context-group purpose="location"><context context-type="linenumber">272</context></context-group>
</trans-unit>
- <trans-unit id="_msg462">
+ <trans-unit id="_msg464">
<source xml:space="preserve">(But this wallet does not have the right keys.)</source>
<context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
- <trans-unit id="_msg463">
+ <trans-unit id="_msg465">
<source xml:space="preserve">Transaction is fully signed and ready for broadcast.</source>
<context-group purpose="location"><context context-type="linenumber">283</context></context-group>
</trans-unit>
- <trans-unit id="_msg464">
+ <trans-unit id="_msg466">
<source xml:space="preserve">Transaction status is unknown.</source>
<context-group purpose="location"><context context-type="linenumber">287</context></context-group>
</trans-unit>
@@ -2095,90 +2104,90 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../paymentserver.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PaymentServer">
- <trans-unit id="_msg465">
+ <trans-unit id="_msg467">
<source xml:space="preserve">Payment request error</source>
- <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">149</context></context-group>
</trans-unit>
- <trans-unit id="_msg466">
+ <trans-unit id="_msg468">
<source xml:space="preserve">Cannot start bitcoin: click-to-pay handler</source>
- <context-group purpose="location"><context context-type="linenumber">153</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">150</context></context-group>
</trans-unit>
- <trans-unit id="_msg467">
+ <trans-unit id="_msg469">
<source xml:space="preserve">URI handling</source>
- <context-group purpose="location"><context context-type="linenumber">201</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">217</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">223</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">230</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">198</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
</trans-unit>
- <trans-unit id="_msg468">
+ <trans-unit id="_msg470">
<source xml:space="preserve">&apos;bitcoin://&apos; is not a valid URI. Use &apos;bitcoin:&apos; instead.</source>
- <context-group purpose="location"><context context-type="linenumber">201</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
- <trans-unit id="_msg469">
+ <trans-unit id="_msg471">
<source xml:space="preserve">Cannot process payment request because BIP70 is not supported.
Due to widespread security flaws in BIP70 it&apos;s strongly recommended that any merchant instructions to switch wallets be ignored.
If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
- <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg470">
+ <trans-unit id="_msg472">
<source xml:space="preserve">URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
- <context-group purpose="location"><context context-type="linenumber">231</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">228</context></context-group>
</trans-unit>
- <trans-unit id="_msg471">
+ <trans-unit id="_msg473">
<source xml:space="preserve">Payment request file handling</source>
- <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">237</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../peertablemodel.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PeerTableModel">
- <trans-unit id="_msg472">
+ <trans-unit id="_msg474">
<source xml:space="preserve">User Agent</source>
<context-group purpose="location"><context context-type="linenumber">112</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains the peer&apos;s User Agent string.</note>
</trans-unit>
- <trans-unit id="_msg473">
+ <trans-unit id="_msg475">
<source xml:space="preserve">Ping</source>
<context-group purpose="location"><context context-type="linenumber">103</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the current latency of the connection with the peer.</note>
</trans-unit>
- <trans-unit id="_msg474">
+ <trans-unit id="_msg476">
<source xml:space="preserve">Peer</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains a unique number used to identify a connection.</note>
</trans-unit>
- <trans-unit id="_msg475">
+ <trans-unit id="_msg477">
<source xml:space="preserve">Age</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</note>
</trans-unit>
- <trans-unit id="_msg476">
+ <trans-unit id="_msg478">
<source xml:space="preserve">Direction</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the direction the peer connection was initiated from.</note>
</trans-unit>
- <trans-unit id="_msg477">
+ <trans-unit id="_msg479">
<source xml:space="preserve">Sent</source>
<context-group purpose="location"><context context-type="linenumber">106</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</note>
</trans-unit>
- <trans-unit id="_msg478">
+ <trans-unit id="_msg480">
<source xml:space="preserve">Received</source>
<context-group purpose="location"><context context-type="linenumber">109</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have received from the peer.</note>
</trans-unit>
- <trans-unit id="_msg479">
+ <trans-unit id="_msg481">
<source xml:space="preserve">Address</source>
<context-group purpose="location"><context context-type="linenumber">91</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</note>
</trans-unit>
- <trans-unit id="_msg480">
+ <trans-unit id="_msg482">
<source xml:space="preserve">Type</source>
<context-group purpose="location"><context context-type="linenumber">97</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which describes the type of peer connection. The &quot;type&quot; describes why the connection exists.</note>
</trans-unit>
- <trans-unit id="_msg481">
+ <trans-unit id="_msg483">
<source xml:space="preserve">Network</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which states the network the peer connected through.</note>
@@ -2187,21 +2196,21 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../peertablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PeerTableModel">
- <trans-unit id="_msg482">
+ <trans-unit id="_msg484">
<source xml:space="preserve">Inbound</source>
- <context-group purpose="location"><context context-type="linenumber">78</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">77</context></context-group>
<note annotates="source" from="developer">An Inbound Connection from a Peer.</note>
</trans-unit>
- <trans-unit id="_msg483">
+ <trans-unit id="_msg485">
<source xml:space="preserve">Outbound</source>
- <context-group purpose="location"><context context-type="linenumber">80</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">79</context></context-group>
<note annotates="source" from="developer">An Outbound Connection to a Peer.</note>
</trans-unit>
</group>
</body></file>
<file original="../bitcoinunits.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg484">
+ <trans-unit id="_msg486">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">197</context></context-group>
</trans-unit>
@@ -2209,194 +2218,194 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../guiutil.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg485">
+ <trans-unit id="_msg487">
<source xml:space="preserve">Enter a Bitcoin address (e.g. %1)</source>
<context-group purpose="location"><context context-type="linenumber">129</context></context-group>
</trans-unit>
- <trans-unit id="_msg486">
+ <trans-unit id="_msg488">
<source xml:space="preserve">Ctrl+W</source>
<context-group purpose="location"><context context-type="linenumber">417</context></context-group>
</trans-unit>
- <trans-unit id="_msg487">
+ <trans-unit id="_msg489">
<source xml:space="preserve">Unroutable</source>
- <context-group purpose="location"><context context-type="linenumber">673</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">674</context></context-group>
</trans-unit>
- <trans-unit id="_msg488">
+ <trans-unit id="_msg490">
<source xml:space="preserve">Internal</source>
- <context-group purpose="location"><context context-type="linenumber">679</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">680</context></context-group>
</trans-unit>
- <trans-unit id="_msg489">
+ <trans-unit id="_msg491">
<source xml:space="preserve">Inbound</source>
- <context-group purpose="location"><context context-type="linenumber">692</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">693</context></context-group>
<note annotates="source" from="developer">An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</note>
</trans-unit>
- <trans-unit id="_msg490">
+ <trans-unit id="_msg492">
<source xml:space="preserve">Outbound</source>
- <context-group purpose="location"><context context-type="linenumber">695</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">696</context></context-group>
<note annotates="source" from="developer">An outbound connection to a peer. An outbound connection is a connection initiated by us.</note>
</trans-unit>
- <trans-unit id="_msg491">
+ <trans-unit id="_msg493">
<source xml:space="preserve">Full Relay</source>
- <context-group purpose="location"><context context-type="linenumber">700</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">701</context></context-group>
<note annotates="source" from="developer">Peer connection type that relays all network information.</note>
</trans-unit>
- <trans-unit id="_msg492">
+ <trans-unit id="_msg494">
<source xml:space="preserve">Block Relay</source>
- <context-group purpose="location"><context context-type="linenumber">703</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">704</context></context-group>
<note annotates="source" from="developer">Peer connection type that relays network information about blocks and not transactions or addresses.</note>
</trans-unit>
- <trans-unit id="_msg493">
+ <trans-unit id="_msg495">
<source xml:space="preserve">Manual</source>
- <context-group purpose="location"><context context-type="linenumber">705</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">706</context></context-group>
<note annotates="source" from="developer">Peer connection type established manually through one of several methods.</note>
</trans-unit>
- <trans-unit id="_msg494">
+ <trans-unit id="_msg496">
<source xml:space="preserve">Feeler</source>
- <context-group purpose="location"><context context-type="linenumber">707</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">708</context></context-group>
<note annotates="source" from="developer">Short-lived peer connection type that tests the aliveness of known addresses.</note>
</trans-unit>
- <trans-unit id="_msg495">
+ <trans-unit id="_msg497">
<source xml:space="preserve">Address Fetch</source>
- <context-group purpose="location"><context context-type="linenumber">709</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">710</context></context-group>
<note annotates="source" from="developer">Short-lived peer connection type that solicits known addresses from a peer.</note>
</trans-unit>
- <trans-unit id="_msg496">
+ <trans-unit id="_msg498">
<source xml:space="preserve">%1 d</source>
- <context-group purpose="location"><context context-type="linenumber">722</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">734</context></context-group>
- </trans-unit>
- <trans-unit id="_msg497">
- <source xml:space="preserve">%1 h</source>
<context-group purpose="location"><context context-type="linenumber">723</context></context-group>
<context-group purpose="location"><context context-type="linenumber">735</context></context-group>
</trans-unit>
- <trans-unit id="_msg498">
- <source xml:space="preserve">%1 m</source>
+ <trans-unit id="_msg499">
+ <source xml:space="preserve">%1 h</source>
<context-group purpose="location"><context context-type="linenumber">724</context></context-group>
<context-group purpose="location"><context context-type="linenumber">736</context></context-group>
</trans-unit>
- <trans-unit id="_msg499">
- <source xml:space="preserve">%1 s</source>
- <context-group purpose="location"><context context-type="linenumber">726</context></context-group>
+ <trans-unit id="_msg500">
+ <source xml:space="preserve">%1 m</source>
+ <context-group purpose="location"><context context-type="linenumber">725</context></context-group>
<context-group purpose="location"><context context-type="linenumber">737</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">763</context></context-group>
</trans-unit>
- <trans-unit id="_msg500">
+ <trans-unit id="_msg501">
+ <source xml:space="preserve">%1 s</source>
+ <context-group purpose="location"><context context-type="linenumber">727</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">738</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">764</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg502">
<source xml:space="preserve">None</source>
- <context-group purpose="location"><context context-type="linenumber">751</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">752</context></context-group>
</trans-unit>
- <trans-unit id="_msg501">
+ <trans-unit id="_msg503">
<source xml:space="preserve">N/A</source>
- <context-group purpose="location"><context context-type="linenumber">757</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">758</context></context-group>
</trans-unit>
- <trans-unit id="_msg502">
+ <trans-unit id="_msg504">
<source xml:space="preserve">%1 ms</source>
- <context-group purpose="location"><context context-type="linenumber">758</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">759</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">776</context></context-group>
- <trans-unit id="_msg503[0]">
+ <context-group purpose="location"><context context-type="linenumber">777</context></context-group>
+ <trans-unit id="_msg505[0]">
<source xml:space="preserve">%n second(s)</source>
</trans-unit>
- <trans-unit id="_msg503[1]">
+ <trans-unit id="_msg505[1]">
<source xml:space="preserve">%n second(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">780</context></context-group>
- <trans-unit id="_msg504[0]">
+ <context-group purpose="location"><context context-type="linenumber">781</context></context-group>
+ <trans-unit id="_msg506[0]">
<source xml:space="preserve">%n minute(s)</source>
</trans-unit>
- <trans-unit id="_msg504[1]">
+ <trans-unit id="_msg506[1]">
<source xml:space="preserve">%n minute(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">784</context></context-group>
- <trans-unit id="_msg505[0]">
+ <context-group purpose="location"><context context-type="linenumber">785</context></context-group>
+ <trans-unit id="_msg507[0]">
<source xml:space="preserve">%n hour(s)</source>
</trans-unit>
- <trans-unit id="_msg505[1]">
+ <trans-unit id="_msg507[1]">
<source xml:space="preserve">%n hour(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">788</context></context-group>
- <trans-unit id="_msg506[0]">
+ <context-group purpose="location"><context context-type="linenumber">789</context></context-group>
+ <trans-unit id="_msg508[0]">
<source xml:space="preserve">%n day(s)</source>
</trans-unit>
- <trans-unit id="_msg506[1]">
+ <trans-unit id="_msg508[1]">
<source xml:space="preserve">%n day(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">792</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">798</context></context-group>
- <trans-unit id="_msg507[0]">
+ <context-group purpose="location"><context context-type="linenumber">793</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">799</context></context-group>
+ <trans-unit id="_msg509[0]">
<source xml:space="preserve">%n week(s)</source>
</trans-unit>
- <trans-unit id="_msg507[1]">
+ <trans-unit id="_msg509[1]">
<source xml:space="preserve">%n week(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg508">
+ <trans-unit id="_msg510">
<source xml:space="preserve">%1 and %2</source>
- <context-group purpose="location"><context context-type="linenumber">798</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">799</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">798</context></context-group>
- <trans-unit id="_msg509[0]">
+ <context-group purpose="location"><context context-type="linenumber">799</context></context-group>
+ <trans-unit id="_msg511[0]">
<source xml:space="preserve">%n year(s)</source>
</trans-unit>
- <trans-unit id="_msg509[1]">
+ <trans-unit id="_msg511[1]">
<source xml:space="preserve">%n year(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg510">
+ <trans-unit id="_msg512">
<source xml:space="preserve">%1 B</source>
- <context-group purpose="location"><context context-type="linenumber">806</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">807</context></context-group>
</trans-unit>
- <trans-unit id="_msg511">
+ <trans-unit id="_msg513">
<source xml:space="preserve">%1 kB</source>
- <context-group purpose="location"><context context-type="linenumber">808</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">809</context></context-group>
</trans-unit>
- <trans-unit id="_msg512">
+ <trans-unit id="_msg514">
<source xml:space="preserve">%1 MB</source>
- <context-group purpose="location"><context context-type="linenumber">810</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">811</context></context-group>
</trans-unit>
- <trans-unit id="_msg513">
+ <trans-unit id="_msg515">
<source xml:space="preserve">%1 GB</source>
- <context-group purpose="location"><context context-type="linenumber">812</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">813</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../qrimagewidget.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QRImageWidget">
- <trans-unit id="_msg514">
+ <trans-unit id="_msg516">
<source xml:space="preserve">&amp;Save Image…</source>
<context-group purpose="location"><context context-type="linenumber">30</context></context-group>
</trans-unit>
- <trans-unit id="_msg515">
+ <trans-unit id="_msg517">
<source xml:space="preserve">&amp;Copy Image</source>
<context-group purpose="location"><context context-type="linenumber">31</context></context-group>
</trans-unit>
- <trans-unit id="_msg516">
+ <trans-unit id="_msg518">
<source xml:space="preserve">Resulting URI too long, try to reduce the text for label / message.</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
- <trans-unit id="_msg517">
+ <trans-unit id="_msg519">
<source xml:space="preserve">Error encoding URI into QR Code.</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg518">
+ <trans-unit id="_msg520">
<source xml:space="preserve">QR code support not available.</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg519">
+ <trans-unit id="_msg521">
<source xml:space="preserve">Save QR Code</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg520">
+ <trans-unit id="_msg522">
<source xml:space="preserve">PNG Image</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
<note annotates="source" from="developer">Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</note>
@@ -2405,7 +2414,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../forms/debugwindow.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg521">
+ <trans-unit id="_msg523">
<source xml:space="preserve">N/A</source>
<context-group purpose="location"><context context-type="linenumber">75</context></context-group>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
@@ -2446,291 +2455,291 @@ If you are receiving this error you should request the merchant provide a BIP21
<context-group purpose="location"><context context-type="linenumber">1662</context></context-group>
<context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg522">
+ <trans-unit id="_msg524">
<source xml:space="preserve">Client version</source>
<context-group purpose="location"><context context-type="linenumber">65</context></context-group>
</trans-unit>
- <trans-unit id="_msg523">
+ <trans-unit id="_msg525">
<source xml:space="preserve">&amp;Information</source>
<context-group purpose="location"><context context-type="linenumber">43</context></context-group>
</trans-unit>
- <trans-unit id="_msg524">
+ <trans-unit id="_msg526">
<source xml:space="preserve">General</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg525">
+ <trans-unit id="_msg527">
<source xml:space="preserve">Datadir</source>
<context-group purpose="location"><context context-type="linenumber">114</context></context-group>
</trans-unit>
- <trans-unit id="_msg526">
+ <trans-unit id="_msg528">
<source xml:space="preserve">To specify a non-default location of the data directory use the &apos;%1&apos; option.</source>
<context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
- <trans-unit id="_msg527">
+ <trans-unit id="_msg529">
<source xml:space="preserve">Blocksdir</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg528">
+ <trans-unit id="_msg530">
<source xml:space="preserve">To specify a non-default location of the blocks directory use the &apos;%1&apos; option.</source>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg529">
+ <trans-unit id="_msg531">
<source xml:space="preserve">Startup time</source>
<context-group purpose="location"><context context-type="linenumber">172</context></context-group>
</trans-unit>
- <trans-unit id="_msg530">
+ <trans-unit id="_msg532">
<source xml:space="preserve">Network</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1093</context></context-group>
</trans-unit>
- <trans-unit id="_msg531">
+ <trans-unit id="_msg533">
<source xml:space="preserve">Name</source>
<context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg532">
+ <trans-unit id="_msg534">
<source xml:space="preserve">Number of connections</source>
<context-group purpose="location"><context context-type="linenumber">231</context></context-group>
</trans-unit>
- <trans-unit id="_msg533">
+ <trans-unit id="_msg535">
<source xml:space="preserve">Block chain</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg534">
+ <trans-unit id="_msg536">
<source xml:space="preserve">Memory Pool</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg535">
+ <trans-unit id="_msg537">
<source xml:space="preserve">Current number of transactions</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg536">
+ <trans-unit id="_msg538">
<source xml:space="preserve">Memory usage</source>
<context-group purpose="location"><context context-type="linenumber">349</context></context-group>
</trans-unit>
- <trans-unit id="_msg537">
+ <trans-unit id="_msg539">
<source xml:space="preserve">Wallet: </source>
<context-group purpose="location"><context context-type="linenumber">443</context></context-group>
</trans-unit>
- <trans-unit id="_msg538">
+ <trans-unit id="_msg540">
<source xml:space="preserve">(none)</source>
<context-group purpose="location"><context context-type="linenumber">454</context></context-group>
</trans-unit>
- <trans-unit id="_msg539">
+ <trans-unit id="_msg541">
<source xml:space="preserve">&amp;Reset</source>
<context-group purpose="location"><context context-type="linenumber">665</context></context-group>
</trans-unit>
- <trans-unit id="_msg540">
+ <trans-unit id="_msg542">
<source xml:space="preserve">Received</source>
<context-group purpose="location"><context context-type="linenumber">745</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1453</context></context-group>
</trans-unit>
- <trans-unit id="_msg541">
+ <trans-unit id="_msg543">
<source xml:space="preserve">Sent</source>
<context-group purpose="location"><context context-type="linenumber">825</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1430</context></context-group>
</trans-unit>
- <trans-unit id="_msg542">
+ <trans-unit id="_msg544">
<source xml:space="preserve">&amp;Peers</source>
<context-group purpose="location"><context context-type="linenumber">866</context></context-group>
</trans-unit>
- <trans-unit id="_msg543">
+ <trans-unit id="_msg545">
<source xml:space="preserve">Banned peers</source>
<context-group purpose="location"><context context-type="linenumber">942</context></context-group>
</trans-unit>
- <trans-unit id="_msg544">
+ <trans-unit id="_msg546">
<source xml:space="preserve">Select a peer to view detailed information.</source>
<context-group purpose="location"><context context-type="linenumber">1010</context></context-group>
<context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1155</context></context-group>
</trans-unit>
- <trans-unit id="_msg545">
+ <trans-unit id="_msg547">
<source xml:space="preserve">Version</source>
<context-group purpose="location"><context context-type="linenumber">1116</context></context-group>
</trans-unit>
- <trans-unit id="_msg546">
+ <trans-unit id="_msg548">
+ <source xml:space="preserve">Whether we relay transactions to this peer.</source>
+ <context-group purpose="location"><context context-type="linenumber">1188</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg549">
+ <source xml:space="preserve">Transaction Relay</source>
+ <context-group purpose="location"><context context-type="linenumber">1191</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg550">
<source xml:space="preserve">Starting Block</source>
<context-group purpose="location"><context context-type="linenumber">1240</context></context-group>
</trans-unit>
- <trans-unit id="_msg547">
+ <trans-unit id="_msg551">
<source xml:space="preserve">Synced Headers</source>
<context-group purpose="location"><context context-type="linenumber">1263</context></context-group>
</trans-unit>
- <trans-unit id="_msg548">
+ <trans-unit id="_msg552">
<source xml:space="preserve">Synced Blocks</source>
<context-group purpose="location"><context context-type="linenumber">1286</context></context-group>
</trans-unit>
- <trans-unit id="_msg549">
+ <trans-unit id="_msg553">
<source xml:space="preserve">Last Transaction</source>
<context-group purpose="location"><context context-type="linenumber">1361</context></context-group>
</trans-unit>
- <trans-unit id="_msg550">
+ <trans-unit id="_msg554">
<source xml:space="preserve">The mapped Autonomous System used for diversifying peer selection.</source>
<context-group purpose="location"><context context-type="linenumber">1571</context></context-group>
</trans-unit>
- <trans-unit id="_msg551">
+ <trans-unit id="_msg555">
<source xml:space="preserve">Mapped AS</source>
<context-group purpose="location"><context context-type="linenumber">1574</context></context-group>
</trans-unit>
- <trans-unit id="_msg552">
+ <trans-unit id="_msg556">
<source xml:space="preserve">Whether we relay addresses to this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1597</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</note>
</trans-unit>
- <trans-unit id="_msg553">
+ <trans-unit id="_msg557">
<source xml:space="preserve">Address Relay</source>
<context-group purpose="location"><context context-type="linenumber">1600</context></context-group>
<note annotates="source" from="developer">Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</note>
</trans-unit>
- <trans-unit id="_msg554">
+ <trans-unit id="_msg558">
<source xml:space="preserve">The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
<context-group purpose="location"><context context-type="linenumber">1623</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</note>
</trans-unit>
- <trans-unit id="_msg555">
+ <trans-unit id="_msg559">
<source xml:space="preserve">The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
<context-group purpose="location"><context context-type="linenumber">1649</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</note>
</trans-unit>
- <trans-unit id="_msg556">
+ <trans-unit id="_msg560">
<source xml:space="preserve">Addresses Processed</source>
<context-group purpose="location"><context context-type="linenumber">1626</context></context-group>
<note annotates="source" from="developer">Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</note>
</trans-unit>
- <trans-unit id="_msg557">
+ <trans-unit id="_msg561">
<source xml:space="preserve">Addresses Rate-Limited</source>
<context-group purpose="location"><context context-type="linenumber">1652</context></context-group>
<note annotates="source" from="developer">Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</note>
</trans-unit>
- <trans-unit id="_msg558">
+ <trans-unit id="_msg562">
<source xml:space="preserve">User Agent</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1139</context></context-group>
</trans-unit>
- <trans-unit id="_msg559">
+ <trans-unit id="_msg563">
<source xml:space="preserve">Node window</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg560">
+ <trans-unit id="_msg564">
<source xml:space="preserve">Current block height</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg561">
+ <trans-unit id="_msg565">
<source xml:space="preserve">Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
<context-group purpose="location"><context context-type="linenumber">397</context></context-group>
</trans-unit>
- <trans-unit id="_msg562">
+ <trans-unit id="_msg566">
<source xml:space="preserve">Decrease font size</source>
<context-group purpose="location"><context context-type="linenumber">475</context></context-group>
</trans-unit>
- <trans-unit id="_msg563">
+ <trans-unit id="_msg567">
<source xml:space="preserve">Increase font size</source>
<context-group purpose="location"><context context-type="linenumber">495</context></context-group>
</trans-unit>
- <trans-unit id="_msg564">
+ <trans-unit id="_msg568">
<source xml:space="preserve">Permissions</source>
<context-group purpose="location"><context context-type="linenumber">1041</context></context-group>
</trans-unit>
- <trans-unit id="_msg565">
+ <trans-unit id="_msg569">
<source xml:space="preserve">The direction and type of peer connection: %1</source>
<context-group purpose="location"><context context-type="linenumber">1064</context></context-group>
</trans-unit>
- <trans-unit id="_msg566">
+ <trans-unit id="_msg570">
<source xml:space="preserve">Direction/Type</source>
<context-group purpose="location"><context context-type="linenumber">1067</context></context-group>
</trans-unit>
- <trans-unit id="_msg567">
+ <trans-unit id="_msg571">
<source xml:space="preserve">The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
<context-group purpose="location"><context context-type="linenumber">1090</context></context-group>
</trans-unit>
- <trans-unit id="_msg568">
+ <trans-unit id="_msg572">
<source xml:space="preserve">Services</source>
<context-group purpose="location"><context context-type="linenumber">1162</context></context-group>
</trans-unit>
- <trans-unit id="_msg569">
- <source xml:space="preserve">Whether the peer requested us to relay transactions.</source>
- <context-group purpose="location"><context context-type="linenumber">1188</context></context-group>
- </trans-unit>
- <trans-unit id="_msg570">
- <source xml:space="preserve">Wants Tx Relay</source>
- <context-group purpose="location"><context context-type="linenumber">1191</context></context-group>
- </trans-unit>
- <trans-unit id="_msg571">
+ <trans-unit id="_msg573">
<source xml:space="preserve">High bandwidth BIP152 compact block relay: %1</source>
<context-group purpose="location"><context context-type="linenumber">1214</context></context-group>
</trans-unit>
- <trans-unit id="_msg572">
+ <trans-unit id="_msg574">
<source xml:space="preserve">High Bandwidth</source>
<context-group purpose="location"><context context-type="linenumber">1217</context></context-group>
</trans-unit>
- <trans-unit id="_msg573">
+ <trans-unit id="_msg575">
<source xml:space="preserve">Connection Time</source>
<context-group purpose="location"><context context-type="linenumber">1309</context></context-group>
</trans-unit>
- <trans-unit id="_msg574">
+ <trans-unit id="_msg576">
<source xml:space="preserve">Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1332</context></context-group>
</trans-unit>
- <trans-unit id="_msg575">
+ <trans-unit id="_msg577">
<source xml:space="preserve">Last Block</source>
<context-group purpose="location"><context context-type="linenumber">1335</context></context-group>
</trans-unit>
- <trans-unit id="_msg576">
+ <trans-unit id="_msg578">
<source xml:space="preserve">Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Last Transaction field in the peer details area.</note>
</trans-unit>
- <trans-unit id="_msg577">
+ <trans-unit id="_msg579">
<source xml:space="preserve">Last Send</source>
<context-group purpose="location"><context context-type="linenumber">1384</context></context-group>
</trans-unit>
- <trans-unit id="_msg578">
+ <trans-unit id="_msg580">
<source xml:space="preserve">Last Receive</source>
<context-group purpose="location"><context context-type="linenumber">1407</context></context-group>
</trans-unit>
- <trans-unit id="_msg579">
+ <trans-unit id="_msg581">
<source xml:space="preserve">Ping Time</source>
<context-group purpose="location"><context context-type="linenumber">1476</context></context-group>
</trans-unit>
- <trans-unit id="_msg580">
+ <trans-unit id="_msg582">
<source xml:space="preserve">The duration of a currently outstanding ping.</source>
<context-group purpose="location"><context context-type="linenumber">1499</context></context-group>
</trans-unit>
- <trans-unit id="_msg581">
+ <trans-unit id="_msg583">
<source xml:space="preserve">Ping Wait</source>
<context-group purpose="location"><context context-type="linenumber">1502</context></context-group>
</trans-unit>
- <trans-unit id="_msg582">
+ <trans-unit id="_msg584">
<source xml:space="preserve">Min Ping</source>
<context-group purpose="location"><context context-type="linenumber">1525</context></context-group>
</trans-unit>
- <trans-unit id="_msg583">
+ <trans-unit id="_msg585">
<source xml:space="preserve">Time Offset</source>
<context-group purpose="location"><context context-type="linenumber">1548</context></context-group>
</trans-unit>
- <trans-unit id="_msg584">
+ <trans-unit id="_msg586">
<source xml:space="preserve">Last block time</source>
<context-group purpose="location"><context context-type="linenumber">290</context></context-group>
</trans-unit>
- <trans-unit id="_msg585">
+ <trans-unit id="_msg587">
<source xml:space="preserve">&amp;Open</source>
<context-group purpose="location"><context context-type="linenumber">400</context></context-group>
</trans-unit>
- <trans-unit id="_msg586">
+ <trans-unit id="_msg588">
<source xml:space="preserve">&amp;Console</source>
<context-group purpose="location"><context context-type="linenumber">426</context></context-group>
</trans-unit>
- <trans-unit id="_msg587">
+ <trans-unit id="_msg589">
<source xml:space="preserve">&amp;Network Traffic</source>
<context-group purpose="location"><context context-type="linenumber">613</context></context-group>
</trans-unit>
- <trans-unit id="_msg588">
+ <trans-unit id="_msg590">
<source xml:space="preserve">Totals</source>
<context-group purpose="location"><context context-type="linenumber">681</context></context-group>
</trans-unit>
- <trans-unit id="_msg589">
+ <trans-unit id="_msg591">
<source xml:space="preserve">Debug log file</source>
<context-group purpose="location"><context context-type="linenumber">390</context></context-group>
</trans-unit>
- <trans-unit id="_msg590">
+ <trans-unit id="_msg592">
<source xml:space="preserve">Clear console</source>
<context-group purpose="location"><context context-type="linenumber">515</context></context-group>
</trans-unit>
@@ -2738,139 +2747,139 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../rpcconsole.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg591">
+ <trans-unit id="_msg593">
<source xml:space="preserve">In:</source>
<context-group purpose="location"><context context-type="linenumber">953</context></context-group>
</trans-unit>
- <trans-unit id="_msg592">
+ <trans-unit id="_msg594">
<source xml:space="preserve">Out:</source>
<context-group purpose="location"><context context-type="linenumber">954</context></context-group>
</trans-unit>
- <trans-unit id="_msg593">
+ <trans-unit id="_msg595">
<source xml:space="preserve">Inbound: initiated by peer</source>
<context-group purpose="location"><context context-type="linenumber">496</context></context-group>
<note annotates="source" from="developer">Explanatory text for an inbound peer connection.</note>
</trans-unit>
- <trans-unit id="_msg594">
+ <trans-unit id="_msg596">
<source xml:space="preserve">Outbound Full Relay: default</source>
<context-group purpose="location"><context context-type="linenumber">500</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</note>
</trans-unit>
- <trans-unit id="_msg595">
+ <trans-unit id="_msg597">
<source xml:space="preserve">Outbound Block Relay: does not relay transactions or addresses</source>
<context-group purpose="location"><context context-type="linenumber">503</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</note>
</trans-unit>
- <trans-unit id="_msg596">
+ <trans-unit id="_msg598">
<source xml:space="preserve">Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
<context-group purpose="location"><context context-type="linenumber">508</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</note>
</trans-unit>
- <trans-unit id="_msg597">
+ <trans-unit id="_msg599">
<source xml:space="preserve">Outbound Feeler: short-lived, for testing addresses</source>
<context-group purpose="location"><context context-type="linenumber">514</context></context-group>
<note annotates="source" from="developer">Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</note>
</trans-unit>
- <trans-unit id="_msg598">
+ <trans-unit id="_msg600">
<source xml:space="preserve">Outbound Address Fetch: short-lived, for soliciting addresses</source>
<context-group purpose="location"><context context-type="linenumber">517</context></context-group>
<note annotates="source" from="developer">Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</note>
</trans-unit>
- <trans-unit id="_msg599">
+ <trans-unit id="_msg601">
<source xml:space="preserve">we selected the peer for high bandwidth relay</source>
<context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg600">
+ <trans-unit id="_msg602">
<source xml:space="preserve">the peer selected us for high bandwidth relay</source>
<context-group purpose="location"><context context-type="linenumber">522</context></context-group>
</trans-unit>
- <trans-unit id="_msg601">
+ <trans-unit id="_msg603">
<source xml:space="preserve">no high bandwidth relay selected</source>
<context-group purpose="location"><context context-type="linenumber">523</context></context-group>
</trans-unit>
- <trans-unit id="_msg602">
+ <trans-unit id="_msg604">
<source xml:space="preserve">Ctrl++</source>
<context-group purpose="location"><context context-type="linenumber">536</context></context-group>
<note annotates="source" from="developer">Main shortcut to increase the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg603">
+ <trans-unit id="_msg605">
<source xml:space="preserve">Ctrl+=</source>
<context-group purpose="location"><context context-type="linenumber">538</context></context-group>
<note annotates="source" from="developer">Secondary shortcut to increase the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg604">
+ <trans-unit id="_msg606">
<source xml:space="preserve">Ctrl+-</source>
<context-group purpose="location"><context context-type="linenumber">542</context></context-group>
<note annotates="source" from="developer">Main shortcut to decrease the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg605">
+ <trans-unit id="_msg607">
<source xml:space="preserve">Ctrl+_</source>
<context-group purpose="location"><context context-type="linenumber">544</context></context-group>
<note annotates="source" from="developer">Secondary shortcut to decrease the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg606">
+ <trans-unit id="_msg608">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">695</context></context-group>
<note annotates="source" from="developer">Context menu action to copy the address of a peer.</note>
</trans-unit>
- <trans-unit id="_msg607">
+ <trans-unit id="_msg609">
<source xml:space="preserve">&amp;Disconnect</source>
<context-group purpose="location"><context context-type="linenumber">699</context></context-group>
</trans-unit>
- <trans-unit id="_msg608">
+ <trans-unit id="_msg610">
<source xml:space="preserve">1 &amp;hour</source>
<context-group purpose="location"><context context-type="linenumber">700</context></context-group>
</trans-unit>
- <trans-unit id="_msg609">
+ <trans-unit id="_msg611">
<source xml:space="preserve">1 d&amp;ay</source>
<context-group purpose="location"><context context-type="linenumber">701</context></context-group>
</trans-unit>
- <trans-unit id="_msg610">
+ <trans-unit id="_msg612">
<source xml:space="preserve">1 &amp;week</source>
<context-group purpose="location"><context context-type="linenumber">702</context></context-group>
</trans-unit>
- <trans-unit id="_msg611">
+ <trans-unit id="_msg613">
<source xml:space="preserve">1 &amp;year</source>
<context-group purpose="location"><context context-type="linenumber">703</context></context-group>
</trans-unit>
- <trans-unit id="_msg612">
+ <trans-unit id="_msg614">
<source xml:space="preserve">&amp;Copy IP/Netmask</source>
<context-group purpose="location"><context context-type="linenumber">729</context></context-group>
<note annotates="source" from="developer">Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer&apos;s IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</note>
</trans-unit>
- <trans-unit id="_msg613">
+ <trans-unit id="_msg615">
<source xml:space="preserve">&amp;Unban</source>
<context-group purpose="location"><context context-type="linenumber">733</context></context-group>
</trans-unit>
- <trans-unit id="_msg614">
+ <trans-unit id="_msg616">
<source xml:space="preserve">Network activity disabled</source>
<context-group purpose="location"><context context-type="linenumber">957</context></context-group>
</trans-unit>
- <trans-unit id="_msg615">
+ <trans-unit id="_msg617">
<source xml:space="preserve">Executing command without any wallet</source>
<context-group purpose="location"><context context-type="linenumber">1035</context></context-group>
</trans-unit>
- <trans-unit id="_msg616">
+ <trans-unit id="_msg618">
<source xml:space="preserve">Ctrl+I</source>
- <context-group purpose="location"><context context-type="linenumber">1351</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1355</context></context-group>
</trans-unit>
- <trans-unit id="_msg617">
+ <trans-unit id="_msg619">
<source xml:space="preserve">Ctrl+T</source>
- <context-group purpose="location"><context context-type="linenumber">1352</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1356</context></context-group>
</trans-unit>
- <trans-unit id="_msg618">
+ <trans-unit id="_msg620">
<source xml:space="preserve">Ctrl+N</source>
- <context-group purpose="location"><context context-type="linenumber">1353</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1357</context></context-group>
</trans-unit>
- <trans-unit id="_msg619">
+ <trans-unit id="_msg621">
<source xml:space="preserve">Ctrl+P</source>
- <context-group purpose="location"><context context-type="linenumber">1354</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
</trans-unit>
- <trans-unit id="_msg620">
+ <trans-unit id="_msg622">
<source xml:space="preserve">Executing command using &quot;%1&quot; wallet</source>
<context-group purpose="location"><context context-type="linenumber">1033</context></context-group>
</trans-unit>
- <trans-unit id="_msg621">
+ <trans-unit id="_msg623">
<source xml:space="preserve">Welcome to the %1 RPC console.
Use up and down arrows to navigate history, and %2 to clear screen.
Use %3 and %4 to increase or decrease the font size.
@@ -2881,16 +2890,16 @@ For more information on using this console, type %6.
<context-group purpose="location"><context context-type="linenumber">887</context></context-group>
<note annotates="source" from="developer">RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</note>
</trans-unit>
- <trans-unit id="_msg622">
+ <trans-unit id="_msg624">
<source xml:space="preserve">Executing…</source>
<context-group purpose="location"><context context-type="linenumber">1043</context></context-group>
<note annotates="source" from="developer">A console message indicating an entered command is currently being executed.</note>
</trans-unit>
- <trans-unit id="_msg623">
+ <trans-unit id="_msg625">
<source xml:space="preserve">(peer: %1)</source>
<context-group purpose="location"><context context-type="linenumber">1161</context></context-group>
</trans-unit>
- <trans-unit id="_msg624">
+ <trans-unit id="_msg626">
<source xml:space="preserve">via %1</source>
<context-group purpose="location"><context context-type="linenumber">1163</context></context-group>
</trans-unit>
@@ -2898,31 +2907,31 @@ For more information on using this console, type %6.
</body></file>
<file original="../rpcconsole.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg625">
+ <trans-unit id="_msg627">
<source xml:space="preserve">Yes</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg626">
+ <trans-unit id="_msg628">
<source xml:space="preserve">No</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg627">
+ <trans-unit id="_msg629">
<source xml:space="preserve">To</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg628">
+ <trans-unit id="_msg630">
<source xml:space="preserve">From</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg629">
+ <trans-unit id="_msg631">
<source xml:space="preserve">Ban for</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg630">
+ <trans-unit id="_msg632">
<source xml:space="preserve">Never</source>
<context-group purpose="location"><context context-type="linenumber">185</context></context-group>
</trans-unit>
- <trans-unit id="_msg631">
+ <trans-unit id="_msg633">
<source xml:space="preserve">Unknown</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
@@ -2930,72 +2939,72 @@ For more information on using this console, type %6.
</body></file>
<file original="../forms/receivecoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog">
- <trans-unit id="_msg632">
+ <trans-unit id="_msg634">
<source xml:space="preserve">&amp;Amount:</source>
<context-group purpose="location"><context context-type="linenumber">37</context></context-group>
</trans-unit>
- <trans-unit id="_msg633">
+ <trans-unit id="_msg635">
<source xml:space="preserve">&amp;Label:</source>
<context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg634">
+ <trans-unit id="_msg636">
<source xml:space="preserve">&amp;Message:</source>
<context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg635">
+ <trans-unit id="_msg637">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg636">
+ <trans-unit id="_msg638">
<source xml:space="preserve">An optional label to associate with the new receiving address.</source>
<context-group purpose="location"><context context-type="linenumber">80</context></context-group>
</trans-unit>
- <trans-unit id="_msg637">
+ <trans-unit id="_msg639">
<source xml:space="preserve">Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg638">
+ <trans-unit id="_msg640">
<source xml:space="preserve">An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
<context-group purpose="location"><context context-type="linenumber">34</context></context-group>
<context-group purpose="location"><context context-type="linenumber">193</context></context-group>
</trans-unit>
- <trans-unit id="_msg639">
+ <trans-unit id="_msg641">
<source xml:space="preserve">An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
<context-group purpose="location"><context context-type="linenumber">66</context></context-group>
</trans-unit>
- <trans-unit id="_msg640">
+ <trans-unit id="_msg642">
<source xml:space="preserve">An optional message that is attached to the payment request and may be displayed to the sender.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg641">
+ <trans-unit id="_msg643">
<source xml:space="preserve">&amp;Create new receiving address</source>
<context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg642">
+ <trans-unit id="_msg644">
<source xml:space="preserve">Clear all fields of the form.</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg643">
+ <trans-unit id="_msg645">
<source xml:space="preserve">Clear</source>
<context-group purpose="location"><context context-type="linenumber">137</context></context-group>
</trans-unit>
- <trans-unit id="_msg644">
+ <trans-unit id="_msg646">
<source xml:space="preserve">Requested payments history</source>
<context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg645">
+ <trans-unit id="_msg647">
<source xml:space="preserve">Show the selected request (does the same as double clicking an entry)</source>
<context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg646">
+ <trans-unit id="_msg648">
<source xml:space="preserve">Show</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
- <trans-unit id="_msg647">
+ <trans-unit id="_msg649">
<source xml:space="preserve">Remove the selected entries from the list</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg648">
+ <trans-unit id="_msg650">
<source xml:space="preserve">Remove</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
@@ -3003,83 +3012,83 @@ For more information on using this console, type %6.
</body></file>
<file original="../receivecoinsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog">
- <trans-unit id="_msg649">
+ <trans-unit id="_msg651">
<source xml:space="preserve">Copy &amp;URI</source>
- <context-group purpose="location"><context context-type="linenumber">47</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">46</context></context-group>
</trans-unit>
- <trans-unit id="_msg650">
+ <trans-unit id="_msg652">
<source xml:space="preserve">&amp;Copy address</source>
- <context-group purpose="location"><context context-type="linenumber">48</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">47</context></context-group>
</trans-unit>
- <trans-unit id="_msg651">
+ <trans-unit id="_msg653">
<source xml:space="preserve">Copy &amp;label</source>
- <context-group purpose="location"><context context-type="linenumber">49</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
- <trans-unit id="_msg652">
+ <trans-unit id="_msg654">
<source xml:space="preserve">Copy &amp;message</source>
- <context-group purpose="location"><context context-type="linenumber">50</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg653">
+ <trans-unit id="_msg655">
<source xml:space="preserve">Copy &amp;amount</source>
- <context-group purpose="location"><context context-type="linenumber">51</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg654">
+ <trans-unit id="_msg656">
<source xml:space="preserve">Could not unlock wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">176</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">175</context></context-group>
</trans-unit>
- <trans-unit id="_msg655">
+ <trans-unit id="_msg657">
<source xml:space="preserve">Could not generate new %1 address</source>
- <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/receiverequestdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog">
- <trans-unit id="_msg656">
+ <trans-unit id="_msg658">
<source xml:space="preserve">Request payment to …</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg657">
+ <trans-unit id="_msg659">
<source xml:space="preserve">Address:</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg658">
+ <trans-unit id="_msg660">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">119</context></context-group>
</trans-unit>
- <trans-unit id="_msg659">
+ <trans-unit id="_msg661">
<source xml:space="preserve">Label:</source>
<context-group purpose="location"><context context-type="linenumber">148</context></context-group>
</trans-unit>
- <trans-unit id="_msg660">
+ <trans-unit id="_msg662">
<source xml:space="preserve">Message:</source>
<context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg661">
+ <trans-unit id="_msg663">
<source xml:space="preserve">Wallet:</source>
<context-group purpose="location"><context context-type="linenumber">212</context></context-group>
</trans-unit>
- <trans-unit id="_msg662">
+ <trans-unit id="_msg664">
<source xml:space="preserve">Copy &amp;URI</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg663">
+ <trans-unit id="_msg665">
<source xml:space="preserve">Copy &amp;Address</source>
<context-group purpose="location"><context context-type="linenumber">250</context></context-group>
</trans-unit>
- <trans-unit id="_msg664">
+ <trans-unit id="_msg666">
<source xml:space="preserve">&amp;Verify</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg665">
+ <trans-unit id="_msg667">
<source xml:space="preserve">Verify this address on e.g. a hardware wallet screen</source>
<context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg666">
+ <trans-unit id="_msg668">
<source xml:space="preserve">&amp;Save Image…</source>
<context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg667">
+ <trans-unit id="_msg669">
<source xml:space="preserve">Payment information</source>
<context-group purpose="location"><context context-type="linenumber">39</context></context-group>
</trans-unit>
@@ -3087,39 +3096,39 @@ For more information on using this console, type %6.
</body></file>
<file original="../receiverequestdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog">
- <trans-unit id="_msg668">
+ <trans-unit id="_msg670">
<source xml:space="preserve">Request payment to %1</source>
- <context-group purpose="location"><context context-type="linenumber">49</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../recentrequeststablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RecentRequestsTableModel">
- <trans-unit id="_msg669">
+ <trans-unit id="_msg671">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg670">
+ <trans-unit id="_msg672">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg671">
+ <trans-unit id="_msg673">
<source xml:space="preserve">Message</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg672">
+ <trans-unit id="_msg674">
<source xml:space="preserve">(no label)</source>
<context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg673">
+ <trans-unit id="_msg675">
<source xml:space="preserve">(no message)</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
- <trans-unit id="_msg674">
+ <trans-unit id="_msg676">
<source xml:space="preserve">(no amount requested)</source>
<context-group purpose="location"><context context-type="linenumber">87</context></context-group>
</trans-unit>
- <trans-unit id="_msg675">
+ <trans-unit id="_msg677">
<source xml:space="preserve">Requested</source>
<context-group purpose="location"><context context-type="linenumber">130</context></context-group>
</trans-unit>
@@ -3127,154 +3136,154 @@ For more information on using this console, type %6.
</body></file>
<file original="../forms/sendcoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsDialog">
- <trans-unit id="_msg676">
+ <trans-unit id="_msg678">
<source xml:space="preserve">Send Coins</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
- <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">757</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">755</context></context-group>
</trans-unit>
- <trans-unit id="_msg677">
+ <trans-unit id="_msg679">
<source xml:space="preserve">Coin Control Features</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg678">
+ <trans-unit id="_msg680">
<source xml:space="preserve">automatically selected</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg679">
+ <trans-unit id="_msg681">
<source xml:space="preserve">Insufficient funds!</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
- <trans-unit id="_msg680">
+ <trans-unit id="_msg682">
<source xml:space="preserve">Quantity:</source>
<context-group purpose="location"><context context-type="linenumber">228</context></context-group>
</trans-unit>
- <trans-unit id="_msg681">
+ <trans-unit id="_msg683">
<source xml:space="preserve">Bytes:</source>
<context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg682">
+ <trans-unit id="_msg684">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
- <trans-unit id="_msg683">
+ <trans-unit id="_msg685">
<source xml:space="preserve">Fee:</source>
<context-group purpose="location"><context context-type="linenumber">391</context></context-group>
</trans-unit>
- <trans-unit id="_msg684">
+ <trans-unit id="_msg686">
<source xml:space="preserve">After Fee:</source>
<context-group purpose="location"><context context-type="linenumber">442</context></context-group>
</trans-unit>
- <trans-unit id="_msg685">
+ <trans-unit id="_msg687">
<source xml:space="preserve">Change:</source>
<context-group purpose="location"><context context-type="linenumber">474</context></context-group>
</trans-unit>
- <trans-unit id="_msg686">
+ <trans-unit id="_msg688">
<source xml:space="preserve">If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
<context-group purpose="location"><context context-type="linenumber">518</context></context-group>
</trans-unit>
- <trans-unit id="_msg687">
+ <trans-unit id="_msg689">
<source xml:space="preserve">Custom change address</source>
<context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg688">
+ <trans-unit id="_msg690">
<source xml:space="preserve">Transaction Fee:</source>
<context-group purpose="location"><context context-type="linenumber">727</context></context-group>
</trans-unit>
- <trans-unit id="_msg689">
+ <trans-unit id="_msg691">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">765</context></context-group>
</trans-unit>
- <trans-unit id="_msg690">
+ <trans-unit id="_msg692">
<source xml:space="preserve">Warning: Fee estimation is currently not possible.</source>
<context-group purpose="location"><context context-type="linenumber">774</context></context-group>
</trans-unit>
- <trans-unit id="_msg691">
+ <trans-unit id="_msg693">
<source xml:space="preserve">per kilobyte</source>
<context-group purpose="location"><context context-type="linenumber">856</context></context-group>
</trans-unit>
- <trans-unit id="_msg692">
+ <trans-unit id="_msg694">
<source xml:space="preserve">Hide</source>
<context-group purpose="location"><context context-type="linenumber">803</context></context-group>
</trans-unit>
- <trans-unit id="_msg693">
+ <trans-unit id="_msg695">
<source xml:space="preserve">Recommended:</source>
<context-group purpose="location"><context context-type="linenumber">915</context></context-group>
</trans-unit>
- <trans-unit id="_msg694">
+ <trans-unit id="_msg696">
<source xml:space="preserve">Custom:</source>
<context-group purpose="location"><context context-type="linenumber">945</context></context-group>
</trans-unit>
- <trans-unit id="_msg695">
+ <trans-unit id="_msg697">
<source xml:space="preserve">Send to multiple recipients at once</source>
<context-group purpose="location"><context context-type="linenumber">1160</context></context-group>
</trans-unit>
- <trans-unit id="_msg696">
+ <trans-unit id="_msg698">
<source xml:space="preserve">Add &amp;Recipient</source>
<context-group purpose="location"><context context-type="linenumber">1163</context></context-group>
</trans-unit>
- <trans-unit id="_msg697">
+ <trans-unit id="_msg699">
<source xml:space="preserve">Clear all fields of the form.</source>
<context-group purpose="location"><context context-type="linenumber">1143</context></context-group>
</trans-unit>
- <trans-unit id="_msg698">
+ <trans-unit id="_msg700">
<source xml:space="preserve">Inputs…</source>
<context-group purpose="location"><context context-type="linenumber">110</context></context-group>
</trans-unit>
- <trans-unit id="_msg699">
+ <trans-unit id="_msg701">
<source xml:space="preserve">Dust:</source>
<context-group purpose="location"><context context-type="linenumber">343</context></context-group>
</trans-unit>
- <trans-unit id="_msg700">
+ <trans-unit id="_msg702">
<source xml:space="preserve">Choose…</source>
<context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg701">
+ <trans-unit id="_msg703">
<source xml:space="preserve">Hide transaction fee settings</source>
<context-group purpose="location"><context context-type="linenumber">800</context></context-group>
</trans-unit>
- <trans-unit id="_msg702">
+ <trans-unit id="_msg704">
<source xml:space="preserve">Specify a custom fee per kB (1,000 bytes) of the transaction&apos;s virtual size.
Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100 satoshis per kvB&quot; for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
<context-group purpose="location"><context context-type="linenumber">851</context></context-group>
</trans-unit>
- <trans-unit id="_msg703">
+ <trans-unit id="_msg705">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">886</context></context-group>
</trans-unit>
- <trans-unit id="_msg704">
+ <trans-unit id="_msg706">
<source xml:space="preserve">A too low fee might result in a never confirming transaction (read the tooltip)</source>
<context-group purpose="location"><context context-type="linenumber">889</context></context-group>
</trans-unit>
- <trans-unit id="_msg705">
+ <trans-unit id="_msg707">
<source xml:space="preserve">(Smart fee not initialized yet. This usually takes a few blocks…)</source>
<context-group purpose="location"><context context-type="linenumber">994</context></context-group>
</trans-unit>
- <trans-unit id="_msg706">
+ <trans-unit id="_msg708">
<source xml:space="preserve">Confirmation time target:</source>
<context-group purpose="location"><context context-type="linenumber">1020</context></context-group>
</trans-unit>
- <trans-unit id="_msg707">
+ <trans-unit id="_msg709">
<source xml:space="preserve">Enable Replace-By-Fee</source>
<context-group purpose="location"><context context-type="linenumber">1078</context></context-group>
</trans-unit>
- <trans-unit id="_msg708">
+ <trans-unit id="_msg710">
<source xml:space="preserve">With Replace-By-Fee (BIP-125) you can increase a transaction&apos;s fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source>
<context-group purpose="location"><context context-type="linenumber">1081</context></context-group>
</trans-unit>
- <trans-unit id="_msg709">
+ <trans-unit id="_msg711">
<source xml:space="preserve">Clear &amp;All</source>
<context-group purpose="location"><context context-type="linenumber">1146</context></context-group>
</trans-unit>
- <trans-unit id="_msg710">
+ <trans-unit id="_msg712">
<source xml:space="preserve">Balance:</source>
<context-group purpose="location"><context context-type="linenumber">1201</context></context-group>
</trans-unit>
- <trans-unit id="_msg711">
+ <trans-unit id="_msg713">
<source xml:space="preserve">Confirm the send action</source>
<context-group purpose="location"><context context-type="linenumber">1117</context></context-group>
</trans-unit>
- <trans-unit id="_msg712">
+ <trans-unit id="_msg714">
<source xml:space="preserve">S&amp;end</source>
<context-group purpose="location"><context context-type="linenumber">1120</context></context-group>
</trans-unit>
@@ -3282,278 +3291,278 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../sendcoinsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsDialog">
- <trans-unit id="_msg713">
+ <trans-unit id="_msg715">
<source xml:space="preserve">Copy quantity</source>
- <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg714">
+ <trans-unit id="_msg716">
<source xml:space="preserve">Copy amount</source>
- <context-group purpose="location"><context context-type="linenumber">100</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg715">
+ <trans-unit id="_msg717">
<source xml:space="preserve">Copy fee</source>
- <context-group purpose="location"><context context-type="linenumber">101</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">97</context></context-group>
</trans-unit>
- <trans-unit id="_msg716">
+ <trans-unit id="_msg718">
<source xml:space="preserve">Copy after fee</source>
- <context-group purpose="location"><context context-type="linenumber">102</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg717">
+ <trans-unit id="_msg719">
<source xml:space="preserve">Copy bytes</source>
- <context-group purpose="location"><context context-type="linenumber">103</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg718">
+ <trans-unit id="_msg720">
<source xml:space="preserve">Copy dust</source>
- <context-group purpose="location"><context context-type="linenumber">104</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
- <trans-unit id="_msg719">
+ <trans-unit id="_msg721">
<source xml:space="preserve">Copy change</source>
- <context-group purpose="location"><context context-type="linenumber">105</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg720">
+ <trans-unit id="_msg722">
<source xml:space="preserve">%1 (%2 blocks)</source>
- <context-group purpose="location"><context context-type="linenumber">179</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">175</context></context-group>
</trans-unit>
- <trans-unit id="_msg721">
+ <trans-unit id="_msg723">
<source xml:space="preserve">Sign on device</source>
- <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">205</context></context-group>
<note annotates="source" from="developer">&quot;device&quot; usually means a hardware wallet.</note>
</trans-unit>
- <trans-unit id="_msg722">
+ <trans-unit id="_msg724">
<source xml:space="preserve">Connect your hardware wallet first.</source>
- <context-group purpose="location"><context context-type="linenumber">212</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg723">
+ <trans-unit id="_msg725">
<source xml:space="preserve">Set external signer script path in Options -&gt; Wallet</source>
- <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">212</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg724">
+ <trans-unit id="_msg726">
<source xml:space="preserve">Cr&amp;eate Unsigned</source>
- <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
</trans-unit>
- <trans-unit id="_msg725">
+ <trans-unit id="_msg727">
<source xml:space="preserve">Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg726">
+ <trans-unit id="_msg728">
<source xml:space="preserve"> from wallet &apos;%1&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
</trans-unit>
- <trans-unit id="_msg727">
+ <trans-unit id="_msg729">
<source xml:space="preserve">%1 to &apos;%2&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg728">
+ <trans-unit id="_msg730">
<source xml:space="preserve">%1 to %2</source>
- <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg729">
+ <trans-unit id="_msg731">
<source xml:space="preserve">To review recipient list click &quot;Show Details…&quot;</source>
- <context-group purpose="location"><context context-type="linenumber">392</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">390</context></context-group>
</trans-unit>
- <trans-unit id="_msg730">
+ <trans-unit id="_msg732">
<source xml:space="preserve">Sign failed</source>
- <context-group purpose="location"><context context-type="linenumber">452</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">450</context></context-group>
</trans-unit>
- <trans-unit id="_msg731">
+ <trans-unit id="_msg733">
<source xml:space="preserve">External signer not found</source>
- <context-group purpose="location"><context context-type="linenumber">457</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">455</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg732">
+ <trans-unit id="_msg734">
<source xml:space="preserve">External signer failure</source>
- <context-group purpose="location"><context context-type="linenumber">462</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">460</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg733">
+ <trans-unit id="_msg735">
<source xml:space="preserve">Save Transaction Data</source>
- <context-group purpose="location"><context context-type="linenumber">428</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">426</context></context-group>
</trans-unit>
- <trans-unit id="_msg734">
+ <trans-unit id="_msg736">
<source xml:space="preserve">Partially Signed Transaction (Binary)</source>
- <context-group purpose="location"><context context-type="linenumber">430</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">428</context></context-group>
<note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note>
</trans-unit>
- <trans-unit id="_msg735">
+ <trans-unit id="_msg737">
<source xml:space="preserve">PSBT saved</source>
- <context-group purpose="location"><context context-type="linenumber">437</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">435</context></context-group>
</trans-unit>
- <trans-unit id="_msg736">
+ <trans-unit id="_msg738">
<source xml:space="preserve">External balance:</source>
- <context-group purpose="location"><context context-type="linenumber">703</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">701</context></context-group>
</trans-unit>
- <trans-unit id="_msg737">
+ <trans-unit id="_msg739">
<source xml:space="preserve">or</source>
- <context-group purpose="location"><context context-type="linenumber">388</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg738">
+ <trans-unit id="_msg740">
<source xml:space="preserve">You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
- <context-group purpose="location"><context context-type="linenumber">370</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">368</context></context-group>
</trans-unit>
- <trans-unit id="_msg739">
+ <trans-unit id="_msg741">
<source xml:space="preserve">Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">340</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">338</context></context-group>
<note annotates="source" from="developer">Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</note>
</trans-unit>
- <trans-unit id="_msg740">
+ <trans-unit id="_msg742">
<source xml:space="preserve">Do you want to create this transaction?</source>
- <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
<note annotates="source" from="developer">Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</note>
</trans-unit>
- <trans-unit id="_msg741">
+ <trans-unit id="_msg743">
<source xml:space="preserve">Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">345</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">343</context></context-group>
<note annotates="source" from="developer">Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</note>
</trans-unit>
- <trans-unit id="_msg742">
+ <trans-unit id="_msg744">
<source xml:space="preserve">Please, review your transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">348</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">346</context></context-group>
<note annotates="source" from="developer">Text to prompt a user to review the details of the transaction they are attempting to send.</note>
</trans-unit>
- <trans-unit id="_msg743">
+ <trans-unit id="_msg745">
<source xml:space="preserve">Transaction fee</source>
- <context-group purpose="location"><context context-type="linenumber">356</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">354</context></context-group>
</trans-unit>
- <trans-unit id="_msg744">
+ <trans-unit id="_msg746">
<source xml:space="preserve">Not signalling Replace-By-Fee, BIP-125.</source>
- <context-group purpose="location"><context context-type="linenumber">372</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">370</context></context-group>
</trans-unit>
- <trans-unit id="_msg745">
+ <trans-unit id="_msg747">
<source xml:space="preserve">Total Amount</source>
- <context-group purpose="location"><context context-type="linenumber">385</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">383</context></context-group>
</trans-unit>
- <trans-unit id="_msg746">
+ <trans-unit id="_msg748">
<source xml:space="preserve">Confirm send coins</source>
- <context-group purpose="location"><context context-type="linenumber">484</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">482</context></context-group>
</trans-unit>
- <trans-unit id="_msg747">
+ <trans-unit id="_msg749">
<source xml:space="preserve">Watch-only balance:</source>
- <context-group purpose="location"><context context-type="linenumber">706</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">704</context></context-group>
</trans-unit>
- <trans-unit id="_msg748">
+ <trans-unit id="_msg750">
<source xml:space="preserve">The recipient address is not valid. Please recheck.</source>
- <context-group purpose="location"><context context-type="linenumber">730</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">728</context></context-group>
</trans-unit>
- <trans-unit id="_msg749">
+ <trans-unit id="_msg751">
<source xml:space="preserve">The amount to pay must be larger than 0.</source>
- <context-group purpose="location"><context context-type="linenumber">733</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">731</context></context-group>
</trans-unit>
- <trans-unit id="_msg750">
+ <trans-unit id="_msg752">
<source xml:space="preserve">The amount exceeds your balance.</source>
- <context-group purpose="location"><context context-type="linenumber">736</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">734</context></context-group>
</trans-unit>
- <trans-unit id="_msg751">
+ <trans-unit id="_msg753">
<source xml:space="preserve">The total exceeds your balance when the %1 transaction fee is included.</source>
- <context-group purpose="location"><context context-type="linenumber">739</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">737</context></context-group>
</trans-unit>
- <trans-unit id="_msg752">
+ <trans-unit id="_msg754">
<source xml:space="preserve">Duplicate address found: addresses should only be used once each.</source>
- <context-group purpose="location"><context context-type="linenumber">742</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">740</context></context-group>
</trans-unit>
- <trans-unit id="_msg753">
+ <trans-unit id="_msg755">
<source xml:space="preserve">Transaction creation failed!</source>
- <context-group purpose="location"><context context-type="linenumber">745</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">743</context></context-group>
</trans-unit>
- <trans-unit id="_msg754">
+ <trans-unit id="_msg756">
<source xml:space="preserve">A fee higher than %1 is considered an absurdly high fee.</source>
- <context-group purpose="location"><context context-type="linenumber">749</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">747</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">872</context></context-group>
- <trans-unit id="_msg755[0]">
+ <context-group purpose="location"><context context-type="linenumber">870</context></context-group>
+ <trans-unit id="_msg757[0]">
<source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source>
</trans-unit>
- <trans-unit id="_msg755[1]">
+ <trans-unit id="_msg757[1]">
<source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source>
</trans-unit>
</group>
- <trans-unit id="_msg756">
+ <trans-unit id="_msg758">
<source xml:space="preserve">Warning: Invalid Bitcoin address</source>
- <context-group purpose="location"><context context-type="linenumber">973</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">971</context></context-group>
</trans-unit>
- <trans-unit id="_msg757">
+ <trans-unit id="_msg759">
<source xml:space="preserve">Warning: Unknown change address</source>
- <context-group purpose="location"><context context-type="linenumber">978</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">976</context></context-group>
</trans-unit>
- <trans-unit id="_msg758">
+ <trans-unit id="_msg760">
<source xml:space="preserve">Confirm custom change address</source>
- <context-group purpose="location"><context context-type="linenumber">981</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">979</context></context-group>
</trans-unit>
- <trans-unit id="_msg759">
+ <trans-unit id="_msg761">
<source xml:space="preserve">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>
- <context-group purpose="location"><context context-type="linenumber">981</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">979</context></context-group>
</trans-unit>
- <trans-unit id="_msg760">
+ <trans-unit id="_msg762">
<source xml:space="preserve">(no label)</source>
- <context-group purpose="location"><context context-type="linenumber">1002</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1000</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/sendcoinsentry.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsEntry">
- <trans-unit id="_msg761">
+ <trans-unit id="_msg763">
<source xml:space="preserve">A&amp;mount:</source>
<context-group purpose="location"><context context-type="linenumber">151</context></context-group>
</trans-unit>
- <trans-unit id="_msg762">
+ <trans-unit id="_msg764">
<source xml:space="preserve">Pay &amp;To:</source>
<context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg763">
+ <trans-unit id="_msg765">
<source xml:space="preserve">&amp;Label:</source>
<context-group purpose="location"><context context-type="linenumber">128</context></context-group>
</trans-unit>
- <trans-unit id="_msg764">
+ <trans-unit id="_msg766">
<source xml:space="preserve">Choose previously used address</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg765">
+ <trans-unit id="_msg767">
<source xml:space="preserve">The Bitcoin address to send the payment to</source>
<context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg766">
+ <trans-unit id="_msg768">
<source xml:space="preserve">Alt+A</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg767">
+ <trans-unit id="_msg769">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg768">
+ <trans-unit id="_msg770">
<source xml:space="preserve">Alt+P</source>
<context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg769">
+ <trans-unit id="_msg771">
<source xml:space="preserve">Remove this entry</source>
<context-group purpose="location"><context context-type="linenumber">106</context></context-group>
</trans-unit>
- <trans-unit id="_msg770">
+ <trans-unit id="_msg772">
<source xml:space="preserve">The amount to send in the selected unit</source>
<context-group purpose="location"><context context-type="linenumber">166</context></context-group>
</trans-unit>
- <trans-unit id="_msg771">
+ <trans-unit id="_msg773">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg772">
+ <trans-unit id="_msg774">
<source xml:space="preserve">S&amp;ubtract fee from amount</source>
<context-group purpose="location"><context context-type="linenumber">176</context></context-group>
</trans-unit>
- <trans-unit id="_msg773">
+ <trans-unit id="_msg775">
<source xml:space="preserve">Use available balance</source>
<context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg774">
+ <trans-unit id="_msg776">
<source xml:space="preserve">Message:</source>
<context-group purpose="location"><context context-type="linenumber">192</context></context-group>
</trans-unit>
- <trans-unit id="_msg775">
+ <trans-unit id="_msg777">
<source xml:space="preserve">Enter a label for this address to add it to the list of used addresses</source>
<context-group purpose="location"><context context-type="linenumber">141</context></context-group>
<context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg776">
+ <trans-unit id="_msg778">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
@@ -3561,11 +3570,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../sendcoinsdialog.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendConfirmationDialog">
- <trans-unit id="_msg777">
+ <trans-unit id="_msg779">
<source xml:space="preserve">Send</source>
<context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg778">
+ <trans-unit id="_msg780">
<source xml:space="preserve">Create Unsigned</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
@@ -3573,105 +3582,105 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../forms/signverifymessagedialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog">
- <trans-unit id="_msg779">
+ <trans-unit id="_msg781">
<source xml:space="preserve">Signatures - Sign / Verify a Message</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg780">
+ <trans-unit id="_msg782">
<source xml:space="preserve">&amp;Sign Message</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg781">
+ <trans-unit id="_msg783">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">33</context></context-group>
</trans-unit>
- <trans-unit id="_msg782">
+ <trans-unit id="_msg784">
<source xml:space="preserve">The Bitcoin address to sign the message with</source>
<context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg783">
+ <trans-unit id="_msg785">
<source xml:space="preserve">Choose previously used address</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
<context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg784">
+ <trans-unit id="_msg786">
<source xml:space="preserve">Alt+A</source>
<context-group purpose="location"><context context-type="linenumber">68</context></context-group>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg785">
+ <trans-unit id="_msg787">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">78</context></context-group>
</trans-unit>
- <trans-unit id="_msg786">
+ <trans-unit id="_msg788">
<source xml:space="preserve">Alt+P</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
</trans-unit>
- <trans-unit id="_msg787">
+ <trans-unit id="_msg789">
<source xml:space="preserve">Enter the message you want to sign here</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
<context-group purpose="location"><context context-type="linenumber">103</context></context-group>
</trans-unit>
- <trans-unit id="_msg788">
+ <trans-unit id="_msg790">
<source xml:space="preserve">Signature</source>
<context-group purpose="location"><context context-type="linenumber">110</context></context-group>
</trans-unit>
- <trans-unit id="_msg789">
+ <trans-unit id="_msg791">
<source xml:space="preserve">Copy the current signature to the system clipboard</source>
<context-group purpose="location"><context context-type="linenumber">140</context></context-group>
</trans-unit>
- <trans-unit id="_msg790">
+ <trans-unit id="_msg792">
<source xml:space="preserve">Sign the message to prove you own this Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">161</context></context-group>
</trans-unit>
- <trans-unit id="_msg791">
+ <trans-unit id="_msg793">
<source xml:space="preserve">Sign &amp;Message</source>
<context-group purpose="location"><context context-type="linenumber">164</context></context-group>
</trans-unit>
- <trans-unit id="_msg792">
+ <trans-unit id="_msg794">
<source xml:space="preserve">Reset all sign message fields</source>
<context-group purpose="location"><context context-type="linenumber">178</context></context-group>
</trans-unit>
- <trans-unit id="_msg793">
+ <trans-unit id="_msg795">
<source xml:space="preserve">Clear &amp;All</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
<context-group purpose="location"><context context-type="linenumber">338</context></context-group>
</trans-unit>
- <trans-unit id="_msg794">
+ <trans-unit id="_msg796">
<source xml:space="preserve">&amp;Verify Message</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg795">
+ <trans-unit id="_msg797">
<source xml:space="preserve">Enter the receiver&apos;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>
<context-group purpose="location"><context context-type="linenumber">246</context></context-group>
</trans-unit>
- <trans-unit id="_msg796">
+ <trans-unit id="_msg798">
<source xml:space="preserve">The Bitcoin address the message was signed with</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg797">
+ <trans-unit id="_msg799">
<source xml:space="preserve">The signed message to verify</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
</trans-unit>
- <trans-unit id="_msg798">
+ <trans-unit id="_msg800">
<source xml:space="preserve">The signature given when the message was signed</source>
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
<context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg799">
+ <trans-unit id="_msg801">
<source xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg800">
+ <trans-unit id="_msg802">
<source xml:space="preserve">Verify &amp;Message</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg801">
+ <trans-unit id="_msg803">
<source xml:space="preserve">Reset all verify message fields</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg802">
+ <trans-unit id="_msg804">
<source xml:space="preserve">Click &quot;Sign Message&quot; to generate signature</source>
<context-group purpose="location"><context context-type="linenumber">125</context></context-group>
</trans-unit>
@@ -3679,164 +3688,164 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../signverifymessagedialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog">
- <trans-unit id="_msg803">
+ <trans-unit id="_msg805">
<source xml:space="preserve">The entered address is invalid.</source>
- <context-group purpose="location"><context context-type="linenumber">120</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">119</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
</trans-unit>
- <trans-unit id="_msg804">
+ <trans-unit id="_msg806">
<source xml:space="preserve">Please check the address and try again.</source>
- <context-group purpose="location"><context context-type="linenumber">120</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">127</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">119</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">126</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg805">
+ <trans-unit id="_msg807">
<source xml:space="preserve">The entered address does not refer to a key.</source>
- <context-group purpose="location"><context context-type="linenumber">127</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">126</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg806">
+ <trans-unit id="_msg808">
<source xml:space="preserve">Wallet unlock was cancelled.</source>
- <context-group purpose="location"><context context-type="linenumber">135</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg807">
+ <trans-unit id="_msg809">
<source xml:space="preserve">No error</source>
- <context-group purpose="location"><context context-type="linenumber">146</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">145</context></context-group>
</trans-unit>
- <trans-unit id="_msg808">
+ <trans-unit id="_msg810">
<source xml:space="preserve">Private key for the entered address is not available.</source>
- <context-group purpose="location"><context context-type="linenumber">149</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">148</context></context-group>
</trans-unit>
- <trans-unit id="_msg809">
+ <trans-unit id="_msg811">
<source xml:space="preserve">Message signing failed.</source>
- <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">151</context></context-group>
</trans-unit>
- <trans-unit id="_msg810">
+ <trans-unit id="_msg812">
<source xml:space="preserve">Message signed.</source>
- <context-group purpose="location"><context context-type="linenumber">164</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">163</context></context-group>
</trans-unit>
- <trans-unit id="_msg811">
+ <trans-unit id="_msg813">
<source xml:space="preserve">The signature could not be decoded.</source>
- <context-group purpose="location"><context context-type="linenumber">233</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">232</context></context-group>
</trans-unit>
- <trans-unit id="_msg812">
+ <trans-unit id="_msg814">
<source xml:space="preserve">Please check the signature and try again.</source>
- <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">233</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg813">
+ <trans-unit id="_msg815">
<source xml:space="preserve">The signature did not match the message digest.</source>
- <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">239</context></context-group>
</trans-unit>
- <trans-unit id="_msg814">
+ <trans-unit id="_msg816">
<source xml:space="preserve">Message verification failed.</source>
- <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">245</context></context-group>
</trans-unit>
- <trans-unit id="_msg815">
+ <trans-unit id="_msg817">
<source xml:space="preserve">Message verified.</source>
- <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../splashscreen.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SplashScreen">
- <trans-unit id="_msg816">
+ <trans-unit id="_msg818">
<source xml:space="preserve">(press q to shutdown and continue later)</source>
- <context-group purpose="location"><context context-type="linenumber">187</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">177</context></context-group>
</trans-unit>
- <trans-unit id="_msg817">
+ <trans-unit id="_msg819">
<source xml:space="preserve">press q to shutdown</source>
- <context-group purpose="location"><context context-type="linenumber">188</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">178</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../trafficgraphwidget.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TrafficGraphWidget">
- <trans-unit id="_msg818">
+ <trans-unit id="_msg820">
<source xml:space="preserve">kB/s</source>
- <context-group purpose="location"><context context-type="linenumber">79</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../transactiondesc.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDesc">
- <trans-unit id="_msg819">
+ <trans-unit id="_msg821">
<source xml:space="preserve">conflicted with a transaction with %1 confirmations</source>
<context-group purpose="location"><context context-type="linenumber">43</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</note>
</trans-unit>
- <trans-unit id="_msg820">
+ <trans-unit id="_msg822">
<source xml:space="preserve">0/unconfirmed, in memory pool</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</note>
</trans-unit>
- <trans-unit id="_msg821">
+ <trans-unit id="_msg823">
<source xml:space="preserve">0/unconfirmed, not in memory pool</source>
<context-group purpose="location"><context context-type="linenumber">55</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</note>
</trans-unit>
- <trans-unit id="_msg822">
+ <trans-unit id="_msg824">
<source xml:space="preserve">abandoned</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</note>
</trans-unit>
- <trans-unit id="_msg823">
+ <trans-unit id="_msg825">
<source xml:space="preserve">%1/unconfirmed</source>
<context-group purpose="location"><context context-type="linenumber">69</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</note>
</trans-unit>
- <trans-unit id="_msg824">
+ <trans-unit id="_msg826">
<source xml:space="preserve">%1 confirmations</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</note>
</trans-unit>
- <trans-unit id="_msg825">
+ <trans-unit id="_msg827">
<source xml:space="preserve">Status</source>
<context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
- <trans-unit id="_msg826">
+ <trans-unit id="_msg828">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">127</context></context-group>
</trans-unit>
- <trans-unit id="_msg827">
+ <trans-unit id="_msg829">
<source xml:space="preserve">Source</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg828">
+ <trans-unit id="_msg830">
<source xml:space="preserve">Generated</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg829">
+ <trans-unit id="_msg831">
<source xml:space="preserve">From</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg830">
+ <trans-unit id="_msg832">
<source xml:space="preserve">unknown</source>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg831">
+ <trans-unit id="_msg833">
<source xml:space="preserve">To</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
<context-group purpose="location"><context context-type="linenumber">174</context></context-group>
<context-group purpose="location"><context context-type="linenumber">244</context></context-group>
</trans-unit>
- <trans-unit id="_msg832">
+ <trans-unit id="_msg834">
<source xml:space="preserve">own address</source>
<context-group purpose="location"><context context-type="linenumber">156</context></context-group>
</trans-unit>
- <trans-unit id="_msg833">
+ <trans-unit id="_msg835">
<source xml:space="preserve">watch-only</source>
<context-group purpose="location"><context context-type="linenumber">156</context></context-group>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg834">
+ <trans-unit id="_msg836">
<source xml:space="preserve">label</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg835">
+ <trans-unit id="_msg837">
<source xml:space="preserve">Credit</source>
<context-group purpose="location"><context context-type="linenumber">194</context></context-group>
<context-group purpose="location"><context context-type="linenumber">206</context></context-group>
@@ -3846,98 +3855,98 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">196</context></context-group>
- <trans-unit id="_msg836[0]">
+ <trans-unit id="_msg838[0]">
<source xml:space="preserve">matures in %n more block(s)</source>
</trans-unit>
- <trans-unit id="_msg836[1]">
+ <trans-unit id="_msg838[1]">
<source xml:space="preserve">matures in %n more block(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg837">
+ <trans-unit id="_msg839">
<source xml:space="preserve">not accepted</source>
<context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
- <trans-unit id="_msg838">
+ <trans-unit id="_msg840">
<source xml:space="preserve">Debit</source>
<context-group purpose="location"><context context-type="linenumber">258</context></context-group>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
<context-group purpose="location"><context context-type="linenumber">347</context></context-group>
</trans-unit>
- <trans-unit id="_msg839">
+ <trans-unit id="_msg841">
<source xml:space="preserve">Total debit</source>
<context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg840">
+ <trans-unit id="_msg842">
<source xml:space="preserve">Total credit</source>
<context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg841">
+ <trans-unit id="_msg843">
<source xml:space="preserve">Transaction fee</source>
<context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg842">
+ <trans-unit id="_msg844">
<source xml:space="preserve">Net amount</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
- <trans-unit id="_msg843">
+ <trans-unit id="_msg845">
<source xml:space="preserve">Message</source>
<context-group purpose="location"><context context-type="linenumber">302</context></context-group>
<context-group purpose="location"><context context-type="linenumber">314</context></context-group>
</trans-unit>
- <trans-unit id="_msg844">
+ <trans-unit id="_msg846">
<source xml:space="preserve">Comment</source>
<context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg845">
+ <trans-unit id="_msg847">
<source xml:space="preserve">Transaction ID</source>
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
- <trans-unit id="_msg846">
+ <trans-unit id="_msg848">
<source xml:space="preserve">Transaction total size</source>
<context-group purpose="location"><context context-type="linenumber">307</context></context-group>
</trans-unit>
- <trans-unit id="_msg847">
+ <trans-unit id="_msg849">
<source xml:space="preserve">Transaction virtual size</source>
<context-group purpose="location"><context context-type="linenumber">308</context></context-group>
</trans-unit>
- <trans-unit id="_msg848">
+ <trans-unit id="_msg850">
<source xml:space="preserve">Output index</source>
<context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg849">
+ <trans-unit id="_msg851">
<source xml:space="preserve"> (Certificate was not verified)</source>
<context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg850">
+ <trans-unit id="_msg852">
<source xml:space="preserve">Merchant</source>
<context-group purpose="location"><context context-type="linenumber">328</context></context-group>
</trans-unit>
- <trans-unit id="_msg851">
+ <trans-unit id="_msg853">
<source xml:space="preserve">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>
<context-group purpose="location"><context context-type="linenumber">336</context></context-group>
</trans-unit>
- <trans-unit id="_msg852">
+ <trans-unit id="_msg854">
<source xml:space="preserve">Debug information</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg853">
+ <trans-unit id="_msg855">
<source xml:space="preserve">Transaction</source>
<context-group purpose="location"><context context-type="linenumber">352</context></context-group>
</trans-unit>
- <trans-unit id="_msg854">
+ <trans-unit id="_msg856">
<source xml:space="preserve">Inputs</source>
<context-group purpose="location"><context context-type="linenumber">355</context></context-group>
</trans-unit>
- <trans-unit id="_msg855">
+ <trans-unit id="_msg857">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg856">
+ <trans-unit id="_msg858">
<source xml:space="preserve">true</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
- <trans-unit id="_msg857">
+ <trans-unit id="_msg859">
<source xml:space="preserve">false</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
@@ -3946,7 +3955,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../forms/transactiondescdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDescDialog">
- <trans-unit id="_msg858">
+ <trans-unit id="_msg860">
<source xml:space="preserve">This pane shows a detailed description of the transaction</source>
<context-group purpose="location"><context context-type="linenumber">20</context></context-group>
</trans-unit>
@@ -3954,7 +3963,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiondescdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDescDialog">
- <trans-unit id="_msg859">
+ <trans-unit id="_msg861">
<source xml:space="preserve">Details for %1</source>
<context-group purpose="location"><context context-type="linenumber">18</context></context-group>
</trans-unit>
@@ -3962,306 +3971,306 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiontablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionTableModel">
- <trans-unit id="_msg860">
+ <trans-unit id="_msg862">
<source xml:space="preserve">Date</source>
- <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg861">
+ <trans-unit id="_msg863">
<source xml:space="preserve">Type</source>
- <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg862">
+ <trans-unit id="_msg864">
<source xml:space="preserve">Label</source>
- <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg863">
+ <trans-unit id="_msg865">
<source xml:space="preserve">Unconfirmed</source>
- <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">317</context></context-group>
</trans-unit>
- <trans-unit id="_msg864">
+ <trans-unit id="_msg866">
<source xml:space="preserve">Abandoned</source>
- <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">320</context></context-group>
</trans-unit>
- <trans-unit id="_msg865">
+ <trans-unit id="_msg867">
<source xml:space="preserve">Confirming (%1 of %2 recommended confirmations)</source>
- <context-group purpose="location"><context context-type="linenumber">327</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg866">
+ <trans-unit id="_msg868">
<source xml:space="preserve">Confirmed (%1 confirmations)</source>
- <context-group purpose="location"><context context-type="linenumber">330</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg867">
+ <trans-unit id="_msg869">
<source xml:space="preserve">Conflicted</source>
- <context-group purpose="location"><context context-type="linenumber">333</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">329</context></context-group>
</trans-unit>
- <trans-unit id="_msg868">
+ <trans-unit id="_msg870">
<source xml:space="preserve">Immature (%1 confirmations, will be available after %2)</source>
- <context-group purpose="location"><context context-type="linenumber">336</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg869">
+ <trans-unit id="_msg871">
<source xml:space="preserve">Generated but not accepted</source>
- <context-group purpose="location"><context context-type="linenumber">339</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg870">
+ <trans-unit id="_msg872">
<source xml:space="preserve">Received with</source>
- <context-group purpose="location"><context context-type="linenumber">378</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">374</context></context-group>
</trans-unit>
- <trans-unit id="_msg871">
+ <trans-unit id="_msg873">
<source xml:space="preserve">Received from</source>
- <context-group purpose="location"><context context-type="linenumber">380</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg872">
+ <trans-unit id="_msg874">
<source xml:space="preserve">Sent to</source>
- <context-group purpose="location"><context context-type="linenumber">383</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">379</context></context-group>
</trans-unit>
- <trans-unit id="_msg873">
+ <trans-unit id="_msg875">
<source xml:space="preserve">Payment to yourself</source>
- <context-group purpose="location"><context context-type="linenumber">385</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">381</context></context-group>
</trans-unit>
- <trans-unit id="_msg874">
+ <trans-unit id="_msg876">
<source xml:space="preserve">Mined</source>
- <context-group purpose="location"><context context-type="linenumber">387</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">383</context></context-group>
</trans-unit>
- <trans-unit id="_msg875">
+ <trans-unit id="_msg877">
<source xml:space="preserve">watch-only</source>
- <context-group purpose="location"><context context-type="linenumber">415</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">411</context></context-group>
</trans-unit>
- <trans-unit id="_msg876">
+ <trans-unit id="_msg878">
<source xml:space="preserve">(n/a)</source>
- <context-group purpose="location"><context context-type="linenumber">431</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">427</context></context-group>
</trans-unit>
- <trans-unit id="_msg877">
+ <trans-unit id="_msg879">
<source xml:space="preserve">(no label)</source>
- <context-group purpose="location"><context context-type="linenumber">638</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">634</context></context-group>
</trans-unit>
- <trans-unit id="_msg878">
+ <trans-unit id="_msg880">
<source xml:space="preserve">Transaction status. Hover over this field to show number of confirmations.</source>
- <context-group purpose="location"><context context-type="linenumber">677</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">673</context></context-group>
</trans-unit>
- <trans-unit id="_msg879">
+ <trans-unit id="_msg881">
<source xml:space="preserve">Date and time that the transaction was received.</source>
- <context-group purpose="location"><context context-type="linenumber">679</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">675</context></context-group>
</trans-unit>
- <trans-unit id="_msg880">
+ <trans-unit id="_msg882">
<source xml:space="preserve">Type of transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">681</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">677</context></context-group>
</trans-unit>
- <trans-unit id="_msg881">
+ <trans-unit id="_msg883">
<source xml:space="preserve">Whether or not a watch-only address is involved in this transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">683</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">679</context></context-group>
</trans-unit>
- <trans-unit id="_msg882">
+ <trans-unit id="_msg884">
<source xml:space="preserve">User-defined intent/purpose of the transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">685</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">681</context></context-group>
</trans-unit>
- <trans-unit id="_msg883">
+ <trans-unit id="_msg885">
<source xml:space="preserve">Amount removed from or added to balance.</source>
- <context-group purpose="location"><context context-type="linenumber">687</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">683</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../transactionview.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionView">
- <trans-unit id="_msg884">
+ <trans-unit id="_msg886">
<source xml:space="preserve">All</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
<context-group purpose="location"><context context-type="linenumber">89</context></context-group>
</trans-unit>
- <trans-unit id="_msg885">
+ <trans-unit id="_msg887">
<source xml:space="preserve">Today</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
- <trans-unit id="_msg886">
+ <trans-unit id="_msg888">
<source xml:space="preserve">This week</source>
<context-group purpose="location"><context context-type="linenumber">75</context></context-group>
</trans-unit>
- <trans-unit id="_msg887">
+ <trans-unit id="_msg889">
<source xml:space="preserve">This month</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg888">
+ <trans-unit id="_msg890">
<source xml:space="preserve">Last month</source>
<context-group purpose="location"><context context-type="linenumber">77</context></context-group>
</trans-unit>
- <trans-unit id="_msg889">
+ <trans-unit id="_msg891">
<source xml:space="preserve">This year</source>
<context-group purpose="location"><context context-type="linenumber">78</context></context-group>
</trans-unit>
- <trans-unit id="_msg890">
+ <trans-unit id="_msg892">
<source xml:space="preserve">Received with</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg891">
+ <trans-unit id="_msg893">
<source xml:space="preserve">Sent to</source>
<context-group purpose="location"><context context-type="linenumber">92</context></context-group>
</trans-unit>
- <trans-unit id="_msg892">
+ <trans-unit id="_msg894">
<source xml:space="preserve">To yourself</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
</trans-unit>
- <trans-unit id="_msg893">
+ <trans-unit id="_msg895">
<source xml:space="preserve">Mined</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg894">
+ <trans-unit id="_msg896">
<source xml:space="preserve">Other</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg895">
+ <trans-unit id="_msg897">
<source xml:space="preserve">Enter address, transaction id, or label to search</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg896">
+ <trans-unit id="_msg898">
<source xml:space="preserve">Min amount</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg897">
+ <trans-unit id="_msg899">
<source xml:space="preserve">Range…</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
- <trans-unit id="_msg898">
+ <trans-unit id="_msg900">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">169</context></context-group>
</trans-unit>
- <trans-unit id="_msg899">
+ <trans-unit id="_msg901">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg900">
+ <trans-unit id="_msg902">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">171</context></context-group>
</trans-unit>
- <trans-unit id="_msg901">
+ <trans-unit id="_msg903">
<source xml:space="preserve">Copy transaction &amp;ID</source>
<context-group purpose="location"><context context-type="linenumber">172</context></context-group>
</trans-unit>
- <trans-unit id="_msg902">
+ <trans-unit id="_msg904">
<source xml:space="preserve">Copy &amp;raw transaction</source>
<context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg903">
+ <trans-unit id="_msg905">
<source xml:space="preserve">Copy full transaction &amp;details</source>
<context-group purpose="location"><context context-type="linenumber">174</context></context-group>
</trans-unit>
- <trans-unit id="_msg904">
+ <trans-unit id="_msg906">
<source xml:space="preserve">&amp;Show transaction details</source>
<context-group purpose="location"><context context-type="linenumber">175</context></context-group>
</trans-unit>
- <trans-unit id="_msg905">
+ <trans-unit id="_msg907">
<source xml:space="preserve">Increase transaction &amp;fee</source>
<context-group purpose="location"><context context-type="linenumber">177</context></context-group>
</trans-unit>
- <trans-unit id="_msg906">
+ <trans-unit id="_msg908">
<source xml:space="preserve">A&amp;bandon transaction</source>
<context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg907">
+ <trans-unit id="_msg909">
<source xml:space="preserve">&amp;Edit address label</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
</trans-unit>
- <trans-unit id="_msg908">
+ <trans-unit id="_msg910">
<source xml:space="preserve">Show in %1</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
<note annotates="source" from="developer">Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</note>
</trans-unit>
- <trans-unit id="_msg909">
+ <trans-unit id="_msg911">
<source xml:space="preserve">Export Transaction History</source>
<context-group purpose="location"><context context-type="linenumber">359</context></context-group>
</trans-unit>
- <trans-unit id="_msg910">
+ <trans-unit id="_msg912">
<source xml:space="preserve">Comma separated file</source>
<context-group purpose="location"><context context-type="linenumber">362</context></context-group>
<note annotates="source" from="developer">Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</note>
</trans-unit>
- <trans-unit id="_msg911">
+ <trans-unit id="_msg913">
<source xml:space="preserve">Confirmed</source>
<context-group purpose="location"><context context-type="linenumber">371</context></context-group>
</trans-unit>
- <trans-unit id="_msg912">
+ <trans-unit id="_msg914">
<source xml:space="preserve">Watch-only</source>
<context-group purpose="location"><context context-type="linenumber">373</context></context-group>
</trans-unit>
- <trans-unit id="_msg913">
+ <trans-unit id="_msg915">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">374</context></context-group>
</trans-unit>
- <trans-unit id="_msg914">
+ <trans-unit id="_msg916">
<source xml:space="preserve">Type</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
</trans-unit>
- <trans-unit id="_msg915">
+ <trans-unit id="_msg917">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg916">
+ <trans-unit id="_msg918">
<source xml:space="preserve">Address</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
</trans-unit>
- <trans-unit id="_msg917">
+ <trans-unit id="_msg919">
<source xml:space="preserve">ID</source>
<context-group purpose="location"><context context-type="linenumber">379</context></context-group>
</trans-unit>
- <trans-unit id="_msg918">
+ <trans-unit id="_msg920">
<source xml:space="preserve">Exporting Failed</source>
<context-group purpose="location"><context context-type="linenumber">382</context></context-group>
</trans-unit>
- <trans-unit id="_msg919">
+ <trans-unit id="_msg921">
<source xml:space="preserve">There was an error trying to save the transaction history to %1.</source>
<context-group purpose="location"><context context-type="linenumber">382</context></context-group>
</trans-unit>
- <trans-unit id="_msg920">
+ <trans-unit id="_msg922">
<source xml:space="preserve">Exporting Successful</source>
<context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg921">
+ <trans-unit id="_msg923">
<source xml:space="preserve">The transaction history was successfully saved to %1.</source>
<context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg922">
+ <trans-unit id="_msg924">
<source xml:space="preserve">Range:</source>
- <context-group purpose="location"><context context-type="linenumber">558</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">555</context></context-group>
</trans-unit>
- <trans-unit id="_msg923">
+ <trans-unit id="_msg925">
<source xml:space="preserve">to</source>
- <context-group purpose="location"><context context-type="linenumber">566</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">563</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../walletframe.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletFrame">
- <trans-unit id="_msg924">
+ <trans-unit id="_msg926">
<source xml:space="preserve">No wallet has been loaded.
Go to File &gt; Open Wallet to load a wallet.
- OR -</source>
<context-group purpose="location"><context context-type="linenumber">45</context></context-group>
</trans-unit>
- <trans-unit id="_msg925">
+ <trans-unit id="_msg927">
<source xml:space="preserve">Create a new wallet</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg926">
+ <trans-unit id="_msg928">
<source xml:space="preserve">Error</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
<context-group purpose="location"><context context-type="linenumber">211</context></context-group>
<context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
- <trans-unit id="_msg927">
+ <trans-unit id="_msg929">
<source xml:space="preserve">Unable to decode PSBT from clipboard (invalid base64)</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
</trans-unit>
- <trans-unit id="_msg928">
+ <trans-unit id="_msg930">
<source xml:space="preserve">Load Transaction Data</source>
<context-group purpose="location"><context context-type="linenumber">207</context></context-group>
</trans-unit>
- <trans-unit id="_msg929">
+ <trans-unit id="_msg931">
<source xml:space="preserve">Partially Signed Transaction (*.psbt)</source>
<context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg930">
+ <trans-unit id="_msg932">
<source xml:space="preserve">PSBT file must be smaller than 100 MiB</source>
<context-group purpose="location"><context context-type="linenumber">211</context></context-group>
</trans-unit>
- <trans-unit id="_msg931">
+ <trans-unit id="_msg933">
<source xml:space="preserve">Unable to decode PSBT</source>
<context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
@@ -4269,896 +4278,948 @@ Go to File &gt; Open Wallet to load a wallet.
</body></file>
<file original="../walletmodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletModel">
- <trans-unit id="_msg932">
+ <trans-unit id="_msg934">
<source xml:space="preserve">Send Coins</source>
- <context-group purpose="location"><context context-type="linenumber">232</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">228</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg933">
+ <trans-unit id="_msg935">
<source xml:space="preserve">Fee bump error</source>
- <context-group purpose="location"><context context-type="linenumber">495</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">547</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">562</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">567</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">489</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">544</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">559</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">564</context></context-group>
</trans-unit>
- <trans-unit id="_msg934">
+ <trans-unit id="_msg936">
<source xml:space="preserve">Increasing transaction fee failed</source>
- <context-group purpose="location"><context context-type="linenumber">495</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">489</context></context-group>
</trans-unit>
- <trans-unit id="_msg935">
+ <trans-unit id="_msg937">
<source xml:space="preserve">Do you want to increase the fee?</source>
- <context-group purpose="location"><context context-type="linenumber">502</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">496</context></context-group>
<note annotates="source" from="developer">Asks a user if they would like to manually increase the fee of a transaction that has already been created.</note>
</trans-unit>
- <trans-unit id="_msg936">
+ <trans-unit id="_msg938">
<source xml:space="preserve">Current fee:</source>
- <context-group purpose="location"><context context-type="linenumber">506</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">500</context></context-group>
</trans-unit>
- <trans-unit id="_msg937">
+ <trans-unit id="_msg939">
<source xml:space="preserve">Increase:</source>
- <context-group purpose="location"><context context-type="linenumber">510</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">504</context></context-group>
</trans-unit>
- <trans-unit id="_msg938">
+ <trans-unit id="_msg940">
<source xml:space="preserve">New fee:</source>
- <context-group purpose="location"><context context-type="linenumber">514</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">508</context></context-group>
</trans-unit>
- <trans-unit id="_msg939">
+ <trans-unit id="_msg941">
<source xml:space="preserve">Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
- <context-group purpose="location"><context context-type="linenumber">522</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">516</context></context-group>
</trans-unit>
- <trans-unit id="_msg940">
+ <trans-unit id="_msg942">
<source xml:space="preserve">Confirm fee bump</source>
- <context-group purpose="location"><context context-type="linenumber">525</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg941">
+ <trans-unit id="_msg943">
<source xml:space="preserve">Can&apos;t draft transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">547</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">544</context></context-group>
</trans-unit>
- <trans-unit id="_msg942">
+ <trans-unit id="_msg944">
<source xml:space="preserve">PSBT copied</source>
- <context-group purpose="location"><context context-type="linenumber">554</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">551</context></context-group>
</trans-unit>
- <trans-unit id="_msg943">
+ <trans-unit id="_msg945">
<source xml:space="preserve">Can&apos;t sign transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">562</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">559</context></context-group>
</trans-unit>
- <trans-unit id="_msg944">
+ <trans-unit id="_msg946">
<source xml:space="preserve">Could not commit transaction</source>
- <context-group purpose="location"><context context-type="linenumber">567</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">564</context></context-group>
</trans-unit>
- <trans-unit id="_msg945">
+ <trans-unit id="_msg947">
<source xml:space="preserve">Can&apos;t display address</source>
- <context-group purpose="location"><context context-type="linenumber">581</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">578</context></context-group>
</trans-unit>
- <trans-unit id="_msg946">
+ <trans-unit id="_msg948">
<source xml:space="preserve">default wallet</source>
- <context-group purpose="location"><context context-type="linenumber">599</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">596</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../walletview.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletView">
- <trans-unit id="_msg947">
+ <trans-unit id="_msg949">
<source xml:space="preserve">&amp;Export</source>
- <context-group purpose="location"><context context-type="linenumber">51</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg948">
+ <trans-unit id="_msg950">
<source xml:space="preserve">Export the data in the current tab to a file</source>
- <context-group purpose="location"><context context-type="linenumber">52</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg949">
+ <trans-unit id="_msg951">
<source xml:space="preserve">Backup Wallet</source>
- <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
</trans-unit>
- <trans-unit id="_msg950">
+ <trans-unit id="_msg952">
<source xml:space="preserve">Wallet Data</source>
- <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
<note annotates="source" from="developer">Name of the wallet data file format.</note>
</trans-unit>
- <trans-unit id="_msg951">
+ <trans-unit id="_msg953">
<source xml:space="preserve">Backup Failed</source>
- <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
</trans-unit>
- <trans-unit id="_msg952">
+ <trans-unit id="_msg954">
<source xml:space="preserve">There was an error trying to save the wallet data to %1.</source>
- <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
</trans-unit>
- <trans-unit id="_msg953">
+ <trans-unit id="_msg955">
<source xml:space="preserve">Backup Successful</source>
- <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg954">
+ <trans-unit id="_msg956">
<source xml:space="preserve">The wallet data was successfully saved to %1.</source>
- <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg955">
+ <trans-unit id="_msg957">
<source xml:space="preserve">Cancel</source>
- <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../bitcoinstrings.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="bitcoin-core">
- <trans-unit id="_msg956">
+ <trans-unit id="_msg958">
<source xml:space="preserve">The %s developers</source>
<context-group purpose="location"><context context-type="linenumber">12</context></context-group>
</trans-unit>
- <trans-unit id="_msg957">
+ <trans-unit id="_msg959">
<source xml:space="preserve">%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
<context-group purpose="location"><context context-type="linenumber">13</context></context-group>
</trans-unit>
- <trans-unit id="_msg958">
+ <trans-unit id="_msg960">
+ <source xml:space="preserve">%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any peer will connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <context-group purpose="location"><context context-type="linenumber">16</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg961">
<source xml:space="preserve">-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<context-group purpose="location"><context context-type="linenumber">20</context></context-group>
</trans-unit>
- <trans-unit id="_msg959">
+ <trans-unit id="_msg962">
<source xml:space="preserve">Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
- <context-group purpose="location"><context context-type="linenumber">38</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg960">
+ <trans-unit id="_msg963">
<source xml:space="preserve">Cannot obtain a lock on data directory %s. %s is probably already running.</source>
- <context-group purpose="location"><context context-type="linenumber">41</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg961">
+ <trans-unit id="_msg964">
<source xml:space="preserve">Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
- <context-group purpose="location"><context context-type="linenumber">46</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">43</context></context-group>
</trans-unit>
- <trans-unit id="_msg962">
+ <trans-unit id="_msg965">
+ <source xml:space="preserve">Disk space for %s may not accommodate the block files. Approximately %u GB of data will be stored in this directory.</source>
+ <context-group purpose="location"><context context-type="linenumber">47</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg966">
<source xml:space="preserve">Distributed under the MIT software license, see the accompanying file %s or %s</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg963">
- <source xml:space="preserve">Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
+ <trans-unit id="_msg967">
+ <source xml:space="preserve">Error loading wallet. Wallet requires blocks to be downloaded, and software does not currently support loading wallets while blocks are being downloaded out of order when using assumeutxo snapshots. Wallet should be able to load successfully after node sync reaches height %s</source>
<context-group purpose="location"><context context-type="linenumber">56</context></context-group>
</trans-unit>
- <trans-unit id="_msg964">
+ <trans-unit id="_msg968">
+ <source xml:space="preserve">Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
+ <context-group purpose="location"><context context-type="linenumber">61</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg969">
<source xml:space="preserve">Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">59</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">64</context></context-group>
</trans-unit>
- <trans-unit id="_msg965">
+ <trans-unit id="_msg970">
<source xml:space="preserve">Error: Dumpfile format record is incorrect. Got &quot;%s&quot;, expected &quot;format&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">65</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg966">
+ <trans-unit id="_msg971">
<source xml:space="preserve">Error: Dumpfile identifier record is incorrect. Got &quot;%s&quot;, expected &quot;%s&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">67</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">72</context></context-group>
</trans-unit>
- <trans-unit id="_msg967">
+ <trans-unit id="_msg972">
<source xml:space="preserve">Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
- <context-group purpose="location"><context context-type="linenumber">69</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
- <trans-unit id="_msg968">
+ <trans-unit id="_msg973">
<source xml:space="preserve">Error: Legacy wallets only support the &quot;legacy&quot;, &quot;p2sh-segwit&quot;, and &quot;bech32&quot; address types</source>
- <context-group purpose="location"><context context-type="linenumber">75</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">80</context></context-group>
</trans-unit>
- <trans-unit id="_msg969">
+ <trans-unit id="_msg974">
+ <source xml:space="preserve">Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet&apos;s passphrase if it is encrypted.</source>
+ <context-group purpose="location"><context context-type="linenumber">86</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg975">
<source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
- <context-group purpose="location"><context context-type="linenumber">87</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">92</context></context-group>
</trans-unit>
- <trans-unit id="_msg970">
+ <trans-unit id="_msg976">
<source xml:space="preserve">File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
- <context-group purpose="location"><context context-type="linenumber">90</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg971">
+ <trans-unit id="_msg977">
<source xml:space="preserve">Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
- <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg972">
+ <trans-unit id="_msg978">
<source xml:space="preserve">Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
- <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">104</context></context-group>
</trans-unit>
- <trans-unit id="_msg973">
+ <trans-unit id="_msg979">
<source xml:space="preserve">More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
- <context-group purpose="location"><context context-type="linenumber">103</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
- <trans-unit id="_msg974">
+ <trans-unit id="_msg980">
<source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">106</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg975">
+ <trans-unit id="_msg981">
<source xml:space="preserve">No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">109</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">114</context></context-group>
</trans-unit>
- <trans-unit id="_msg976">
+ <trans-unit id="_msg982">
<source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">116</context></context-group>
</trans-unit>
- <trans-unit id="_msg977">
+ <trans-unit id="_msg983">
<source xml:space="preserve">Please check that your computer&apos;s date and time are correct! If your clock is wrong, %s will not work properly.</source>
- <context-group purpose="location"><context context-type="linenumber">121</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">132</context></context-group>
</trans-unit>
- <trans-unit id="_msg978">
+ <trans-unit id="_msg984">
<source xml:space="preserve">Please contribute if you find %s useful. Visit %s for further information about the software.</source>
- <context-group purpose="location"><context context-type="linenumber">124</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">135</context></context-group>
</trans-unit>
- <trans-unit id="_msg979">
+ <trans-unit id="_msg985">
<source xml:space="preserve">Prune configured below the minimum of %d MiB. Please use a higher number.</source>
- <context-group purpose="location"><context context-type="linenumber">127</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
</trans-unit>
- <trans-unit id="_msg980">
+ <trans-unit id="_msg986">
<source xml:space="preserve">Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
- <context-group purpose="location"><context context-type="linenumber">129</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">140</context></context-group>
</trans-unit>
- <trans-unit id="_msg981">
+ <trans-unit id="_msg987">
<source xml:space="preserve">Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source>
- <context-group purpose="location"><context context-type="linenumber">132</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg982">
+ <trans-unit id="_msg988">
<source xml:space="preserve">SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
- <context-group purpose="location"><context context-type="linenumber">135</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
- <trans-unit id="_msg983">
+ <trans-unit id="_msg989">
<source xml:space="preserve">The block database contains a block which appears to be from the future. This may be due to your computer&apos;s date and time being set incorrectly. Only rebuild the block database if you are sure that your computer&apos;s date and time are correct</source>
- <context-group purpose="location"><context context-type="linenumber">141</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg984">
+ <trans-unit id="_msg990">
<source xml:space="preserve">The block index db contains a legacy &apos;txindex&apos;. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
- <context-group purpose="location"><context context-type="linenumber">146</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">157</context></context-group>
</trans-unit>
- <trans-unit id="_msg985">
+ <trans-unit id="_msg991">
<source xml:space="preserve">The transaction amount is too small to send after the fee has been deducted</source>
- <context-group purpose="location"><context context-type="linenumber">150</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">168</context></context-group>
</trans-unit>
- <trans-unit id="_msg986">
+ <trans-unit id="_msg992">
<source xml:space="preserve">This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source>
- <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg987">
+ <trans-unit id="_msg993">
<source xml:space="preserve">This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
- <context-group purpose="location"><context context-type="linenumber">156</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">174</context></context-group>
</trans-unit>
- <trans-unit id="_msg988">
+ <trans-unit id="_msg994">
<source xml:space="preserve">This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
- <context-group purpose="location"><context context-type="linenumber">159</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">177</context></context-group>
</trans-unit>
- <trans-unit id="_msg989">
+ <trans-unit id="_msg995">
<source xml:space="preserve">This is the transaction fee you may discard if change is smaller than dust at this level</source>
- <context-group purpose="location"><context context-type="linenumber">162</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg990">
+ <trans-unit id="_msg996">
<source xml:space="preserve">This is the transaction fee you may pay when fee estimates are not available.</source>
- <context-group purpose="location"><context context-type="linenumber">165</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg991">
+ <trans-unit id="_msg997">
<source xml:space="preserve">Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
- <context-group purpose="location"><context context-type="linenumber">167</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">185</context></context-group>
</trans-unit>
- <trans-unit id="_msg992">
+ <trans-unit id="_msg998">
<source xml:space="preserve">Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
- <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">188</context></context-group>
</trans-unit>
- <trans-unit id="_msg993">
+ <trans-unit id="_msg999">
<source xml:space="preserve">Unknown wallet file format &quot;%s&quot; provided. Please provide one of &quot;bdb&quot; or &quot;sqlite&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">195</context></context-group>
</trans-unit>
- <trans-unit id="_msg994">
+ <trans-unit id="_msg1000">
<source xml:space="preserve">Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
- <context-group purpose="location"><context context-type="linenumber">184</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
</trans-unit>
- <trans-unit id="_msg995">
+ <trans-unit id="_msg1001">
<source xml:space="preserve">Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
- <context-group purpose="location"><context context-type="linenumber">187</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
</trans-unit>
- <trans-unit id="_msg996">
+ <trans-unit id="_msg1002">
<source xml:space="preserve">Warning: Dumpfile wallet format &quot;%s&quot; does not match command line specified format &quot;%s&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">191</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
</trans-unit>
- <trans-unit id="_msg997">
+ <trans-unit id="_msg1003">
<source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source>
- <context-group purpose="location"><context context-type="linenumber">194</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg998">
+ <trans-unit id="_msg1004">
<source xml:space="preserve">Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
- <context-group purpose="location"><context context-type="linenumber">196</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
</trans-unit>
- <trans-unit id="_msg999">
+ <trans-unit id="_msg1005">
<source xml:space="preserve">Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
- <context-group purpose="location"><context context-type="linenumber">199</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
</trans-unit>
- <trans-unit id="_msg1000">
+ <trans-unit id="_msg1006">
<source xml:space="preserve">You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
- <context-group purpose="location"><context context-type="linenumber">202</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
</trans-unit>
- <trans-unit id="_msg1001">
+ <trans-unit id="_msg1007">
<source xml:space="preserve">%s is set very high!</source>
- <context-group purpose="location"><context context-type="linenumber">211</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">233</context></context-group>
</trans-unit>
- <trans-unit id="_msg1002">
+ <trans-unit id="_msg1008">
<source xml:space="preserve">-maxmempool must be at least %d MB</source>
- <context-group purpose="location"><context context-type="linenumber">212</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
</trans-unit>
- <trans-unit id="_msg1003">
+ <trans-unit id="_msg1009">
<source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source>
- <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">235</context></context-group>
</trans-unit>
- <trans-unit id="_msg1004">
+ <trans-unit id="_msg1010">
<source xml:space="preserve">Cannot resolve -%s address: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">236</context></context-group>
</trans-unit>
- <trans-unit id="_msg1005">
+ <trans-unit id="_msg1011">
<source xml:space="preserve">Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
- <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">237</context></context-group>
</trans-unit>
- <trans-unit id="_msg1006">
+ <trans-unit id="_msg1012">
<source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source>
- <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg1007">
+ <trans-unit id="_msg1013">
<source xml:space="preserve">Cannot write to data directory &apos;%s&apos;; check permissions.</source>
- <context-group purpose="location"><context context-type="linenumber">217</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">239</context></context-group>
</trans-unit>
- <trans-unit id="_msg1008">
+ <trans-unit id="_msg1014">
<source xml:space="preserve">The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
- <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
- </trans-unit>
- <trans-unit id="_msg1009">
- <source xml:space="preserve">%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
- <context-group purpose="location"><context context-type="linenumber">16</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">149</context></context-group>
</trans-unit>
- <trans-unit id="_msg1010">
+ <trans-unit id="_msg1015">
<source xml:space="preserve">-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
<context-group purpose="location"><context context-type="linenumber">23</context></context-group>
</trans-unit>
- <trans-unit id="_msg1011">
+ <trans-unit id="_msg1016">
<source xml:space="preserve">-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg1012">
+ <trans-unit id="_msg1017">
<source xml:space="preserve">-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
<context-group purpose="location"><context context-type="linenumber">31</context></context-group>
</trans-unit>
- <trans-unit id="_msg1013">
- <source xml:space="preserve">Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
- <context-group purpose="location"><context context-type="linenumber">35</context></context-group>
- </trans-unit>
- <trans-unit id="_msg1014">
+ <trans-unit id="_msg1018">
<source xml:space="preserve">Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
- <context-group purpose="location"><context context-type="linenumber">43</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">40</context></context-group>
</trans-unit>
- <trans-unit id="_msg1015">
+ <trans-unit id="_msg1019">
<source xml:space="preserve">Error loading %s: External signer wallet being loaded without external signer support compiled</source>
<context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg1016">
+ <trans-unit id="_msg1020">
<source xml:space="preserve">Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
- <context-group purpose="location"><context context-type="linenumber">62</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">67</context></context-group>
</trans-unit>
- <trans-unit id="_msg1017">
+ <trans-unit id="_msg1021">
<source xml:space="preserve">Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
- <context-group purpose="location"><context context-type="linenumber">72</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">77</context></context-group>
</trans-unit>
- <trans-unit id="_msg1018">
+ <trans-unit id="_msg1022">
<source xml:space="preserve">Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
- <context-group purpose="location"><context context-type="linenumber">78</context></context-group>
- </trans-unit>
- <trans-unit id="_msg1019">
- <source xml:space="preserve">Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
- <context-group purpose="location"><context context-type="linenumber">81</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg1020">
+ <trans-unit id="_msg1023">
<source xml:space="preserve">Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
- <context-group purpose="location"><context context-type="linenumber">84</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">89</context></context-group>
</trans-unit>
- <trans-unit id="_msg1021">
+ <trans-unit id="_msg1024">
<source xml:space="preserve">Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
- <context-group purpose="location"><context context-type="linenumber">93</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg1022">
+ <trans-unit id="_msg1025">
+ <source xml:space="preserve">Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source>
+ <context-group purpose="location"><context context-type="linenumber">119</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1026">
<source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
- <context-group purpose="location"><context context-type="linenumber">114</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg1023">
+ <trans-unit id="_msg1027">
<source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
- <context-group purpose="location"><context context-type="linenumber">117</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">125</context></context-group>
</trans-unit>
- <trans-unit id="_msg1024">
+ <trans-unit id="_msg1028">
+ <source xml:space="preserve">Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source>
+ <context-group purpose="location"><context context-type="linenumber">129</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1029">
+ <source xml:space="preserve">The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet&apos;s UTXOs</source>
+ <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1030">
+ <source xml:space="preserve">The preselected coins total amount does not cover the transaction target. Please allow other inputs to be automatically selected or include more coins manually</source>
+ <context-group purpose="location"><context context-type="linenumber">164</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1031">
+ <source xml:space="preserve">Unexpected legacy entry in descriptor wallet found. Loading wallet %s
+
+The wallet might have been tampered with or created with malicious intent.
+</source>
+ <context-group purpose="location"><context context-type="linenumber">191</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1032">
<source xml:space="preserve">Unrecognized descriptor found. Loading wallet %s
The wallet might had been created on a newer version.
Please try running the latest software version.
</source>
- <context-group purpose="location"><context context-type="linenumber">176</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
- <trans-unit id="_msg1025">
+ <trans-unit id="_msg1033">
<source xml:space="preserve">Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
- <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">203</context></context-group>
</trans-unit>
- <trans-unit id="_msg1026">
+ <trans-unit id="_msg1034">
<source xml:space="preserve">
Unable to cleanup failed migration</source>
- <context-group purpose="location"><context context-type="linenumber">205</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
</trans-unit>
- <trans-unit id="_msg1027">
+ <trans-unit id="_msg1035">
<source xml:space="preserve">
Unable to restore backup of wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">208</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">230</context></context-group>
</trans-unit>
- <trans-unit id="_msg1028">
+ <trans-unit id="_msg1036">
<source xml:space="preserve">Config setting for %s only applied on %s network when in [%s] section.</source>
- <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg1029">
+ <trans-unit id="_msg1037">
<source xml:space="preserve">Copyright (C) %i-%i</source>
- <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg1030">
+ <trans-unit id="_msg1038">
<source xml:space="preserve">Corrupted block database detected</source>
- <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">242</context></context-group>
</trans-unit>
- <trans-unit id="_msg1031">
+ <trans-unit id="_msg1039">
<source xml:space="preserve">Could not find asmap file %s</source>
- <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">243</context></context-group>
</trans-unit>
- <trans-unit id="_msg1032">
+ <trans-unit id="_msg1040">
<source xml:space="preserve">Could not parse asmap file %s</source>
- <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">244</context></context-group>
</trans-unit>
- <trans-unit id="_msg1033">
+ <trans-unit id="_msg1041">
<source xml:space="preserve">Disk space is too low!</source>
- <context-group purpose="location"><context context-type="linenumber">223</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">245</context></context-group>
</trans-unit>
- <trans-unit id="_msg1034">
+ <trans-unit id="_msg1042">
<source xml:space="preserve">Do you want to rebuild the block database now?</source>
- <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
</trans-unit>
- <trans-unit id="_msg1035">
+ <trans-unit id="_msg1043">
<source xml:space="preserve">Done loading</source>
- <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">247</context></context-group>
</trans-unit>
- <trans-unit id="_msg1036">
+ <trans-unit id="_msg1044">
<source xml:space="preserve">Dump file %s does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg1037">
+ <trans-unit id="_msg1045">
<source xml:space="preserve">Error creating %s</source>
- <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">249</context></context-group>
</trans-unit>
- <trans-unit id="_msg1038">
+ <trans-unit id="_msg1046">
<source xml:space="preserve">Error initializing block database</source>
- <context-group purpose="location"><context context-type="linenumber">228</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">250</context></context-group>
</trans-unit>
- <trans-unit id="_msg1039">
+ <trans-unit id="_msg1047">
<source xml:space="preserve">Error initializing wallet database environment %s!</source>
- <context-group purpose="location"><context context-type="linenumber">229</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
</trans-unit>
- <trans-unit id="_msg1040">
+ <trans-unit id="_msg1048">
<source xml:space="preserve">Error loading %s</source>
- <context-group purpose="location"><context context-type="linenumber">230</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">252</context></context-group>
</trans-unit>
- <trans-unit id="_msg1041">
+ <trans-unit id="_msg1049">
<source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source>
- <context-group purpose="location"><context context-type="linenumber">231</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
</trans-unit>
- <trans-unit id="_msg1042">
+ <trans-unit id="_msg1050">
<source xml:space="preserve">Error loading %s: Wallet corrupted</source>
- <context-group purpose="location"><context context-type="linenumber">232</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
</trans-unit>
- <trans-unit id="_msg1043">
+ <trans-unit id="_msg1051">
<source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source>
- <context-group purpose="location"><context context-type="linenumber">233</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">255</context></context-group>
</trans-unit>
- <trans-unit id="_msg1044">
+ <trans-unit id="_msg1052">
<source xml:space="preserve">Error loading block database</source>
- <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">256</context></context-group>
</trans-unit>
- <trans-unit id="_msg1045">
+ <trans-unit id="_msg1053">
<source xml:space="preserve">Error opening block database</source>
- <context-group purpose="location"><context context-type="linenumber">235</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg1046">
+ <trans-unit id="_msg1054">
<source xml:space="preserve">Error reading from database, shutting down.</source>
- <context-group purpose="location"><context context-type="linenumber">236</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">258</context></context-group>
</trans-unit>
- <trans-unit id="_msg1047">
+ <trans-unit id="_msg1055">
<source xml:space="preserve">Error reading next record from wallet database</source>
- <context-group purpose="location"><context context-type="linenumber">237</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">259</context></context-group>
</trans-unit>
- <trans-unit id="_msg1048">
+ <trans-unit id="_msg1056">
+ <source xml:space="preserve">Error: Cannot extract destination from the generated scriptpubkey</source>
+ <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1057">
<source xml:space="preserve">Error: Could not add watchonly tx to watchonly wallet</source>
- <context-group purpose="location"><context context-type="linenumber">238</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg1049">
+ <trans-unit id="_msg1058">
<source xml:space="preserve">Error: Could not delete watchonly transactions</source>
- <context-group purpose="location"><context context-type="linenumber">239</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
</trans-unit>
- <trans-unit id="_msg1050">
+ <trans-unit id="_msg1059">
<source xml:space="preserve">Error: Couldn&apos;t create cursor into database</source>
- <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg1051">
+ <trans-unit id="_msg1060">
<source xml:space="preserve">Error: Disk space is low for %s</source>
- <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
</trans-unit>
- <trans-unit id="_msg1052">
+ <trans-unit id="_msg1061">
<source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
- <context-group purpose="location"><context context-type="linenumber">242</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">265</context></context-group>
</trans-unit>
- <trans-unit id="_msg1053">
+ <trans-unit id="_msg1062">
<source xml:space="preserve">Error: Failed to create new watchonly wallet</source>
- <context-group purpose="location"><context context-type="linenumber">243</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">266</context></context-group>
</trans-unit>
- <trans-unit id="_msg1054">
+ <trans-unit id="_msg1063">
<source xml:space="preserve">Error: Got key that was not hex: %s</source>
- <context-group purpose="location"><context context-type="linenumber">244</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg1055">
+ <trans-unit id="_msg1064">
<source xml:space="preserve">Error: Got value that was not hex: %s</source>
- <context-group purpose="location"><context context-type="linenumber">245</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg1056">
+ <trans-unit id="_msg1065">
<source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source>
- <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg1057">
+ <trans-unit id="_msg1066">
<source xml:space="preserve">Error: Missing checksum</source>
- <context-group purpose="location"><context context-type="linenumber">247</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">270</context></context-group>
</trans-unit>
- <trans-unit id="_msg1058">
+ <trans-unit id="_msg1067">
<source xml:space="preserve">Error: No %s addresses available.</source>
- <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
- <trans-unit id="_msg1059">
+ <trans-unit id="_msg1068">
<source xml:space="preserve">Error: Not all watchonly txs could be deleted</source>
- <context-group purpose="location"><context context-type="linenumber">249</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">272</context></context-group>
</trans-unit>
- <trans-unit id="_msg1060">
+ <trans-unit id="_msg1069">
<source xml:space="preserve">Error: This wallet already uses SQLite</source>
- <context-group purpose="location"><context context-type="linenumber">250</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg1061">
+ <trans-unit id="_msg1070">
<source xml:space="preserve">Error: This wallet is already a descriptor wallet</source>
- <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg1062">
+ <trans-unit id="_msg1071">
<source xml:space="preserve">Error: Unable to begin reading all records in the database</source>
- <context-group purpose="location"><context context-type="linenumber">252</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
- <trans-unit id="_msg1063">
+ <trans-unit id="_msg1072">
<source xml:space="preserve">Error: Unable to make a backup of your wallet</source>
- <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">276</context></context-group>
</trans-unit>
- <trans-unit id="_msg1064">
+ <trans-unit id="_msg1073">
<source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source>
- <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">277</context></context-group>
</trans-unit>
- <trans-unit id="_msg1065">
+ <trans-unit id="_msg1074">
<source xml:space="preserve">Error: Unable to read all records in the database</source>
- <context-group purpose="location"><context context-type="linenumber">255</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">278</context></context-group>
</trans-unit>
- <trans-unit id="_msg1066">
+ <trans-unit id="_msg1075">
<source xml:space="preserve">Error: Unable to remove watchonly address book data</source>
- <context-group purpose="location"><context context-type="linenumber">256</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg1067">
+ <trans-unit id="_msg1076">
<source xml:space="preserve">Error: Unable to write record to new wallet</source>
- <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
- <trans-unit id="_msg1068">
+ <trans-unit id="_msg1077">
<source xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</source>
- <context-group purpose="location"><context context-type="linenumber">258</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">281</context></context-group>
</trans-unit>
- <trans-unit id="_msg1069">
+ <trans-unit id="_msg1078">
<source xml:space="preserve">Failed to rescan the wallet during initialization</source>
- <context-group purpose="location"><context context-type="linenumber">259</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
</trans-unit>
- <trans-unit id="_msg1070">
+ <trans-unit id="_msg1079">
<source xml:space="preserve">Failed to verify database</source>
- <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
</trans-unit>
- <trans-unit id="_msg1071">
+ <trans-unit id="_msg1080">
<source xml:space="preserve">Fee rate (%s) is lower than the minimum fee rate setting (%s)</source>
- <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg1072">
+ <trans-unit id="_msg1081">
<source xml:space="preserve">Ignoring duplicate -wallet %s.</source>
- <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">285</context></context-group>
</trans-unit>
- <trans-unit id="_msg1073">
+ <trans-unit id="_msg1082">
<source xml:space="preserve">Importing…</source>
- <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
</trans-unit>
- <trans-unit id="_msg1074">
+ <trans-unit id="_msg1083">
<source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source>
- <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">287</context></context-group>
</trans-unit>
- <trans-unit id="_msg1075">
+ <trans-unit id="_msg1084">
<source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source>
- <context-group purpose="location"><context context-type="linenumber">265</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
</trans-unit>
- <trans-unit id="_msg1076">
+ <trans-unit id="_msg1085">
<source xml:space="preserve">Input not found or already spent</source>
- <context-group purpose="location"><context context-type="linenumber">266</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
</trans-unit>
- <trans-unit id="_msg1077">
+ <trans-unit id="_msg1086">
+ <source xml:space="preserve">Insufficient dbcache for block verification</source>
+ <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1087">
<source xml:space="preserve">Insufficient funds</source>
- <context-group purpose="location"><context context-type="linenumber">267</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">291</context></context-group>
</trans-unit>
- <trans-unit id="_msg1078">
+ <trans-unit id="_msg1088">
<source xml:space="preserve">Invalid -i2psam address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
</trans-unit>
- <trans-unit id="_msg1079">
+ <trans-unit id="_msg1089">
<source xml:space="preserve">Invalid -onion address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">269</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">293</context></context-group>
</trans-unit>
- <trans-unit id="_msg1080">
+ <trans-unit id="_msg1090">
<source xml:space="preserve">Invalid -proxy address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">270</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
- <trans-unit id="_msg1081">
+ <trans-unit id="_msg1091">
<source xml:space="preserve">Invalid P2P permission: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">295</context></context-group>
</trans-unit>
- <trans-unit id="_msg1082">
+ <trans-unit id="_msg1092">
<source xml:space="preserve">Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">272</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
- <trans-unit id="_msg1083">
+ <trans-unit id="_msg1093">
<source xml:space="preserve">Invalid amount for -discardfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">273</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">297</context></context-group>
</trans-unit>
- <trans-unit id="_msg1084">
+ <trans-unit id="_msg1094">
<source xml:space="preserve">Invalid amount for -fallbackfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg1085">
+ <trans-unit id="_msg1095">
<source xml:space="preserve">Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
- <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">299</context></context-group>
</trans-unit>
- <trans-unit id="_msg1086">
+ <trans-unit id="_msg1096">
<source xml:space="preserve">Invalid netmask specified in -whitelist: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">276</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">300</context></context-group>
</trans-unit>
- <trans-unit id="_msg1087">
+ <trans-unit id="_msg1097">
+ <source xml:space="preserve">Invalid port specified in %s: &apos;%s&apos;</source>
+ <context-group purpose="location"><context context-type="linenumber">301</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1098">
+ <source xml:space="preserve">Invalid pre-selected input %s</source>
+ <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1099">
<source xml:space="preserve">Listening for incoming connections failed (listen returned error %s)</source>
- <context-group purpose="location"><context context-type="linenumber">277</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">303</context></context-group>
</trans-unit>
- <trans-unit id="_msg1088">
+ <trans-unit id="_msg1100">
<source xml:space="preserve">Loading P2P addresses…</source>
- <context-group purpose="location"><context context-type="linenumber">278</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg1089">
+ <trans-unit id="_msg1101">
<source xml:space="preserve">Loading banlist…</source>
- <context-group purpose="location"><context context-type="linenumber">279</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
- <trans-unit id="_msg1090">
+ <trans-unit id="_msg1102">
<source xml:space="preserve">Loading block index…</source>
- <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
- <trans-unit id="_msg1091">
+ <trans-unit id="_msg1103">
<source xml:space="preserve">Loading wallet…</source>
- <context-group purpose="location"><context context-type="linenumber">281</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">307</context></context-group>
</trans-unit>
- <trans-unit id="_msg1092">
+ <trans-unit id="_msg1104">
<source xml:space="preserve">Missing amount</source>
- <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
</trans-unit>
- <trans-unit id="_msg1093">
+ <trans-unit id="_msg1105">
<source xml:space="preserve">Missing solving data for estimating transaction size</source>
- <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg1094">
+ <trans-unit id="_msg1106">
<source xml:space="preserve">Need to specify a port with -whitebind: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">284</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
</trans-unit>
- <trans-unit id="_msg1095">
+ <trans-unit id="_msg1107">
<source xml:space="preserve">No addresses available</source>
- <context-group purpose="location"><context context-type="linenumber">285</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
- <trans-unit id="_msg1096">
+ <trans-unit id="_msg1108">
<source xml:space="preserve">Not enough file descriptors available.</source>
- <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">312</context></context-group>
</trans-unit>
- <trans-unit id="_msg1097">
+ <trans-unit id="_msg1109">
+ <source xml:space="preserve">Not found pre-selected input %s</source>
+ <context-group purpose="location"><context context-type="linenumber">313</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1110">
+ <source xml:space="preserve">Not solvable pre-selected input %s</source>
+ <context-group purpose="location"><context context-type="linenumber">314</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1111">
<source xml:space="preserve">Prune cannot be configured with a negative value.</source>
- <context-group purpose="location"><context context-type="linenumber">287</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
- <trans-unit id="_msg1098">
+ <trans-unit id="_msg1112">
<source xml:space="preserve">Prune mode is incompatible with -txindex.</source>
- <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">316</context></context-group>
</trans-unit>
- <trans-unit id="_msg1099">
+ <trans-unit id="_msg1113">
<source xml:space="preserve">Pruning blockstore…</source>
- <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">317</context></context-group>
</trans-unit>
- <trans-unit id="_msg1100">
+ <trans-unit id="_msg1114">
<source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source>
- <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg1101">
+ <trans-unit id="_msg1115">
<source xml:space="preserve">Replaying blocks…</source>
- <context-group purpose="location"><context context-type="linenumber">291</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg1102">
+ <trans-unit id="_msg1116">
<source xml:space="preserve">Rescanning…</source>
- <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">320</context></context-group>
</trans-unit>
- <trans-unit id="_msg1103">
+ <trans-unit id="_msg1117">
<source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source>
- <context-group purpose="location"><context context-type="linenumber">293</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg1104">
+ <trans-unit id="_msg1118">
<source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source>
- <context-group purpose="location"><context context-type="linenumber">294</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">322</context></context-group>
</trans-unit>
- <trans-unit id="_msg1105">
+ <trans-unit id="_msg1119">
<source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source>
- <context-group purpose="location"><context context-type="linenumber">295</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg1106">
+ <trans-unit id="_msg1120">
<source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source>
- <context-group purpose="location"><context context-type="linenumber">296</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg1107">
+ <trans-unit id="_msg1121">
<source xml:space="preserve">Section [%s] is not recognized.</source>
- <context-group purpose="location"><context context-type="linenumber">297</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg1108">
+ <trans-unit id="_msg1122">
<source xml:space="preserve">Signing transaction failed</source>
- <context-group purpose="location"><context context-type="linenumber">298</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg1109">
+ <trans-unit id="_msg1123">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; does not exist</source>
- <context-group purpose="location"><context context-type="linenumber">299</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">327</context></context-group>
</trans-unit>
- <trans-unit id="_msg1110">
+ <trans-unit id="_msg1124">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; is a relative path</source>
- <context-group purpose="location"><context context-type="linenumber">300</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">328</context></context-group>
</trans-unit>
- <trans-unit id="_msg1111">
+ <trans-unit id="_msg1125">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; is not a directory</source>
- <context-group purpose="location"><context context-type="linenumber">301</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">329</context></context-group>
</trans-unit>
- <trans-unit id="_msg1112">
+ <trans-unit id="_msg1126">
<source xml:space="preserve">Specified blocks directory &quot;%s&quot; does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">330</context></context-group>
</trans-unit>
- <trans-unit id="_msg1113">
+ <trans-unit id="_msg1127">
<source xml:space="preserve">Starting network threads…</source>
- <context-group purpose="location"><context context-type="linenumber">303</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">331</context></context-group>
</trans-unit>
- <trans-unit id="_msg1114">
+ <trans-unit id="_msg1128">
<source xml:space="preserve">The source code is available from %s.</source>
- <context-group purpose="location"><context context-type="linenumber">304</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg1115">
+ <trans-unit id="_msg1129">
<source xml:space="preserve">The specified config file %s does not exist</source>
- <context-group purpose="location"><context context-type="linenumber">305</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">333</context></context-group>
</trans-unit>
- <trans-unit id="_msg1116">
+ <trans-unit id="_msg1130">
<source xml:space="preserve">The transaction amount is too small to pay the fee</source>
- <context-group purpose="location"><context context-type="linenumber">306</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg1117">
+ <trans-unit id="_msg1131">
<source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source>
- <context-group purpose="location"><context context-type="linenumber">307</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg1118">
+ <trans-unit id="_msg1132">
<source xml:space="preserve">This is experimental software.</source>
- <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">336</context></context-group>
</trans-unit>
- <trans-unit id="_msg1119">
+ <trans-unit id="_msg1133">
<source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">309</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">337</context></context-group>
</trans-unit>
- <trans-unit id="_msg1120">
+ <trans-unit id="_msg1134">
<source xml:space="preserve">This is the transaction fee you will pay if you send a transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">338</context></context-group>
</trans-unit>
- <trans-unit id="_msg1121">
+ <trans-unit id="_msg1135">
<source xml:space="preserve">Transaction amount too small</source>
- <context-group purpose="location"><context context-type="linenumber">311</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">339</context></context-group>
</trans-unit>
- <trans-unit id="_msg1122">
+ <trans-unit id="_msg1136">
<source xml:space="preserve">Transaction amounts must not be negative</source>
- <context-group purpose="location"><context context-type="linenumber">312</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">340</context></context-group>
</trans-unit>
- <trans-unit id="_msg1123">
+ <trans-unit id="_msg1137">
<source xml:space="preserve">Transaction change output index out of range</source>
- <context-group purpose="location"><context context-type="linenumber">313</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">341</context></context-group>
</trans-unit>
- <trans-unit id="_msg1124">
+ <trans-unit id="_msg1138">
<source xml:space="preserve">Transaction has too long of a mempool chain</source>
- <context-group purpose="location"><context context-type="linenumber">314</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">342</context></context-group>
</trans-unit>
- <trans-unit id="_msg1125">
+ <trans-unit id="_msg1139">
<source xml:space="preserve">Transaction must have at least one recipient</source>
- <context-group purpose="location"><context context-type="linenumber">315</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">343</context></context-group>
</trans-unit>
- <trans-unit id="_msg1126">
+ <trans-unit id="_msg1140">
<source xml:space="preserve">Transaction needs a change address, but we can&apos;t generate it.</source>
- <context-group purpose="location"><context context-type="linenumber">316</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg1127">
+ <trans-unit id="_msg1141">
<source xml:space="preserve">Transaction too large</source>
- <context-group purpose="location"><context context-type="linenumber">317</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">345</context></context-group>
</trans-unit>
- <trans-unit id="_msg1128">
+ <trans-unit id="_msg1142">
<source xml:space="preserve">Unable to allocate memory for -maxsigcachesize: &apos;%s&apos; MiB</source>
- <context-group purpose="location"><context context-type="linenumber">318</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">346</context></context-group>
</trans-unit>
- <trans-unit id="_msg1129">
+ <trans-unit id="_msg1143">
<source xml:space="preserve">Unable to bind to %s on this computer (bind returned error %s)</source>
- <context-group purpose="location"><context context-type="linenumber">319</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">347</context></context-group>
</trans-unit>
- <trans-unit id="_msg1130">
+ <trans-unit id="_msg1144">
<source xml:space="preserve">Unable to bind to %s on this computer. %s is probably already running.</source>
- <context-group purpose="location"><context context-type="linenumber">320</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">348</context></context-group>
</trans-unit>
- <trans-unit id="_msg1131">
+ <trans-unit id="_msg1145">
<source xml:space="preserve">Unable to create the PID file &apos;%s&apos;: %s</source>
- <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">349</context></context-group>
</trans-unit>
- <trans-unit id="_msg1132">
+ <trans-unit id="_msg1146">
<source xml:space="preserve">Unable to find UTXO for external input</source>
- <context-group purpose="location"><context context-type="linenumber">322</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">350</context></context-group>
</trans-unit>
- <trans-unit id="_msg1133">
+ <trans-unit id="_msg1147">
<source xml:space="preserve">Unable to generate initial keys</source>
- <context-group purpose="location"><context context-type="linenumber">323</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg1134">
+ <trans-unit id="_msg1148">
<source xml:space="preserve">Unable to generate keys</source>
- <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">352</context></context-group>
</trans-unit>
- <trans-unit id="_msg1135">
+ <trans-unit id="_msg1149">
<source xml:space="preserve">Unable to open %s for writing</source>
- <context-group purpose="location"><context context-type="linenumber">325</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">353</context></context-group>
</trans-unit>
- <trans-unit id="_msg1136">
+ <trans-unit id="_msg1150">
<source xml:space="preserve">Unable to parse -maxuploadtarget: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">354</context></context-group>
</trans-unit>
- <trans-unit id="_msg1137">
+ <trans-unit id="_msg1151">
<source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source>
- <context-group purpose="location"><context context-type="linenumber">327</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">355</context></context-group>
</trans-unit>
- <trans-unit id="_msg1138">
+ <trans-unit id="_msg1152">
<source xml:space="preserve">Unable to unload the wallet before migrating</source>
- <context-group purpose="location"><context context-type="linenumber">328</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">356</context></context-group>
</trans-unit>
- <trans-unit id="_msg1139">
+ <trans-unit id="_msg1153">
<source xml:space="preserve">Unknown -blockfilterindex value %s.</source>
- <context-group purpose="location"><context context-type="linenumber">329</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">357</context></context-group>
</trans-unit>
- <trans-unit id="_msg1140">
+ <trans-unit id="_msg1154">
<source xml:space="preserve">Unknown address type &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">330</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">358</context></context-group>
</trans-unit>
- <trans-unit id="_msg1141">
+ <trans-unit id="_msg1155">
<source xml:space="preserve">Unknown change type &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">331</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">359</context></context-group>
</trans-unit>
- <trans-unit id="_msg1142">
+ <trans-unit id="_msg1156">
<source xml:space="preserve">Unknown network specified in -onlynet: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">360</context></context-group>
</trans-unit>
- <trans-unit id="_msg1143">
+ <trans-unit id="_msg1157">
<source xml:space="preserve">Unknown new rules activated (versionbit %i)</source>
- <context-group purpose="location"><context context-type="linenumber">333</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">361</context></context-group>
</trans-unit>
- <trans-unit id="_msg1144">
+ <trans-unit id="_msg1158">
<source xml:space="preserve">Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
- <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">362</context></context-group>
</trans-unit>
- <trans-unit id="_msg1145">
+ <trans-unit id="_msg1159">
<source xml:space="preserve">Unsupported logging category %s=%s.</source>
- <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">363</context></context-group>
</trans-unit>
- <trans-unit id="_msg1146">
+ <trans-unit id="_msg1160">
<source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source>
- <context-group purpose="location"><context context-type="linenumber">336</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">364</context></context-group>
</trans-unit>
- <trans-unit id="_msg1147">
+ <trans-unit id="_msg1161">
<source xml:space="preserve">Verifying blocks…</source>
- <context-group purpose="location"><context context-type="linenumber">337</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">365</context></context-group>
</trans-unit>
- <trans-unit id="_msg1148">
+ <trans-unit id="_msg1162">
<source xml:space="preserve">Verifying wallet(s)…</source>
- <context-group purpose="location"><context context-type="linenumber">338</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">366</context></context-group>
</trans-unit>
- <trans-unit id="_msg1149">
+ <trans-unit id="_msg1163">
<source xml:space="preserve">Wallet needed to be rewritten: restart %s to complete</source>
- <context-group purpose="location"><context context-type="linenumber">339</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">367</context></context-group>
</trans-unit>
</group>
</body></file>
diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts
index 655f3cc84b..fe52d2afb4 100644
--- a/src/qt/locale/bitcoin_eo.ts
+++ b/src/qt/locale/bitcoin_eo.ts
@@ -568,6 +568,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">defaÅ­lta monujo</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Monujo-Nomo</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Fenestro</translation>
</message>
@@ -930,6 +935,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Bitmono</translation>
</message>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -1147,6 +1173,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Konfirmi reŝargo de agordoj</translation>
</message>
<message>
@@ -1719,15 +1746,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Tajpu etikedon por tiu ĉi adreso por aldoni Äin al la listo de uzitaj adresoj</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Pagi Al:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Memorando:</translation>
- </message>
-</context>
+ </context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -1854,10 +1873,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/nekonfirmite</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 konfirmoj</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts
index 7ccc2c24d9..96fc7bf082 100644
--- a/src/qt/locale/bitcoin_es.ts
+++ b/src/qt/locale/bitcoin_es.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">Haz clic derecho para editar la dirección o etiqueta </translation>
+ <translation type="unfinished">Haz clic con el botón derecho del ratón para editar la dirección o la etiqueta</translation>
</message>
<message>
<source>Create a new address</source>
@@ -23,11 +23,11 @@
</message>
<message>
<source>C&amp;lose</source>
- <translation type="unfinished">Cerrar</translation>
+ <translation type="unfinished">C&amp;errar</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation type="unfinished">Borrar de la lista la dirección seleccionada</translation>
+ <translation type="unfinished">Eliminar de la lista la dirección actualmente seleccionada</translation>
</message>
<message>
<source>Enter address or label to search</source>
@@ -43,7 +43,7 @@
</message>
<message>
<source>&amp;Delete</source>
- <translation type="unfinished">&amp;Borrar</translation>
+ <translation type="unfinished">E&amp;liminar</translation>
</message>
<message>
<source>Choose the address to send coins to</source>
@@ -55,7 +55,7 @@
</message>
<message>
<source>C&amp;hoose</source>
- <translation type="unfinished">Escoger</translation>
+ <translation type="unfinished">E&amp;scoger</translation>
</message>
<message>
<source>Sending addresses</source>
@@ -67,13 +67,13 @@
</message>
<message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
- <translation type="unfinished">Estas son tus direcciones Bitcoin para enviar pagos. Comprueba siempre la cantidad y la dirección de recibo antes de transferir monedas.</translation>
+ <translation type="unfinished">Estas son tus direcciones Bitcoin para enviar pagos. Comprueba siempre el importe y la dirección de recepción antes de transferir monedas.</translation>
</message>
<message>
<source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
Signing is only possible with addresses of the type 'legacy'.</source>
- <translation type="unfinished">Estas son tus direcciones Bitcoin para la recepción de pagos. Usa el botón 'Crear una nueva dirección para recepción' en la pestaña Recibir para crear nuevas direcciones.
-Firmar solo es posible con direcciones del tipo Legacy.</translation>
+ <translation type="unfinished">Estas son tus direcciones Bitcoin para la recepción de pagos. Usa el botón «Crear una nueva dirección para recepción» en la pestaña Recibir para crear nuevas direcciones.
+Firmar solo es posible con direcciones del tipo «Legacy».</translation>
</message>
<message>
<source>&amp;Copy Address</source>
@@ -81,7 +81,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation type="unfinished">Copiar &amp;Etiqueta</translation>
+ <translation type="unfinished">Copiar &amp;etiqueta</translation>
</message>
<message>
<source>&amp;Edit</source>
@@ -89,7 +89,12 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Export Address List</source>
- <translation type="unfinished">Exportar la Lista de Direcciones</translation>
+ <translation type="unfinished">Exportar la lista de direcciones</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Archivo separado por comas</translation>
</message>
<message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
@@ -160,7 +165,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</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 type="unfinished">Atención: Si cifras tu monedero y pierdes la contraseña, perderás ¡&lt;b&gt;TODOS TUS BITCOINS&lt;/b&gt;!</translation>
+ <translation type="unfinished">Atención: Si cifras tu monedero y pierdes la contraseña, &lt;b&gt;¡PERDERÃS TODOS TUS BITCOINS!&lt;/b&gt;</translation>
</message>
<message>
<source>Are you sure you wish to encrypt your wallet?</source>
@@ -196,7 +201,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</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 type="unfinished">IMPORTANTE: Cualquier copia de seguridad que hayas hecho del archivo de tu monedero debe ser reemplazada por el archivo cifrado del monedero recién generado. Por razones de seguridad, las copias de seguridad anteriores del archivo de la billetera sin cifrar serán inútiles cuando empieces a usar el nuevo monedero cifrado.</translation>
+ <translation type="unfinished">IMPORTANTE: Cualquier copia de seguridad que hayas hecho del archivo de tu monedero debe ser reemplazada por el archivo cifrado del monedero recién generado. Por razones de seguridad, las copias de seguridad anteriores del archivo del monedero sin cifrar serán inútiles cuando empieces a usar el nuevo monedero cifrado.</translation>
</message>
<message>
<source>Wallet encryption failed</source>
@@ -208,7 +213,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>The supplied passphrases do not match.</source>
- <translation type="unfinished">Las contraseñas dadas no coinciden.</translation>
+ <translation type="unfinished">Las contraseñas proporcionadas no coinciden.</translation>
</message>
<message>
<source>Wallet unlock failed</source>
@@ -235,12 +240,16 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Banned Until</source>
- <translation type="unfinished">Prohibido hasta</translation>
+ <translation type="unfinished">Bloqueado hasta</translation>
</message>
</context>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">El archivo de configuración %1 puede estar corrupto o no ser válido.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">Excepción fuera de control</translation>
</message>
@@ -267,11 +276,15 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<message>
<source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
<extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
- <translation type="unfinished">Un error fatal ha ocurrido. Comprueba que el archivo de configuración soporta escritura, o intenta correr de nuevo el programa con -nosettings</translation>
+ <translation type="unfinished">Un error fatal ha ocurrido. Comprueba que el archivo de configuración soporta escritura, o intenta ejecutar de nuevo el programa con -nosettings</translation>
</message>
<message>
<source>Error: Specified data directory "%1" does not exist.</source>
- <translation type="unfinished">Error: El directorio de datos especificado "%1" no existe.</translation>
+ <translation type="unfinished">Error: El directorio de datos especificado «%1» no existe.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">Error: No se puede analizar/parsear el archivo de configuración: %1.</translation>
</message>
<message>
<source>%1 didn't yet exit safely…</source>
@@ -283,7 +296,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Amount</source>
- <translation type="unfinished">Cantidad</translation>
+ <translation type="unfinished">Importe</translation>
</message>
<message>
<source>Enter a Bitcoin address (e.g. %1)</source>
@@ -298,6 +311,16 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Interno</translation>
</message>
<message>
+ <source>Inbound</source>
+ <extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
+ <translation type="unfinished">Entrante</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment>
+ <translation type="unfinished">Saliente</translation>
+ </message>
+ <message>
<source>Full Relay</source>
<extracomment>Peer connection type that relays all network information.</extracomment>
<translation type="unfinished">Transmisión completa</translation>
@@ -328,43 +351,47 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n segundo</numerusform>
+ <numerusform>%n segundos</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minuto</numerusform>
+ <numerusform>%n minutos</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n hora</numerusform>
+ <numerusform>%n horas</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n día</numerusform>
+ <numerusform>%n días</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n semana</numerusform>
+ <numerusform>%n semanas</numerusform>
</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation type="unfinished">%1 y %2</translation>
+ </message>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n años</numerusform>
+ <numerusform>%n años</numerusform>
</translation>
</message>
</context>
@@ -379,44 +406,76 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">El archivo de configuración no puede escribirse</translation>
</message>
<message>
+ <source>The %s developers</source>
+ <translation type="unfinished">Los desarrolladores de %s</translation>
+ </message>
+ <message>
<source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
<translation type="unfinished">%s corrupto. Intenta utilizar la herramienta del monedero bitcoin-monedero para salvar o restaurar una copia de seguridad.</translation>
</message>
<message>
+ <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
+ <translation type="unfinished">-maxtxfee tiene un valor muy elevado! Comisiones muy grandes podrían ser pagadas en una única transacción.</translation>
+ </message>
+ <message>
<source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
<translation type="unfinished">No se pudo cambiar la versión %i a la versión anterior %i. Versión del monedero sin cambios.</translation>
</message>
<message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation type="unfinished">No se puede bloquear el directorio %s. %s probablemente ya se está ejecutando.</translation>
+ </message>
+ <message>
<source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
- <translation type="unfinished">No se puede actualizar un monedero no dividido en HD de la versión 1%i a la versión 1%i sin actualizar para admitir el grupo de claves pre-dividido. Por favor, use la versión 1%i o ninguna versión especificada.</translation>
+ <translation type="unfinished">No se puede actualizar un monedero no dividido en HD de la versión %i a la versión %i sin actualizar para admitir el grupo de claves pre-dividido. Por favor, use la versión %i o ninguna versión especificada.</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation type="unfinished">Distribuido bajo la licencia de software MIT, vea el archivo adjunto %s o %s</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 type="unfinished">¡Error leyendo %s!. Todas las claves se han leído correctamente, pero los datos de la transacción o el libro de direcciones pueden faltar o ser incorrectos.</translation>
</message>
<message>
<source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
- <translation type="unfinished">¡Error de lectura %s! Los datos de la transacción pueden faltar o ser incorrectos. Reescaneo de la billetera.</translation>
+ <translation type="unfinished">¡Error de lectura %s! Los datos de la transacción pueden faltar o ser incorrectos. Reescaneo del monedero.</translation>
</message>
<message>
<source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
- <translation type="unfinished">Error: el registro del formato del archivo de volcado es incorrecto. Se obtuvo "%s", del "formato" esperado.</translation>
+ <translation type="unfinished">Error: el registro del formato del archivo de volcado es incorrecto. Se obtuvo «%s», del «formato» esperado.</translation>
</message>
<message>
<source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source>
- <translation type="unfinished">Error: el registro del identificador del archivo de volcado es incorrecto. Se obtuvo "%s" se esperaba "%s".</translation>
+ <translation type="unfinished">Error: el registro del identificador del archivo de volcado es incorrecto. Se obtuvo «%s» se esperaba «%s».</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
+ <translation type="unfinished">Error: la versión del archivo volcado no es compatible. Esta versión de monedero bitcoin solo admite archivos de volcado de la versión 1. Consigue volcado de fichero con la versión %s</translation>
</message>
<message>
<source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
- <translation type="unfinished">Error: Los monederos heredados solo admiten los tipos de dirección "legacy", "p2sh-segwit" y "bech32"</translation>
+ <translation type="unfinished">Error: Los monederos heredados solo admiten los tipos de dirección «legacy», «p2sh-segwit» y «bech32»</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation type="unfinished">Estimación de la comisión fallida. Fallbackfee está deshabilitado. Espere unos pocos bloques o habilite -fallbackfee.</translation>
</message>
<message>
<source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
<translation type="unfinished">El archivo %s ya existe. Si está seguro de que esto es lo que quiere, muévalo de lugar primero.</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 type="unfinished">Importe inválido para -maxtxfee=&lt;amount&gt;: «%s» (debe ser al menos la comisión mímina de %s para prevenir transacciones atascadas)</translation>
+ </message>
+ <message>
<source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
- <translation type="unfinished">Peers.dat inválido o corrupto (%s). Si cree que se trata de un error, infórmelo a %s. Como alternativa, puedes mover el archivo (%s) (renombrarlo, moverlo o eliminarlo) para que se cree uno nuevo en el siguiente inicio.</translation>
+ <translation type="unfinished">Archivo peers.dat inválido o corrupto (%s). Si cree que se trata de un error, infórmelo a %s. Como alternativa, puedes mover el archivo (%s) (renombrarlo, moverlo o eliminarlo) para que se cree uno nuevo en el siguiente inicio.</translation>
</message>
<message>
<source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
- <translation type="unfinished">Se proporciona más de una dirección de ligar de cebolla. Utilizando %s para el servicio Tor cebolla creado automático.</translation>
+ <translation type="unfinished">Se proporciona más de una dirección de enlace onion. Utilizando %s para el servicio onion de Tor creado automáticamente.</translation>
</message>
<message>
<source>No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
@@ -428,41 +487,121 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
- <translation type="unfinished">Ningún archivo de billetera proveído. Para usar createfromdump, -format=&lt;format&gt;debe ser proveído.</translation>
+ <translation type="unfinished">Ningún archivo de formato monedero facilitado. Para usar createfromdump, -format=&lt;format&gt;debe ser facilitado.</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 type="unfinished">¡Por favor, compruebe si la fecha y hora en su computadora son correctas! Si su reloj está mal, %s no trabajará correctamente.</translation>
+ </message>
+ <message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <translation type="unfinished">Contribuya si encuentra %s de utilidad. Visite %s para más información acerca del programa.</translation>
+ </message>
+ <message>
+ <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
+ <translation type="unfinished">La poda se ha configurado por debajo del mínimo de %d MiB. Por favor utiliza un valor mas alto.</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">El modo poda no es compatible con -reindex-chainstate. Haz uso de un -reindex completo en su lugar.</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 type="unfinished">Poda: la última sincronización del monedero sobrepasa los datos podados. Necesita reindexar con -reindex (o descargar la cadena de bloques de nuevo en el caso de un nodo podado)</translation>
</message>
<message>
<source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
<translation type="unfinished">SQLiteDatabase: versión del esquema de la monedero sqlite desconocido %d. Sólo version %d se admite</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 type="unfinished">La base de datos de bloques contiene un bloque que parece ser del futuro. Esto puede ser porque la fecha y hora de su ordenador están mal ajustados. Reconstruya la base de datos de bloques solo si está seguro de que la fecha y hora de su ordenador están ajustadas correctamente.</translation>
+ </message>
+ <message>
<source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
- <translation type="unfinished">El índice de bloque db contiene un 'txindex' heredado. Para borrar el espacio de disco ocupado, ejecute un -reindex completo, de lo contrario ignore este error. Este mensaje de error no se volverá a mostrar.</translation>
+ <translation type="unfinished">El índice de bloque db contiene un «txindex» heredado. Para borrar el espacio de disco ocupado, ejecute un -reindex completo, de lo contrario ignore este error. Este mensaje de error no se volverá a mostrar.</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation type="unfinished">Importe de transacción muy pequeño después de la deducción de la comisión</translation>
</message>
<message>
<source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source>
- <translation type="unfinished">Este error podría ocurrir si la billetera no fuese apagada correctamente y fuese cargada usando una compilación con una versión más nueva de Berkeley DB. Si es así, utilice el software que cargó por última vez en esta billetera.</translation>
+ <translation type="unfinished">Este error podría ocurrir si el monedero no fuese apagado correctamente y fuese cargado usando una compilación con una versión más nueva de Berkeley DB. Si es así, utilice el software que cargó por última vez este monedero.</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 type="unfinished">Esta es una versión de pre-prueba - utilícela bajo su propio riesgo. No la utilice para usos comerciales o de minería.</translation>
</message>
<message>
<source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
- <translation type="unfinished">Esta es la tarifa máxima que pagas (además de la tarifa normal) para priorizar la evasión del gasto parcial sobre la selección regular de monedas.</translation>
+ <translation type="unfinished">Esta es la comisión máxima que pagas (además de la comisión normal) para priorizar la evasión del gasto parcial sobre la selección regular de monedas.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
+ <translation type="unfinished">Esta es la comisión de transacción que puede descartar si el cambio es más pequeño que el polvo a este nivel.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation type="unfinished">Esta es la comisión por transacción que deberá pagar cuando la estimación de comisión no esté disponible.</translation>
+ </message>
+ <message>
+ <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
+ <translation type="unfinished">La longitud total de la cadena de versión de red ( %i ) supera la longitud máxima ( %i ) . Reducir el número o tamaño de uacomments .</translation>
+ </message>
+ <message>
+ <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
+ <translation type="unfinished">No se ha podido reproducir los bloques. Deberá reconstruir la base de datos utilizando -reindex-chainstate.</translation>
</message>
<message>
<source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source>
- <translation type="unfinished">Formato de monedero desconocido "%s" proporcionado. Por favor, proporcione uno de "bdb" o "sqlite".</translation>
+ <translation type="unfinished">Formato de monedero desconocido «%s» proporcionado. Por favor, proporcione uno de «bdb» o «sqlite».</translation>
+ </message>
+ <message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">Formato de la base de datos chainstate encontrado. Por favor reinicia con -reindex-chainstate. Esto reconstruirá la base de datos chainstate.</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Monedero creado satisfactoriamente. El tipo de monedero «Legacy» está descontinuado y la asistencia para crear y abrir monederos «legacy» será eliminada en el futuro.</translation>
</message>
<message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
- <translation type="unfinished">Aviso: el formato del monedero del archivo de volcado "%s" no coincide con el formato especificado en la línea de comandos "%s".</translation>
+ <translation type="unfinished">Aviso: el formato del monedero del archivo de volcado «%s» no coincide con el formato especificado en la línea de comandos «%s».</translation>
+ </message>
+ <message>
+ <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
+ <translation type="unfinished">Advertencia: Claves privadas detectadas en el monedero {%s} con clave privada deshabilitada</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 type="unfinished">Advertencia: ¡No parecemos concordar del todo con nuestros pares! Puede que necesite actualizarse, o puede que otros nodos necesiten actualizarse.</translation>
</message>
<message>
<source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
<translation type="unfinished">Hay que validar los datos de los testigos de los bloques después de la altura%d. Por favor, reinicie con -reindex.</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 type="unfinished">Necesita reconstruir la base de datos utilizando -reindex para volver al modo sin poda. Esto volverá a descargar toda la cadena de bloques</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation type="unfinished">¡%s esta configurado muy alto!</translation>
+ </message>
+ <message>
+ <source>-maxmempool must be at least %d MB</source>
+ <translation type="unfinished">-maxmempool debe ser por lo menos de %d MB</translation>
+ </message>
+ <message>
<source>A fatal internal error occurred, see debug.log for details</source>
<translation type="unfinished">Ha ocurrido un error interno grave. Consulta debug.log para más detalles.</translation>
</message>
<message>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation type="unfinished">No se puede resolver -%s dirección: «%s»</translation>
+ </message>
+ <message>
<source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
<translation type="unfinished">No se puede establecer -forcednsseed a true cuando se establece -dnsseed a false.</translation>
</message>
@@ -471,10 +610,130 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">No se puede establecer -peerblockfilters sin -blockfilterindex.</translation>
</message>
<message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation type="unfinished">No es posible escribir en el directorio «%s»; comprueba permisos.</translation>
+ </message>
+ <message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">La actualización -txindex iniciada por una versión anterior no puede completarse. Reinicie con la versión anterior o ejecute un -reindex completo.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">solicitud %s de escucha en el puerto %u . Este puerto se considera "malo" y por lo tanto es poco probable que ningún par de Bitcoin Core se conecte a él. Ver doc/p2p-bad-ports.md para más detalles y una lista completa.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">La opción -reindex-chainstate no es compatible con -blockfilterindex. Por favor, desactiva temporalmente blockfilterindex cuando uses -reindex-chainstate, o sustituye -reindex-chainstate por -reindex para reconstruir completamente todos los índices.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">La opción -reindex-chainstate no es compatible con -coinstatsindex. Por favor, desactiva temporalmente coinstatsindex cuando uses -reindex-chainstate, o sustituye -reindex-chainstate por -reindex para reconstruir completamente todos los índices.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">La opción -reindex-chainstate no es compatible con -txindex. Por favor, desactiva temporalmente txindex cuando uses -reindex-chainstate, o sustituye -reindex-chainstate por -reindex para reconstruir completamente todos los índices.</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">Asumido-válido: la última sincronización del monedero va más allá de los datos de bloques disponibles. Debes esperar a que se descarguen en segundo plano más bloques de la cadena de validación.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">No se puede proporcionar conexiones específicas y hacer que addrman encuentre conexiones salientes al mismo tiempo.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Error de carga %s : Se está cargando el monedero del firmante externo sin que se haya compilado el soporte del firmante externo</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Error: los datos de la libreta de direcciones en el monedero no se identifican como pertenecientes a monederos migrados</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">Error: Se han creado descriptores duplicados durante la migración. Tu monedero puede estar dañado.</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Error: La transacción %s del monedero no se puede identificar como perteneciente a monederos migrados</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">Error: No se pueden producir descriptores para este monedero legacy. Asegúrate primero que el monedero está desbloqueado.</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">No se ha podido cambiar el nombre del archivo peers.dat . Por favor, muévalo o elimínelo e inténtelo de nuevo.</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">Opciones incompatibles: -dnsseed=1 se especificó explicitamente, pero -onlynet impide conexiones a IPv4/IPv6</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">Conexiones salientes restringidas a Tor (-onlynet=onion) pero el proxy para alcanzar la red Tor está explícitamente prohibido: -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">Conexiones salientes restringidas a Tor (-onlynet=onion) pero no se proporciona el proxy para alcanzar la red Tor: no se indica ninguna de las opciones -proxy, -onion, o -listenonion </translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">Se encontró un descriptor desconocido. Cargando monedero %s
+
+El monedero puede haber sido creado con una versión más nueva.
+Por favor intenta ejecutar la ultima versión del software.
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">Categoría especifica de nivel de registro no soportada -loglevel=%s. Se espera -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Categorías válidas: %s. Niveles de registro válidos: %s.</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+No es posible limpiar la migración fallida</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+No es posible restaurar la copia de seguridad del monedero.</translation>
+ </message>
+ <message>
+ <source>Config setting for %s only applied on %s network when in [%s] section.</source>
+ <translation type="unfinished">Los ajustes de configuración para %s solo aplicados en la red %s cuando se encuentra en la sección [%s].</translation>
+ </message>
+ <message>
+ <source>Corrupted block database detected</source>
+ <translation type="unfinished">Corrupción de base de datos de bloques detectada.</translation>
+ </message>
+ <message>
+ <source>Could not find asmap file %s</source>
+ <translation type="unfinished">No se pudo encontrar el archivo AS Map %s</translation>
+ </message>
+ <message>
+ <source>Could not parse asmap file %s</source>
+ <translation type="unfinished">No se pudo analizar el archivo AS Map %s</translation>
+ </message>
+ <message>
<source>Disk space is too low!</source>
<translation type="unfinished">¡El espacio en el disco es demasiado pequeño!</translation>
</message>
<message>
+ <source>Do you want to rebuild the block database now?</source>
+ <translation type="unfinished">¿Quieres reconstruir la base de datos de bloques ahora?</translation>
+ </message>
+ <message>
+ <source>Done loading</source>
+ <translation type="unfinished">Carga completa</translation>
+ </message>
+ <message>
<source>Dump file %s does not exist.</source>
<translation type="unfinished">El archivo de volcado %s no existe</translation>
</message>
@@ -483,20 +742,72 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Error creando %s</translation>
</message>
<message>
+ <source>Error initializing block database</source>
+ <translation type="unfinished">Error al inicializar la base de datos de bloques</translation>
+ </message>
+ <message>
+ <source>Error initializing wallet database environment %s!</source>
+ <translation type="unfinished">Error al inicializar el entorno de la base de datos del monedero %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s</source>
+ <translation type="unfinished">Error cargando %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation type="unfinished">Error cargando %s: Las claves privadas solo pueden ser deshabilitadas durante la creación.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation type="unfinished">Error cargando %s: Monedero corrupto</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation type="unfinished">Error cargando %s: Monedero requiere una versión mas reciente de %s</translation>
+ </message>
+ <message>
+ <source>Error loading block database</source>
+ <translation type="unfinished">Error cargando base de datos de bloques</translation>
+ </message>
+ <message>
+ <source>Error opening block database</source>
+ <translation type="unfinished">Error al abrir base de datos de bloques.</translation>
+ </message>
+ <message>
+ <source>Error reading from database, shutting down.</source>
+ <translation type="unfinished">Error al leer la base de datos, cerrando aplicación.</translation>
+ </message>
+ <message>
<source>Error reading next record from wallet database</source>
- <translation type="unfinished">Error al leer el seguiente registro de la base de datos de la "wallet"</translation>
+ <translation type="unfinished">Error al leer el siguiente registro de la base de datos del monedero</translation>
+ </message>
+ <message>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">Error: No se puede añadir la transacción de observación al monedero de observación</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">Error: No se pueden eliminar las transacciones de observación</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
<translation type="unfinished">Error: No se pudo crear el cursor en la base de datos</translation>
</message>
<message>
+ <source>Error: Disk space is low for %s</source>
+ <translation type="unfinished">Error: Espacio en disco bajo por %s</translation>
+ </message>
+ <message>
<source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
<translation type="unfinished">Error: La suma de comprobación del archivo de volcado no coincide. Calculada%s, prevista%s</translation>
</message>
<message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">Error: No se puede crear un monedero de observación</translation>
+ </message>
+ <message>
<source>Error: Got key that was not hex: %s</source>
- <translation type="unfinished">Error: Se recibió una llave que no es hex: %s</translation>
+ <translation type="unfinished">Error: Se recibió una clave que no es hex: %s</translation>
</message>
<message>
<source>Error: Got value that was not hex: %s</source>
@@ -504,24 +815,59 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Error: Keypool ran out, please call keypoolrefill first</source>
- <translation type="unfinished">Keypool se ha agotado, por favor, llama a keypoolrefill antes</translation>
+ <translation type="unfinished">Error: Keypool se ha agotado, por favor, invoca «keypoolrefill» primero</translation>
</message>
<message>
<source>Error: Missing checksum</source>
- <translation type="unfinished">Error: No se ha encontrado 'checksum'</translation>
+ <translation type="unfinished">Error: No se ha encontrado suma de comprobación</translation>
</message>
<message>
<source>Error: No %s addresses available.</source>
- <translation type="unfinished">Error: No hay %sdirecciones disponibles.
-</translation>
+ <translation type="unfinished">Error: No hay direcciones %s disponibles .</translation>
+ </message>
+ <message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">Error: No se pueden eliminar todas las transacciones de observación</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">Error: Este monedero ya usa SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">Error: Este monedero ya es un monedero descriptor</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">Error: No es posible comenzar a leer todos los registros en la base de datos</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">Error: No es posible realizar la copia de seguridad de tu monedero</translation>
</message>
<message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">Error: No se ha podido analizar la versión %ucomo uint32_t</translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">Error: No es posible leer todos los registros en la base de datos</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">Error: No es posible eliminar los datos de la libreta de direcciones de observación</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
- <translation type="unfinished">Error: No se pudo escribir el registro en la nueva billetera</translation>
+ <translation type="unfinished">Error: No se pudo escribir el registro en el nuevo monedero</translation>
+ </message>
+ <message>
+ <source>Failed to listen on any port. Use -listen=0 if you want this.</source>
+ <translation type="unfinished">Ha fallado la escucha en todos los puertos. Usa -listen=0 si deseas esto.</translation>
+ </message>
+ <message>
+ <source>Failed to rescan the wallet during initialization</source>
+ <translation type="unfinished">Fallo al volver a escanear el monedero durante el inicio</translation>
</message>
<message>
<source>Failed to verify database</source>
@@ -540,6 +886,14 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Importando...</translation>
</message>
<message>
+ <source>Incorrect or no genesis block found. Wrong datadir for network?</source>
+ <translation type="unfinished">Bloque de génesis no encontrado o incorrecto. ¿datadir equivocada para la red?</translation>
+ </message>
+ <message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation type="unfinished">La inicialización de la verificación de validez falló. Se está cerrando %s.</translation>
+ </message>
+ <message>
<source>Input not found or already spent</source>
<translation type="unfinished">Entrada no encontrada o ya gastada</translation>
</message>
@@ -549,7 +903,43 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Invalid -i2psam address or hostname: '%s'</source>
- <translation type="unfinished">Dirección de -i2psam o dominio ' %s' inválido</translation>
+ <translation type="unfinished">Dirección de -i2psam o dominio «%s» inválido</translation>
+ </message>
+ <message>
+ <source>Invalid -onion address or hostname: '%s'</source>
+ <translation type="unfinished">Dirección -onion o hostname: «%s» inválido</translation>
+ </message>
+ <message>
+ <source>Invalid -proxy address or hostname: '%s'</source>
+ <translation type="unfinished">Dirección -proxy o hostname: «%s» inválido</translation>
+ </message>
+ <message>
+ <source>Invalid P2P permission: '%s'</source>
+ <translation type="unfinished">Permiso P2P: «%s» inválido</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation type="unfinished">Importe para -%s=&lt;amount&gt;: «%s» inválido</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -discardfee=&lt;amount&gt;: '%s'</source>
+ <translation type="unfinished">Importe para -discardfee=&lt;amount&gt;: «%s» inválido</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
+ <translation type="unfinished">Importe para -fallbackfee=&lt;amount&gt;: «%s» inválido</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
+ <translation type="unfinished">Importe para -paytxfee=&lt;amount&gt;: «%s» inválido (debe ser al menos %s)</translation>
+ </message>
+ <message>
+ <source>Invalid netmask specified in -whitelist: '%s'</source>
+ <translation type="unfinished">Máscara de red especificada en -whitelist: «%s» inválida</translation>
+ </message>
+ <message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">La escucha para conexiones entrantes falló (la escucha devolvió el error %s)</translation>
</message>
<message>
<source>Loading P2P addresses…</source>
@@ -557,7 +947,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Loading banlist…</source>
- <translation type="unfinished">Cargando banlist...</translation>
+ <translation type="unfinished">Cargando lista de bloqueos...</translation>
</message>
<message>
<source>Loading block index…</source>
@@ -569,29 +959,41 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Missing amount</source>
- <translation type="unfinished">Cantidad faltante</translation>
+ <translation type="unfinished">Importe faltante</translation>
</message>
<message>
<source>Missing solving data for estimating transaction size</source>
<translation type="unfinished">Faltan datos de resolución para estimar el tamaño de las transacciones</translation>
</message>
<message>
+ <source>Need to specify a port with -whitebind: '%s'</source>
+ <translation type="unfinished">Necesita especificar un puerto con -whitebind: «%s»</translation>
+ </message>
+ <message>
<source>No addresses available</source>
<translation type="unfinished">Sin direcciones disponibles</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">No se ha especificado un servidor de proxy. Use -proxy=&lt;ip&gt;o -proxy=&lt;ip:port&gt;.</translation>
+ <source>Not enough file descriptors available.</source>
+ <translation type="unfinished">No hay suficientes descriptores de archivo disponibles.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">"Prune mode" es incompatible with -txindex.</translation>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation type="unfinished">La poda no se puede configurar con un valor negativo.</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation type="unfinished">El modo de poda es incompatible con -txindex.</translation>
</message>
<message>
<source>Pruning blockstore…</source>
<translation type="unfinished">Podando almacén de bloques…</translation>
</message>
<message>
+ <source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
+ <translation type="unfinished">Reduciendo -maxconnections de %d a %d, debido a limitaciones del sistema.</translation>
+ </message>
+ <message>
<source>Replaying blocks…</source>
<translation type="unfinished">Reproduciendo bloques…</translation>
</message>
@@ -616,16 +1018,76 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">SQLiteDatabase: id aplicación inesperada. Esperado %u, tiene %u</translation>
</message>
<message>
+ <source>Section [%s] is not recognized.</source>
+ <translation type="unfinished">Sección [%s] no reconocida.</translation>
+ </message>
+ <message>
+ <source>Signing transaction failed</source>
+ <translation type="unfinished">Firma de transacción fallida</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" does not exist</source>
+ <translation type="unfinished">No existe -walletdir «%s» especificada</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is a relative path</source>
+ <translation type="unfinished">Ruta relativa para -walletdir «%s» especificada</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is not a directory</source>
+ <translation type="unfinished">No existe directorio para -walletdir «%s» especificada</translation>
+ </message>
+ <message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation type="unfinished">No existe directorio de bloques «%s» especificado.</translation>
+ </message>
+ <message>
<source>Starting network threads…</source>
<translation type="unfinished">Iniciando procesos de red...</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation type="unfinished">El código fuente esta disponible desde %s.</translation>
+ </message>
+ <message>
<source>The specified config file %s does not exist</source>
<translation type="unfinished">El archivo de configuración especificado %s no existe </translation>
</message>
<message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation type="unfinished">El importe de la transacción es muy pequeño para pagar la comisión</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation type="unfinished">El monedero evitará pagar menos de la comisión mínima de retransmisión. </translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation type="unfinished">Este es un software experimental.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation type="unfinished">Esta es la comisión mínima que pagarás en cada transacción.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation type="unfinished">Esta es la comisión por transacción a pagar si realiza una transacción.</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation type="unfinished">Importe de la transacción muy pequeño</translation>
+ </message>
+ <message>
<source>Transaction amounts must not be negative</source>
- <translation type="unfinished">Los montos de la transacción no deben ser negativos</translation>
+ <translation type="unfinished">Los importes de la transacción no deben ser negativos</translation>
+ </message>
+ <message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">Ãndice de salida de cambio de transacción fuera de rango</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation type="unfinished">La transacción lleva largo tiempo en la piscina de memoria</translation>
</message>
<message>
<source>Transaction must have at least one recipient</source>
@@ -640,18 +1102,82 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Transacción demasiado grande</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">No se ha podido reservar memoria para -maxsigcachesize: «%s» MiB</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer (bind returned error %s)</source>
+ <translation type="unfinished">No es posible conectar con %s en este sistema (bind ha devuelto el error %s)</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation type="unfinished">No se ha podido conectar con %s en este equipo. %s es posible que esté todavía en ejecución.</translation>
+ </message>
+ <message>
+ <source>Unable to create the PID file '%s': %s</source>
+ <translation type="unfinished">No es posible crear el fichero PID «%s»: %s</translation>
+ </message>
+ <message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">No se encuentra UTXO para entrada externa</translation>
+ </message>
+ <message>
+ <source>Unable to generate initial keys</source>
+ <translation type="unfinished">No es posible generar las claves iniciales</translation>
+ </message>
+ <message>
+ <source>Unable to generate keys</source>
+ <translation type="unfinished">No es posible generar claves</translation>
+ </message>
+ <message>
<source>Unable to open %s for writing</source>
<translation type="unfinished">No se ha podido abrir %s para escribir</translation>
</message>
<message>
<source>Unable to parse -maxuploadtarget: '%s'</source>
- <translation type="unfinished">No se ha podido analizar -maxuploadtarget: '%s'</translation>
+ <translation type="unfinished">No se ha podido analizar -maxuploadtarget: «%s»</translation>
+ </message>
+ <message>
+ <source>Unable to start HTTP server. See debug log for details.</source>
+ <translation type="unfinished">No se ha podido iniciar el servidor HTTP. Ver registro de depuración para detalles.</translation>
+ </message>
+ <message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">Fallo al descargar el monedero antes de la migración</translation>
+ </message>
+ <message>
+ <source>Unknown -blockfilterindex value %s.</source>
+ <translation type="unfinished">Valor -blockfilterindex %s desconocido.</translation>
+ </message>
+ <message>
+ <source>Unknown address type '%s'</source>
+ <translation type="unfinished">Tipo de dirección «%s» desconocida</translation>
+ </message>
+ <message>
+ <source>Unknown change type '%s'</source>
+ <translation type="unfinished">Tipo de cambio «%s» desconocido</translation>
+ </message>
+ <message>
+ <source>Unknown network specified in -onlynet: '%s'</source>
+ <translation type="unfinished">Red especificada en -onlynet: «%s» desconocida</translation>
</message>
<message>
<source>Unknown new rules activated (versionbit %i)</source>
<translation type="unfinished">Nuevas reglas desconocidas activadas (versionbit %i)</translation>
</message>
<message>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">Nivel de registro de depuración global -loglevel=%s no soportado. Valores válidos: %s.</translation>
+ </message>
+ <message>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Categoría de registro no soportada %s=%s. </translation>
+ </message>
+ <message>
+ <source>User Agent comment (%s) contains unsafe characters.</source>
+ <translation type="unfinished">El comentario del Agente de Usuario (%s) contiene caracteres inseguros.</translation>
+ </message>
+ <message>
<source>Verifying blocks…</source>
<translation type="unfinished">Verificando bloques...</translation>
</message>
@@ -659,7 +1185,11 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<source>Verifying wallet(s)…</source>
<translation type="unfinished">Verificando monedero(s)...</translation>
</message>
- </context>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation type="unfinished">Es necesario reescribir el monedero: reiniciar %s para completar</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
@@ -732,12 +1262,32 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Enviar monedas a una dirección Bitcoin</translation>
</message>
<message>
+ <source>Backup wallet to another location</source>
+ <translation type="unfinished">Respaldar monedero en otra ubicación</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation type="unfinished">Cambiar la contraseña utilizada para el cifrado del monedero</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation type="unfinished">&amp;Enviar</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation type="unfinished">&amp;Recibir</translation>
+ </message>
+ <message>
<source>&amp;Options…</source>
<translation type="unfinished">&amp;Opciones...</translation>
</message>
<message>
<source>&amp;Encrypt Wallet…</source>
- <translation type="unfinished">&amp;Cifrar monedero</translation>
+ <translation type="unfinished">Cifrar &amp;monedero...</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">Cifrar las claves privadas de tu monedero</translation>
</message>
<message>
<source>&amp;Backup Wallet…</source>
@@ -752,12 +1302,20 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Firmar &amp;mensaje...</translation>
</message>
<message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">Firmar un mensaje para probar que eres dueño de esta dirección</translation>
+ </message>
+ <message>
<source>&amp;Verify message…</source>
<translation type="unfinished">&amp;Verificar mensaje...</translation>
</message>
<message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">Verificar mensajes comprobando que están firmados con direcciones Bitcoin concretas</translation>
+ </message>
+ <message>
<source>&amp;Load PSBT from file…</source>
- <translation type="unfinished">&amp;Cargar PSBT desde archivo...</translation>
+ <translation type="unfinished">&amp;Cargar TBPF desde archivo...</translation>
</message>
<message>
<source>Open &amp;URI…</source>
@@ -765,23 +1323,35 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Close Wallet…</source>
- <translation type="unfinished">Cerrar cartera...</translation>
+ <translation type="unfinished">Cerrar monedero...</translation>
</message>
<message>
<source>Create Wallet…</source>
- <translation type="unfinished">Crear cartera...</translation>
+ <translation type="unfinished">Crear monedero...</translation>
</message>
<message>
<source>Close All Wallets…</source>
- <translation type="unfinished">Cerrar todas las carteras...</translation>
+ <translation type="unfinished">Cerrar todos los monederos...</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation type="unfinished">&amp;Archivo</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation type="unfinished">&amp;Configuración</translation>
</message>
<message>
<source>&amp;Help</source>
<translation type="unfinished">&amp;Ayuda</translation>
</message>
<message>
+ <source>Tabs toolbar</source>
+ <translation type="unfinished">Barra de pestañas</translation>
+ </message>
+ <message>
<source>Syncing Headers (%1%)…</source>
- <translation type="unfinished">Sincronizando cabeceras (1%1%)</translation>
+ <translation type="unfinished">Sincronizando cabeceras (%1%)...</translation>
</message>
<message>
<source>Synchronizing with network…</source>
@@ -797,24 +1367,52 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Reindexing blocks on disk…</source>
- <translation type="unfinished">Reindexando bloques en disco</translation>
+ <translation type="unfinished">Reindexando bloques en disco...</translation>
</message>
<message>
<source>Connecting to peers…</source>
- <translation type="unfinished">Conectando con compañeros...</translation>
+ <translation type="unfinished">Conectando con pares...</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation type="unfinished">Solicitar pagos (genera código QR y URI's de Bitcoin)</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation type="unfinished">Editar la lista de las direcciones y etiquetas almacenadas</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation type="unfinished">Mostrar la lista de direcciones de envío y etiquetas</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation type="unfinished">&amp;Opciones de línea de comandos</translation>
</message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Procesado %n bloque del historial de transacciones.</numerusform>
+ <numerusform>Procesado %n bloques del historial de transacciones.</numerusform>
</translation>
</message>
<message>
+ <source>%1 behind</source>
+ <translation type="unfinished">%1 detrás</translation>
+ </message>
+ <message>
<source>Catching up…</source>
<translation type="unfinished">Poniéndose al día...</translation>
</message>
<message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation type="unfinished">El último bloque recibido fue generado hace %1 horas.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation type="unfinished">Las transacciones posteriores aún no son visibles.</translation>
+ </message>
+ <message>
<source>Warning</source>
<translation type="unfinished">Advertencia</translation>
</message>
@@ -823,18 +1421,38 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Información</translation>
</message>
<message>
+ <source>Up to date</source>
+ <translation type="unfinished">Actualizado al día </translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction</source>
<translation type="unfinished">Cargar una transacción de Bitcoin parcialmente firmada</translation>
</message>
<message>
<source>Load PSBT from &amp;clipboard…</source>
- <translation type="unfinished">Cargar PSBT desde &amp;portapapeles</translation>
+ <translation type="unfinished">Cargar TBPF desde &amp;portapapeles...</translation>
</message>
<message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">Cargar una transacción de Bitcoin parcialmente firmada desde el Portapapeles</translation>
</message>
<message>
+ <source>Node window</source>
+ <translation type="unfinished">Ventana del nodo</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">Direcciones de &amp;envío</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">Direcciones de &amp;recepción</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI</source>
+ <translation type="unfinished">Abrir un bitcoin: URI</translation>
+ </message>
+ <message>
<source>Open Wallet</source>
<translation type="unfinished">Abrir Monedero</translation>
</message>
@@ -847,16 +1465,30 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Cerrar monedero</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Restaurar monedero…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Restaurar monedero desde un archivo de respaldo</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Cerrar todos los monederos</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation type="unfinished">Muestra el mensaje de ayuda %1 para obtener una lista con posibles opciones de línea de comandos de Bitcoin.</translation>
+ </message>
+ <message>
<source>&amp;Mask values</source>
<translation type="unfinished">&amp;Ocultar valores</translation>
</message>
<message>
<source>Mask the values in the Overview tab</source>
- <translation type="unfinished">Esconder los valores de la ventana de previsualización</translation>
+ <translation type="unfinished">Ocultar los valores de la ventana de previsualización</translation>
</message>
<message>
<source>default wallet</source>
@@ -867,26 +1499,66 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">No hay monederos disponibles</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Datos del monedero </translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Cargar copia de seguridad del monedero</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Restaurar monedero</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nombre del monedero</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Ventana</translation>
</message>
+ <message>
+ <source>Zoom</source>
+ <translation type="unfinished">Acercar</translation>
+ </message>
+ <message>
+ <source>Main Window</source>
+ <translation type="unfinished">Ventana principal</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation type="unfinished">%1 cliente</translation>
+ </message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Ocultar </translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">&amp;Mostrar</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n conexión activa con la red Bitcoin.</numerusform>
+ <numerusform>%n conexiones activas con la red Bitcoin.</numerusform>
</translation>
</message>
<message>
<source>Click for more actions.</source>
<extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
- <translation type="unfinished">Haz click para ver más acciones.</translation>
+ <translation type="unfinished">Haz clic para ver más acciones.</translation>
</message>
<message>
<source>Show Peers tab</source>
<extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
- <translation type="unfinished">Mostrar pestaña Pares</translation>
+ <translation type="unfinished">Mostrar pestaña de pares</translation>
</message>
<message>
<source>Disable network activity</source>
@@ -899,6 +1571,10 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Habilitar la actividad de la red</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Presincronizando cabeceras (%1%)...</translation>
+ </message>
+ <message>
<source>Warning: %1</source>
<translation type="unfinished">Advertencia: %1</translation>
</message>
@@ -911,7 +1587,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<message>
<source>Amount: %1
</source>
- <translation type="unfinished">Cantidad: %1
+ <translation type="unfinished">Importe: %1
</translation>
</message>
<message>
@@ -921,6 +1597,12 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</translation>
</message>
<message>
+ <source>Type: %1
+</source>
+ <translation type="unfinished">Tipo: %1
+</translation>
+ </message>
+ <message>
<source>Label: %1
</source>
<translation type="unfinished">Etiqueta: %1
@@ -938,11 +1620,27 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Incoming transaction</source>
- <translation type="unfinished">Transacción entrante</translation>
+ <translation type="unfinished">Transacción recibida</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished">La generación de clave HD está &lt;b&gt;habilitada&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">La generación de clave HD está &lt;b&gt;deshabilitada&lt;/b&gt;</translation>
</message>
<message>
<source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
- <translation type="unfinished">Llave privada &lt;b&gt;deshabilitada&lt;/b&gt;</translation>
+ <translation type="unfinished">Clave privada &lt;b&gt;deshabilitada&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 type="unfinished">El monedero está &lt;b&gt;cifrado&lt;/b&gt; y actualmente &lt;b&gt;desbloqueado&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 type="unfinished">El monedero está &lt;b&gt;cifrado&lt;/b&gt; y actualmente &lt;b&gt;bloqueado&lt;/b&gt;</translation>
</message>
<message>
<source>Original message:</source>
@@ -950,6 +1648,13 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
</context>
<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">Unidad en la que se muestran los importes. Haga clic para seleccionar otra unidad.</translation>
+ </message>
+</context>
+<context>
<name>CoinControlDialog</name>
<message>
<source>Coin Selection</source>
@@ -961,13 +1666,17 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Amount:</source>
- <translation type="unfinished">Cuantía:</translation>
+ <translation type="unfinished">Importe:</translation>
</message>
<message>
<source>Fee:</source>
<translation type="unfinished">Comisión:</translation>
</message>
<message>
+ <source>Dust:</source>
+ <translation type="unfinished">Polvo:</translation>
+ </message>
+ <message>
<source>After Fee:</source>
<translation type="unfinished">Después de la comisión:</translation>
</message>
@@ -981,15 +1690,23 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Tree mode</source>
- <translation type="unfinished">Modo Ãrbol</translation>
+ <translation type="unfinished">Modo árbol</translation>
</message>
<message>
<source>List mode</source>
- <translation type="unfinished">Modo Lista</translation>
+ <translation type="unfinished">Modo lista</translation>
</message>
<message>
<source>Amount</source>
- <translation type="unfinished">Cantidad</translation>
+ <translation type="unfinished">Importe</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation type="unfinished">Recibido con dirección</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation type="unfinished">Recibido con etiqueta</translation>
</message>
<message>
<source>Date</source>
@@ -1004,16 +1721,20 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Confirmado</translation>
</message>
<message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Copiar importe</translation>
+ </message>
+ <message>
<source>&amp;Copy address</source>
- <translation type="unfinished">copiar dirección </translation>
+ <translation type="unfinished">&amp;Copiar dirección</translation>
</message>
<message>
<source>Copy &amp;label</source>
- <translation type="unfinished">Copiar &amp;label</translation>
+ <translation type="unfinished">Copiar &amp;etiqueta</translation>
</message>
<message>
<source>Copy &amp;amount</source>
- <translation type="unfinished">Copiar &amp;amount</translation>
+ <translation type="unfinished">Copiar &amp;importe</translation>
</message>
<message>
<source>Copy transaction &amp;ID and output index</source>
@@ -1021,13 +1742,17 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>L&amp;ock unspent</source>
- <translation type="unfinished">Bloquear no gastado</translation>
+ <translation type="unfinished">B&amp;loquear no gastado</translation>
</message>
<message>
<source>&amp;Unlock unspent</source>
<translation type="unfinished">&amp;Desbloquear lo no gastado</translation>
</message>
<message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">Copiar cantidad</translation>
+ </message>
+ <message>
<source>Copy fee</source>
<translation type="unfinished">Copiar comisión</translation>
</message>
@@ -1036,14 +1761,34 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Copiar después de la comisión</translation>
</message>
<message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Copiar bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">Copiar polvo</translation>
+ </message>
+ <message>
<source>Copy change</source>
<translation type="unfinished">Copiar cambio</translation>
</message>
<message>
+ <source>(%1 locked)</source>
+ <translation type="unfinished">(%1 bloqueado)</translation>
+ </message>
+ <message>
<source>yes</source>
<translation type="unfinished">sí</translation>
</message>
<message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished">Esta etiqueta se vuelve roja si algún receptor recibe un importe inferior al umbral actual establecido para el polvo.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation type="unfinished">Puede variar en +/- %1 satoshi(s) por entrada.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(sin etiqueta)</translation>
</message>
@@ -1061,25 +1806,29 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<message>
<source>Create Wallet</source>
<extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
- <translation type="unfinished">Crear Monedero</translation>
+ <translation type="unfinished">Crear monedero</translation>
</message>
<message>
<source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
- <translation type="unfinished">Creando Monedero &lt;b&gt;%1&lt;/b&gt;…</translation>
+ <translation type="unfinished">Creando monedero &lt;b&gt;%1&lt;/b&gt;…</translation>
</message>
<message>
<source>Create wallet failed</source>
- <translation type="unfinished">Crear monedero ha fallado</translation>
+ <translation type="unfinished">Fallo al crear monedero</translation>
</message>
<message>
<source>Create wallet warning</source>
- <translation type="unfinished">Advertencia sobre crear monedero</translation>
+ <translation type="unfinished">Advertencia al crear monedero</translation>
</message>
<message>
<source>Can't list signers</source>
<translation type="unfinished">No se pueden enumerar los firmantes</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Se han encontrado demasiados firmantes externos</translation>
+ </message>
</context>
<context>
<name>LoadWalletsActivity</name>
@@ -1098,25 +1847,53 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<name>OpenWalletActivity</name>
<message>
<source>Open wallet failed</source>
- <translation type="unfinished">Abrir monedero ha fallado</translation>
+ <translation type="unfinished">Fallo al abrir monedero</translation>
</message>
<message>
<source>Open wallet warning</source>
- <translation type="unfinished">Advertencia sobre crear monedero</translation>
+ <translation type="unfinished">Advertencia al abrir monedero</translation>
</message>
<message>
<source>default wallet</source>
- <translation type="unfinished">Monedero predeterminado</translation>
+ <translation type="unfinished">monedero predeterminado</translation>
</message>
<message>
<source>Open Wallet</source>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
- <translation type="unfinished">Abrir Monedero</translation>
+ <translation type="unfinished">Abrir monedero</translation>
</message>
<message>
<source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
- <translation type="unfinished">Abriendo Monedero &lt;b&gt;%1&lt;/b&gt;...</translation>
+ <translation type="unfinished">Abriendo monedero &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Restaurar monedero</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Restaurando monedero &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Fallo al restaurar monedero</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Advertencia al restaurar monedero</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Mensaje al restaurar monedero</translation>
</message>
</context>
<context>
@@ -1130,6 +1907,10 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">¿Estás seguro de que deseas cerrar el monedero &lt;i&gt;%1&lt;/i&gt;?</translation>
</message>
<message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">Cerrar el monedero durante demasiado tiempo puede causar la resincronización de toda la cadena si la poda es habilitada.</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Cerrar todos los monederos</translation>
</message>
@@ -1142,11 +1923,11 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<name>CreateWalletDialog</name>
<message>
<source>Create Wallet</source>
- <translation type="unfinished">Crear Monedero</translation>
+ <translation type="unfinished">Crear monedero</translation>
</message>
<message>
<source>Wallet Name</source>
- <translation type="unfinished">Nombre del Monedero</translation>
+ <translation type="unfinished">Nombre del monedero</translation>
</message>
<message>
<source>Wallet</source>
@@ -1158,15 +1939,27 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Encrypt Wallet</source>
- <translation type="unfinished">Cifrar Monedero</translation>
+ <translation type="unfinished">Cifrar monedero</translation>
</message>
<message>
<source>Advanced Options</source>
- <translation type="unfinished">Opciones Avanzadas</translation>
+ <translation type="unfinished">Opciones avanzadas</translation>
+ </message>
+ <message>
+ <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
+ <translation type="unfinished">Deshabilita las claves privadas para este monedero. Los monederos con claves privadas deshabilitadas no tendrán claves privadas y no podrán tener ni una semilla HD ni claves privadas importadas. Esto es ideal para monederos de solo observación.</translation>
</message>
<message>
<source>Disable Private Keys</source>
- <translation type="unfinished">Deshabilita las Llaves Privadas</translation>
+ <translation type="unfinished">Deshabilita las claves privadas</translation>
+ </message>
+ <message>
+ <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
+ <translation type="unfinished">Crear un monedero vacío. Los monederos vacíos no tienen claves privadas ni scripts. Las claves privadas y direcciones pueden importarse después o también establecer una semilla HD.</translation>
+ </message>
+ <message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">Crear monedero vacío</translation>
</message>
<message>
<source>Use descriptors for scriptPubKey management</source>
@@ -1202,23 +1995,55 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<name>EditAddressDialog</name>
<message>
<source>Edit Address</source>
- <translation type="unfinished">Editar Dirección</translation>
+ <translation type="unfinished">Editar dirección</translation>
</message>
<message>
<source>&amp;Label</source>
<translation type="unfinished">&amp;Etiqueta</translation>
</message>
<message>
+ <source>The label associated with this address list entry</source>
+ <translation type="unfinished">La etiqueta asociada con esta entrada en la lista de direcciones</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation type="unfinished">La dirección asociada con esta entrada en la guía. Solo puede ser modificada para direcciones de envío.</translation>
+ </message>
+ <message>
<source>&amp;Address</source>
<translation type="unfinished">&amp;Dirección</translation>
</message>
<message>
+ <source>New sending address</source>
+ <translation type="unfinished">Nueva dirección de envío</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation type="unfinished">Editar dirección de recepción</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation type="unfinished">Editar dirección de envio</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation type="unfinished">La dirección introducida «%1» no es una dirección Bitcoin válida.</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 type="unfinished">La dirección «%1» ya existe como dirección de recepción con la etiqueta «%2» y, por lo tanto, no se puede agregar como dirección de envío.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation type="unfinished">La dirección introducida «%1» ya se encuentra en la libreta de direcciones con la etiqueta «%2».</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">No se pudo desbloquear el monedero.</translation>
</message>
<message>
<source>New key generation failed.</source>
- <translation type="unfinished">La generación de la nueva clave fallo</translation>
+ <translation type="unfinished">Fallo en la generación de la nueva clave.</translation>
</message>
</context>
<context>
@@ -1231,26 +2056,71 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<source>name</source>
<translation type="unfinished">nombre</translation>
</message>
- </context>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation type="unfinished">El directorio ya existe. Agrega %1 si tiene la intención de crear un nuevo directorio aquí.</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation type="unfinished">La ruta ya existe, y no es un directorio.</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation type="unfinished">No puede crear directorio de datos aquí.</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB de espacio disponible</numerusform>
+ <numerusform>%n GB de espacio disponible</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(de %n GB necesario)</numerusform>
+ <numerusform>(de %n GB necesarios)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB necesario para completar la cadena de bloques)</numerusform>
+ <numerusform>(%n GB necesarios para completar la cadena de bloques)</numerusform>
+ </translation>
+ </message>
<message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(de %1 GB necesarios)</translation>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation type="unfinished">Al menos %1 GB de información será almacenada en este directorio, y seguirá creciendo a través del tiempo.</translation>
</message>
<message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB necesarios para la cadena completa)</translation>
+ <source>Approximately %1 GB of data will be stored in this directory.</source>
+ <translation type="unfinished">Aproximadamente %1 GB de información será almacenada en este directorio.</translation>
</message>
<message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(suficiente para restaurar copias de seguridad de %n día de antigüedad)</numerusform>
+ <numerusform>(suficiente para restaurar copias de seguridad de %n días de antigüedad)</numerusform>
</translation>
</message>
<message>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation type="unfinished">%1 descargará y almacenará una copia de la cadena de bloques de Bitcoin.</translation>
+ </message>
+ <message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished">El monedero también se almacenará en este directorio.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation type="unfinished">Error: El directorio de datos especificado «%1» no pudo ser creado.</translation>
+ </message>
+ <message>
<source>Welcome</source>
<translation type="unfinished">Bienvenido</translation>
</message>
@@ -1259,14 +2129,42 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Bienvenido a %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 type="unfinished">Al ser esta la primera vez que se ejecuta el programa, puedes escoger donde %1 almacenará los datos.</translation>
+ </message>
+ <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Limitar el almacenamiento de cadena de bloques a</translation>
</message>
<message>
+ <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
+ <translation type="unfinished">Al revertir este ajuste se requiere volver a descargar la cadena de bloques completa. Es más rápido descargar primero la cadena completa y después podarla. Desactiva algunas características avanzadas.</translation>
+ </message>
+ <message>
<source> GB</source>
<translation type="unfinished">GB</translation>
</message>
- </context>
+ <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 type="unfinished">El primer proceso de sincronización consume muchos recursos, y es posible que puedan ocurrir problemas de hardware que anteriormente no hayas notado. Cada vez que ejecutes %1 automáticamente se reiniciará el proceso de sincronización desde el punto que lo dejaste anteriormente.</translation>
+ </message>
+ <message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Cuando hagas clic en OK, %1 se iniciará la descarga y procesamiento de toda la cadena %4 de bloques (%2 GB) empezando con las primeras transacciones en %3 cuando %4 fue inicialmente lanzado.</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 type="unfinished">Si ha elegido limitar el almacenamiento de la cadena de bloques (pruning o poda), los datos históricos todavía se deben descargar y procesar, pero se eliminarán posteriormente para mantener el uso del disco bajo.</translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation type="unfinished">Usa el directorio de datos predeterminado</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation type="unfinished">Usa un directorio de datos personalizado:</translation>
+ </message>
+</context>
<context>
<name>HelpMessageDialog</name>
<message>
@@ -1275,9 +2173,13 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>About %1</source>
- <translation type="unfinished">Alrededor de %1</translation>
+ <translation type="unfinished">Acerca de %1</translation>
</message>
- </context>
+ <message>
+ <source>Command-line options</source>
+ <translation type="unfinished">&amp;Opciones de línea de comandos</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1292,6 +2194,22 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<context>
<name>ModalOverlay</name>
<message>
+ <source>Form</source>
+ <translation type="unfinished">Formulario</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 type="unfinished">Es posible que las transacciones recientes aún no estén visibles y por lo tanto, el saldo de su monedero podría ser incorrecto. Esta información será correcta una vez que su monedero haya terminado de sincronizarse con la red bitcoin, como se detalla a continuación.</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 type="unfinished">La red no aceptará intentar gastar bitcoins que se vean afectados por transacciones aún no mostradas.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation type="unfinished">Numero de bloques pendientes</translation>
+ </message>
+ <message>
<source>Unknown…</source>
<translation type="unfinished">Desconocido...</translation>
</message>
@@ -1300,6 +2218,10 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">calculando...</translation>
</message>
<message>
+ <source>Last block time</source>
+ <translation type="unfinished">Hora del último bloque</translation>
+ </message>
+ <message>
<source>Progress</source>
<translation type="unfinished">Progreso</translation>
</message>
@@ -1308,12 +2230,36 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Incremento del progreso por hora</translation>
</message>
<message>
+ <source>Estimated time left until synced</source>
+ <translation type="unfinished">Tiempo estimado antes de sincronizar</translation>
+ </message>
+ <message>
<source>Hide</source>
- <translation type="unfinished">Ocultar </translation>
+ <translation type="unfinished">Ocultar</translation>
+ </message>
+ <message>
+ <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
+ <translation type="unfinished">%1 está actualmente sincronizándose. Descargará cabeceras y bloques de nodos semejantes y los validará hasta alcanzar la cabeza de la cadena de bloques.</translation>
</message>
<message>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
- <translation type="unfinished">Desconocido. Sincronizando Cabeceras (%1, %2%)…</translation>
+ <translation type="unfinished">Desconocido. Sincronizando cabeceras (%1, %2%)…</translation>
+ </message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Desconocido. Presincronizando cabeceras (%1, %2%)…</translation>
+ </message>
+</context>
+<context>
+ <name>OpenURIDialog</name>
+ <message>
+ <source>Open bitcoin URI</source>
+ <translation type="unfinished">Abrir URI de bitcoin</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
+ <translation type="unfinished">Pegar dirección desde portapapeles</translation>
</message>
</context>
<context>
@@ -1327,17 +2273,73 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">&amp;Principal</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation type="unfinished">Iniciar automáticamente %1 después de iniciar sesión en el sistema.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation type="unfinished">&amp;Iniciar %1 al iniciar sesión en el sistema</translation>
+ </message>
+ <message>
<source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
- <translation type="unfinished">Activar el pruning reduce significativamente el espacio de disco necesario para guardar las transacciones. Todos los bloques son completamente validados de cualquier manera. Revertir esta opción requiere que descarques de nuevo toda la cadena de bloques.</translation>
+ <translation type="unfinished">Activar la poda reduce significativamente el espacio de disco necesario para guardar las transacciones. Todos los bloques son completamente validados de cualquier manera. Revertir esta opción requiere descargar de nuevo toda la cadena de bloques.</translation>
+ </message>
+ <message>
+ <source>Size of &amp;database cache</source>
+ <translation type="unfinished">Tamaño de la caché de la base de &amp;datos</translation>
+ </message>
+ <message>
+ <source>Number of script &amp;verification threads</source>
+ <translation type="unfinished">Número de hilos de &amp;verificación de scripts</translation>
+ </message>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation type="unfinished">Dirección IP del proxy (Ejemplo. 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 type="unfinished">Muestra si el proxy SOCKS5 por defecto se utiliza para conectarse a pares a través de este tipo de red.</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 type="unfinished">Minimizar en vez de salir de la aplicación cuando la ventana está cerrada. Cuando se activa esta opción, la aplicación sólo se cerrará después de seleccionar Salir en el menú.</translation>
+ </message>
+ <message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Las opciones establecidas en este diálogo serán invalidadas por la línea de comandos:</translation>
+ </message>
+ <message>
+ <source>Open the %1 configuration file from the working directory.</source>
+ <translation type="unfinished">Abrir el archivo de configuración %1 en el directorio de trabajo.</translation>
+ </message>
+ <message>
+ <source>Open Configuration File</source>
+ <translation type="unfinished">Abrir archivo de configuración</translation>
+ </message>
+ <message>
+ <source>Reset all client options to default.</source>
+ <translation type="unfinished">Restablecer todas las opciones del cliente a los valores predeterminados.</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation type="unfinished">&amp;Restablecer opciones</translation>
</message>
<message>
<source>&amp;Network</source>
<translation type="unfinished">&amp;Red</translation>
</message>
<message>
+ <source>Prune &amp;block storage to</source>
+ <translation type="unfinished">Podar el almacenamiento de &amp;bloques a</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Revertir estas configuraciones requiere descargar de nuevo la cadena de bloques completa.</translation>
+ </message>
+ <message>
<source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
<extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
- <translation type="unfinished">Tamaño máximo de la caché de la base de datos. Una caché más grande puede contribuir a una sincronización más rápida, después de lo cual el beneficio es menos pronunciado para la mayoría de los casos de uso. Disminuir el tamaño de la caché reducirá el uso de la memoria. La memoria mempool no utilizada se comparte para esta caché.</translation>
+ <translation type="unfinished">Tamaño máximo de la caché de la base de datos. Una caché más grande puede contribuir a una sincronización más rápida, después de lo cual el beneficio es menos pronunciado para la mayoría de los casos de uso. Disminuir el tamaño de la caché reducirá el uso de la memoria. La memoria de la piscina de memoria no utilizada se comparte para esta caché.</translation>
</message>
<message>
<source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
@@ -1345,6 +2347,10 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Establezca el número de hilos de verificación de scripts. Los valores negativos corresponden al número de núcleos que se desea dejar libres al sistema.</translation>
</message>
<message>
+ <source>(0 = auto, &lt;0 = leave that many cores free)</source>
+ <translation type="unfinished">(0 = auto, &lt;0 = deja esa cantidad de núcleos libres)</translation>
+ </message>
+ <message>
<source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
<extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
<translation type="unfinished">Esto te permite a ti o a una herramienta de terceros comunicarse con el nodo a través de la línea de comandos y comandos JSON-RPC.</translation>
@@ -1355,9 +2361,13 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Activar servidor R&amp;PC</translation>
</message>
<message>
+ <source>W&amp;allet</source>
+ <translation type="unfinished">M&amp;onedero</translation>
+ </message>
+ <message>
<source>Whether to set subtract fee from amount as default or not.</source>
<extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
- <translation type="unfinished">Establecer si se resta la tasa del importe por defecto o no.</translation>
+ <translation type="unfinished">Establecer si se resta la comisión del importe por defecto o no.</translation>
</message>
<message>
<source>Subtract &amp;fee from amount by default</source>
@@ -1370,37 +2380,45 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Enable coin &amp;control features</source>
- <translation type="unfinished">Habilitar características de &amp;Control de Moneda.</translation>
+ <translation type="unfinished">Habilitar características de &amp;control de moneda.</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 type="unfinished">Si deshabilitas el gasto de un cambio no confirmado, el cambio de una transacción no se puede usar hasta que esa transacción tenga al menos una confirmación. Esto también afecta a cómo se calcula tu saldo.</translation>
</message>
<message>
+ <source>&amp;Spend unconfirmed change</source>
+ <translation type="unfinished">&amp;Gastar cambio sin confirmar</translation>
+ </message>
+ <message>
<source>Enable &amp;PSBT controls</source>
<extracomment>An options window setting to enable PSBT controls.</extracomment>
- <translation type="unfinished">Activar controles &amp;PSBT</translation>
+ <translation type="unfinished">Activar controles &amp;TBPF</translation>
</message>
<message>
<source>Whether to show PSBT controls.</source>
<extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
- <translation type="unfinished">Establecer si se muestran los controles PSBT</translation>
+ <translation type="unfinished">Establecer si se muestran los controles TBPF</translation>
</message>
<message>
<source>External Signer (e.g. hardware wallet)</source>
- <translation type="unfinished">Dispositivo Externo de Firma (ej. billetera de hardware)</translation>
+ <translation type="unfinished">Dispositivo externo de firma (ej. billetera de hardware)</translation>
</message>
<message>
<source>&amp;External signer script path</source>
- <translation type="unfinished">&amp;Ruta de script de firma externo</translation>
+ <translation type="unfinished">Ruta de script de firma &amp;externo</translation>
</message>
<message>
<source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
<translation type="unfinished">Ruta completa al script compatible con Bitcoin Core (ej. C:\Descargas\hwi.exe o /Usuarios/SuUsuario/Descargas/hwi.py). Cuidado: código malicioso podría robarle sus monedas!</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 type="unfinished">Abrir automáticamente el puerto del cliente Bitcoin en el router. Esta opción solo funciona cuando el router admite UPnP y está activado.</translation>
+ </message>
+ <message>
<source>Map port using &amp;UPnP</source>
- <translation type="unfinished">Mapear el puerto usando &amp;UPnp</translation>
+ <translation type="unfinished">Mapear el puerto usando &amp;UPnP</translation>
</message>
<message>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
@@ -1416,7 +2434,31 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Allow incomin&amp;g connections</source>
- <translation type="unfinished">Permitir conexiones entrantes</translation>
+ <translation type="unfinished">&amp;Permitir conexiones entrantes</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
+ <translation type="unfinished">Conectar a la red de Bitcoin a través de un proxy SOCKS5.</translation>
+ </message>
+ <message>
+ <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
+ <translation type="unfinished">&amp;Conectar a través del proxy SOCKS5 (proxy predeterminado):</translation>
+ </message>
+ <message>
+ <source>Proxy &amp;IP:</source>
+ <translation type="unfinished">&amp;IP proxy::</translation>
+ </message>
+ <message>
+ <source>&amp;Port:</source>
+ <translation type="unfinished">&amp;Puerto:</translation>
+ </message>
+ <message>
+ <source>Port of the proxy (e.g. 9050)</source>
+ <translation type="unfinished">Puerto del proxy (ej. 9050)</translation>
+ </message>
+ <message>
+ <source>Used for reaching peers via:</source>
+ <translation type="unfinished">Utilizado para llegar a los pares a través de:</translation>
</message>
<message>
<source>&amp;Window</source>
@@ -1424,27 +2466,55 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Show the icon in the system tray.</source>
- <translation type="unfinished">Mostrar el ícono en la bandeja del sistema.</translation>
+ <translation type="unfinished">Mostrar el icono en la bandeja del sistema.</translation>
</message>
<message>
<source>&amp;Show tray icon</source>
- <translation type="unfinished">Mostrar la bandeja del sistema.</translation>
+ <translation type="unfinished">Mostrar la &amp;bandeja del sistema.</translation>
</message>
<message>
<source>Show only a tray icon after minimizing the window.</source>
<translation type="unfinished">Mostrar solo un icono de bandeja después de minimizar la ventana.</translation>
</message>
<message>
+ <source>&amp;Minimize to the tray instead of the taskbar</source>
+ <translation type="unfinished">&amp;Minimiza a la bandeja en vez de la barra de tareas</translation>
+ </message>
+ <message>
+ <source>M&amp;inimize on close</source>
+ <translation type="unfinished">M&amp;inimizar al cerrar</translation>
+ </message>
+ <message>
<source>&amp;Display</source>
<translation type="unfinished">&amp;Mostrar</translation>
</message>
<message>
+ <source>User Interface &amp;language:</source>
+ <translation type="unfinished">&amp;Idioma de la interfaz de usuario:</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation type="unfinished">El idioma de la interfaz de usuario puede establecerse aquí. Esta configuración tendrá efecto después de reiniciar %1.</translation>
+ </message>
+ <message>
+ <source>&amp;Unit to show amounts in:</source>
+ <translation type="unfinished">&amp;Unidad en la que mostrar importes:</translation>
+ </message>
+ <message>
+ <source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
+ <translation type="unfinished">Elegir la subdivisión predeterminada para mostrar cantidades en la interfaz y cuando se envían monedas.</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 type="unfinished">URLs de terceros (por ejemplo, un explorador de bloques) que aparecen en la pestaña de transacciones como elementos del menú contextual. %s en la URL se sustituye por el hash de la transacción. Las URL múltiples se separan con una barra vertical |.</translation>
</message>
<message>
<source>&amp;Third-party transaction URLs</source>
- <translation type="unfinished">URLs de transacciones de &amp;Terceros</translation>
+ <translation type="unfinished">URLs de transacciones de &amp;terceros</translation>
+ </message>
+ <message>
+ <source>Whether to show coin control features or not.</source>
+ <translation type="unfinished">Mostrar o no funcionalidad del control de moneda</translation>
</message>
<message>
<source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
@@ -1452,19 +2522,23 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
- <translation type="unfinished">Usar proxy SOCKS&amp;5 para alcanzar nodos via servicios ocultos Tor:</translation>
+ <translation type="unfinished">Usar proxy SOCKS&amp;5 para alcanzar nodos vía servicios anónimos Tor:</translation>
</message>
<message>
<source>Monospaced font in the Overview tab:</source>
- <translation type="unfinished">letra Monospace en la pestaña Resumen: </translation>
+ <translation type="unfinished">Fuente monoespaciada en la pestaña Resumen:</translation>
</message>
<message>
<source>embedded "%1"</source>
- <translation type="unfinished">incrustado "%1"</translation>
+ <translation type="unfinished">incrustado «%1»</translation>
</message>
<message>
<source>closest matching "%1"</source>
- <translation type="unfinished">coincidencia más aproximada "%1"</translation>
+ <translation type="unfinished">coincidencia más aproximada «%1»</translation>
+ </message>
+ <message>
+ <source>&amp;Cancel</source>
+ <translation type="unfinished">&amp;Cancelar</translation>
</message>
<message>
<source>Compiled without external signing support (required for external signing)</source>
@@ -1481,14 +2555,22 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirmar restablecimiento de opciones</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Es necesario reiniciar el cliente para activar los cambios.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Los ajustes actuales se guardarán en «%1».</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">El cliente se cerrará. ¿Deseas continuar?</translation>
</message>
<message>
@@ -1497,6 +2579,11 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Opciones de configuración</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>
+ <extracomment>Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</extracomment>
+ <translation type="unfinished">El archivo de configuración se utiliza para especificar opciones de usuario avanzadas que anulan la configuración de la GUI. Además, cualquier opción de línea de comandos anulará este archivo de configuración.</translation>
+ </message>
+ <message>
<source>Continue</source>
<translation type="unfinished">Continuar</translation>
</message>
@@ -1518,14 +2605,25 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">No se puede leer el ajuste «%1», %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
<translation type="unfinished">Formulario</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 type="unfinished">La información mostrada puede estar desactualizada. Su monedero se sincroniza automáticamente con la red de Bitcoin después de establecer una conexión, pero este proceso aún no se ha completado.</translation>
+ </message>
+ <message>
<source>Watch-only:</source>
- <translation type="unfinished">Solo lectura:</translation>
+ <translation type="unfinished">Solo observación:</translation>
</message>
<message>
<source>Available:</source>
@@ -1544,24 +2642,44 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
<translation type="unfinished">Total de transacciones que aún no se han sido confirmadas, y que no son contabilizadas dentro del saldo disponible para gastar</translation>
</message>
<message>
+ <source>Immature:</source>
+ <translation type="unfinished">No disponible:</translation>
+ </message>
+ <message>
+ <source>Mined balance that has not yet matured</source>
+ <translation type="unfinished">Saldo recién minado que aún no está disponible</translation>
+ </message>
+ <message>
<source>Your current total balance</source>
<translation type="unfinished">Saldo total actual</translation>
</message>
<message>
<source>Your current balance in watch-only addresses</source>
- <translation type="unfinished">Su saldo actual en direcciones solo-lectura</translation>
+ <translation type="unfinished">Su saldo actual en direcciones de observación</translation>
</message>
<message>
<source>Spendable:</source>
- <translation type="unfinished">Gastable:</translation>
+ <translation type="unfinished">Disponible:</translation>
</message>
<message>
<source>Recent transactions</source>
<translation type="unfinished">Transaciones recientes</translation>
</message>
<message>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation type="unfinished">Transacciones sin confirmar a direcciones de observación</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation type="unfinished">Saldo minado en direcciones de observación que aún no está disponible</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation type="unfinished">Saldo total actual en direcciones de observación</translation>
+ </message>
+ <message>
<source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
- <translation type="unfinished">Modo de privacidad activado para la pestaña de visión general. Para desenmascarar los valores, desmarcar los valores de Configuración-&gt;Máscara.</translation>
+ <translation type="unfinished">Modo de privacidad activado para la pestaña de visión general. Para desenmascarar los valores, desmarcar los valores de Configuración-&gt;Enmascarar valores.</translation>
</message>
</context>
<context>
@@ -1600,7 +2718,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Cannot sign inputs while wallet is locked.</source>
- <translation type="unfinished">No se pueden firmar las entradas mientras la billetera está bloqueada.</translation>
+ <translation type="unfinished">No se pueden firmar las entradas mientras el monedero está bloqueado.</translation>
</message>
<message>
<source>Could not sign any more inputs.</source>
@@ -1628,7 +2746,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>PSBT copied to clipboard.</source>
- <translation type="unfinished">PSBT copiado al portapapeles</translation>
+ <translation type="unfinished">TBPF copiado al portapapeles</translation>
</message>
<message>
<source>Save Transaction Data</source>
@@ -1641,7 +2759,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>PSBT saved to disk.</source>
- <translation type="unfinished">PSBT guardado en la memoria.</translation>
+ <translation type="unfinished">TBPF guardado en disco.</translation>
</message>
<message>
<source> * Sends %1 to %2</source>
@@ -1649,7 +2767,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Unable to calculate transaction fee or total transaction amount.</source>
- <translation type="unfinished">No se ha podido calcular la comisión por transacción o la totalidad de la cantidad de la transacción.</translation>
+ <translation type="unfinished">No se ha podido calcular la comisión por transacción o la totalidad del importe de la transacción.</translation>
</message>
<message>
<source>Pays transaction fee: </source>
@@ -1657,7 +2775,7 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Total Amount</source>
- <translation type="unfinished">Cantidad Total</translation>
+ <translation type="unfinished">Importe total</translation>
</message>
<message>
<source>or</source>
@@ -1693,12 +2811,28 @@ Firmar solo es posible con direcciones del tipo Legacy.</translation>
</message>
<message>
<source>Transaction status is unknown.</source>
- <translation type="unfinished">El estatus de la transacción es desconocido.</translation>
+ <translation type="unfinished">El estado de la transacción es desconocido.</translation>
</message>
</context>
<context>
<name>PaymentServer</name>
<message>
+ <source>Payment request error</source>
+ <translation type="unfinished">Error en la solicitud de pago</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation type="unfinished">No se puede iniciar bitcoin: controlador clic-para-pagar</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation type="unfinished">Gestión de URI</translation>
+ </message>
+ <message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation type="unfinished">«bitcoin: //» no es un URI válido. Use «bitcoin:» en su lugar.</translation>
+ </message>
+ <message>
<source>Cannot process payment request because BIP70 is not supported.
Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
@@ -1706,15 +2840,38 @@ If you are receiving this error you should request the merchant provide a BIP21
Debido a los fallos de seguridad generalizados en el BIP70, se recomienda encarecidamente ignorar las instrucciones del comerciante para cambiar de monedero.
Si recibe este error, debe solicitar al comerciante que le proporcione un URI compatible con BIP21.</translation>
</message>
- </context>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation type="unfinished">¡No se puede interpretar la URI! Esto puede deberse a una dirección Bitcoin inválida o a parámetros de URI mal formados.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation type="unfinished">Gestión del archivo de solicitud de pago</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
+ <source>User Agent</source>
+ <extracomment>Title of Peers Table column which contains the peer's User Agent string.</extracomment>
+ <translation type="unfinished">Agente del usuario</translation>
+ </message>
+ <message>
<source>Peer</source>
<extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
<translation type="unfinished">Pares</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Duración</translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
+ <translation type="unfinished">Sentido</translation>
+ </message>
+ <message>
<source>Sent</source>
<extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment>
<translation type="unfinished">Enviado</translation>
@@ -1730,11 +2887,26 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
<translation type="unfinished">Dirección</translation>
</message>
<message>
+ <source>Type</source>
+ <extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment>
+ <translation type="unfinished">Tipo</translation>
+ </message>
+ <message>
<source>Network</source>
<extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment>
<translation type="unfinished">Red</translation>
</message>
- </context>
+ <message>
+ <source>Inbound</source>
+ <extracomment>An Inbound Connection from a Peer.</extracomment>
+ <translation type="unfinished">Entrante</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <extracomment>An Outbound Connection to a Peer.</extracomment>
+ <translation type="unfinished">Saliente</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
<message>
@@ -1746,6 +2918,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
<translation type="unfinished">&amp;Copiar Imagen</translation>
</message>
<message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation type="unfinished">URI resultante demasiado larga. Intente reducir el texto de la etiqueta / mensaje.</translation>
+ </message>
+ <message>
<source>Error encoding URI into QR Code.</source>
<translation type="unfinished">Fallo al codificar URI en código QR.</translation>
</message>
@@ -1755,7 +2931,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
</message>
<message>
<source>Save QR Code</source>
- <translation type="unfinished">Guardar Código QR</translation>
+ <translation type="unfinished">Guardar código QR</translation>
</message>
<message>
<source>PNG Image</source>
@@ -1771,13 +2947,25 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
</message>
<message>
<source>Client version</source>
- <translation type="unfinished">Versión del Cliente</translation>
+ <translation type="unfinished">Versión del cliente</translation>
</message>
<message>
<source>&amp;Information</source>
<translation type="unfinished">&amp;Información</translation>
</message>
<message>
+ <source>To specify a non-default location of the data directory use the '%1' option.</source>
+ <translation type="unfinished">Para especificar una localización personalizada del directorio de datos, usa la opción «%1».</translation>
+ </message>
+ <message>
+ <source>To specify a non-default location of the blocks directory use the '%1' option.</source>
+ <translation type="unfinished">Para especificar una localización personalizada del directorio de bloques, usa la opción «%1». </translation>
+ </message>
+ <message>
+ <source>Startup time</source>
+ <translation type="unfinished">Hora de inicio</translation>
+ </message>
+ <message>
<source>Network</source>
<translation type="unfinished">Red</translation>
</message>
@@ -1794,6 +2982,10 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
<translation type="unfinished">Cadena de bloques</translation>
</message>
<message>
+ <source>Memory Pool</source>
+ <translation type="unfinished">Piscina de memoria</translation>
+ </message>
+ <message>
<source>Current number of transactions</source>
<translation type="unfinished">Número actual de transacciones</translation>
</message>
@@ -1803,7 +2995,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
</message>
<message>
<source>Wallet: </source>
- <translation type="unfinished">Monedero</translation>
+ <translation type="unfinished">Monedero:</translation>
</message>
<message>
<source>(none)</source>
@@ -1823,48 +3015,91 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
</message>
<message>
<source>&amp;Peers</source>
- <translation type="unfinished">Pares</translation>
+ <translation type="unfinished">&amp;Pares</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation type="unfinished">Pares bloqueados</translation>
+ </message>
+ <message>
+ <source>Select a peer to view detailed information.</source>
+ <translation type="unfinished">Selecciona un par para ver la información detallada.</translation>
</message>
<message>
<source>Version</source>
<translation type="unfinished">Versión</translation>
</message>
<message>
+ <source>Starting Block</source>
+ <translation type="unfinished">Bloque de inicio</translation>
+ </message>
+ <message>
+ <source>Synced Headers</source>
+ <translation type="unfinished">Encabezados sincronizados</translation>
+ </message>
+ <message>
+ <source>Synced Blocks</source>
+ <translation type="unfinished">Bloques sincronizados</translation>
+ </message>
+ <message>
<source>Last Transaction</source>
<translation type="unfinished">Última transacción</translation>
</message>
<message>
+ <source>The mapped Autonomous System used for diversifying peer selection.</source>
+ <translation type="unfinished">El Sistema Autónomo mapeado utilizado para la selección diversificada de pares.</translation>
+ </message>
+ <message>
+ <source>Mapped AS</source>
+ <translation type="unfinished">SA Mapeado</translation>
+ </message>
+ <message>
<source>Whether we relay addresses to this peer.</source>
- <extracomment>Tooltip text for the Address Relay field in the peer details area.</extracomment>
- <translation type="unfinished">Si retransmitimos las direcciones a este peer.</translation>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Si retransmitimos las direcciones a este par.</translation>
</message>
<message>
<source>Address Relay</source>
- <translation type="unfinished">Transimisión de la dirección</translation>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Transmisión de la dirección</translation>
</message>
<message>
- <source>Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Processed field in the peer details area.</extracomment>
- <translation type="unfinished">Número total de direcciones procesadas, excluyendo las descartadas por limitación de tasa</translation>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">El número total de direcciones recibidas desde este par que han sido procesadas (excluyendo las direcciones que han sido desestimadas debido a la limitación de velocidad).</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">El número total de direcciones recibidas desde este par que han sido desestimadas (no procesadas) debido a la limitación de velocidad.</translation>
</message>
<message>
<source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
<translation type="unfinished">Direcciones procesadas</translation>
</message>
<message>
- <source>Total number of addresses dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area.</extracomment>
- <translation type="unfinished">Número total de direcciones descartadas por límite de tasa</translation>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Direcciones con límite de ratio</translation>
</message>
<message>
- <source>Addresses Rate-Limited</source>
- <translation type="unfinished">Direcciones con límite de tasa</translation>
+ <source>User Agent</source>
+ <translation type="unfinished">Agente del usuario</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">Ventana del nodo</translation>
</message>
<message>
<source>Current block height</source>
<translation type="unfinished">Altura del bloque actual</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 type="unfinished">Abra el archivo de registro de depuración %1 del directorio de datos actual. Esto puede tomar unos segundos para archivos de registro grandes.</translation>
+ </message>
+ <message>
<source>Decrease font size</source>
<translation type="unfinished">Reducir el tamaño de la fuente</translation>
</message>
@@ -1886,8 +3121,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
</message>
<message>
<source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
- <translation type="unfinished">El protocolo de red de este par está conectado a través de:
- IPv4, IPv6, Onion, I2P, o CJDNS.</translation>
+ <translation type="unfinished">El protocolo de red de este par está conectado a través de: IPv4, IPv6, Onion, I2P, o CJDNS.</translation>
</message>
<message>
<source>Services</source>
@@ -1895,7 +3129,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
</message>
<message>
<source>Whether the peer requested us to relay transactions.</source>
- <translation type="unfinished">Si el peer nos solicitó que transmitiéramos las transacciones.</translation>
+ <translation type="unfinished">Si el par nos solicitó que transmitiéramos las transacciones.</translation>
</message>
<message>
<source>Wants Tx Relay</source>
@@ -1907,7 +3141,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
</message>
<message>
<source>High Bandwidth</source>
- <translation type="unfinished">banda ancha</translation>
+ <translation type="unfinished">Banda ancha</translation>
</message>
<message>
<source>Connection Time</source>
@@ -1919,12 +3153,76 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
</message>
<message>
<source>Last Block</source>
- <translation type="unfinished">Último Bloque</translation>
+ <translation type="unfinished">Último bloque</translation>
</message>
<message>
<source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
<extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
- <translation type="unfinished">Tiempo transcurrido desde que se recibió de este par una nueva transacción aceptada en nuestro mempool.</translation>
+ <translation type="unfinished">Tiempo transcurrido desde que se recibió de este par una nueva transacción aceptada en nuestra piscina de memoria.</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation type="unfinished">Último envío</translation>
+ </message>
+ <message>
+ <source>Last Receive</source>
+ <translation type="unfinished">Última recepción</translation>
+ </message>
+ <message>
+ <source>Ping Time</source>
+ <translation type="unfinished">Tiempo de ping</translation>
+ </message>
+ <message>
+ <source>The duration of a currently outstanding ping.</source>
+ <translation type="unfinished">La duración de un ping actualmente pendiente.</translation>
+ </message>
+ <message>
+ <source>Ping Wait</source>
+ <translation type="unfinished">Espera de ping</translation>
+ </message>
+ <message>
+ <source>Min Ping</source>
+ <translation type="unfinished">Ping mínimo</translation>
+ </message>
+ <message>
+ <source>Time Offset</source>
+ <translation type="unfinished">Desplazamiento de tiempo</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">Hora del último bloque</translation>
+ </message>
+ <message>
+ <source>&amp;Open</source>
+ <translation type="unfinished">&amp;Abrir</translation>
+ </message>
+ <message>
+ <source>&amp;Console</source>
+ <translation type="unfinished">&amp;Consola</translation>
+ </message>
+ <message>
+ <source>&amp;Network Traffic</source>
+ <translation type="unfinished">&amp;Tráfico de Red</translation>
+ </message>
+ <message>
+ <source>Totals</source>
+ <translation type="unfinished">Totales</translation>
+ </message>
+ <message>
+ <source>Debug log file</source>
+ <translation type="unfinished">Archivo de registro de depuración</translation>
+ </message>
+ <message>
+ <source>Clear console</source>
+ <translation type="unfinished">Limpiar consola</translation>
+ </message>
+ <message>
+ <source>In:</source>
+ <translation type="unfinished">Entrada:</translation>
+ </message>
+ <message>
+ <source>Out:</source>
+ <translation type="unfinished">Salida:</translation>
</message>
<message>
<source>Inbound: initiated by peer</source>
@@ -1978,8 +3276,12 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
<translation type="unfinished">&amp;Desconectar</translation>
</message>
<message>
+ <source>1 &amp;hour</source>
+ <translation type="unfinished">1 &amp;hora</translation>
+ </message>
+ <message>
<source>1 d&amp;ay</source>
- <translation type="unfinished">1 día</translation>
+ <translation type="unfinished">1 &amp;día</translation>
</message>
<message>
<source>1 &amp;week</source>
@@ -1995,10 +3297,22 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co
<translation type="unfinished">&amp;Copiar IP/Mascara de red</translation>
</message>
<message>
+ <source>&amp;Unban</source>
+ <translation type="unfinished">&amp;Desbloquear</translation>
+ </message>
+ <message>
<source>Network activity disabled</source>
<translation type="unfinished">Actividad de red desactivada</translation>
</message>
<message>
+ <source>Executing command without any wallet</source>
+ <translation type="unfinished">Ejecutar comando sin monedero</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation type="unfinished">Ejecutar comando usando monedero «%1»</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.
Use up and down arrows to navigate history, and %2 to clear screen.
Use %3 and %4 to increase or decrease the font size.
@@ -2012,7 +3326,7 @@ For more information on using this console, type %6.
Utiliza %3 y %4 para aumentar o disminuir el tamaño de la fuente.
Escribe %5 para ver un resumen de los comandos disponibles. Para más información sobre cómo usar esta consola, escribe %6.
-%7AVISO: Los estafadores han estado activos diciendo a los usuarios que escriban comandos aquí, robando el contenido de sus carteras. No uses esta consola sin entender completamente las ramificaciones de un comando.%8</translation>
+%7 AVISO: Los estafadores han estado activos diciendo a los usuarios que escriban comandos aquí, robando el contenido de sus monederos. No uses esta consola sin entender completamente las ramificaciones de un comando.%8</translation>
</message>
<message>
<source>Executing…</source>
@@ -2040,6 +3354,10 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
<translation type="unfinished">De</translation>
</message>
<message>
+ <source>Ban for</source>
+ <translation type="unfinished">Bloqueo para</translation>
+ </message>
+ <message>
<source>Never</source>
<translation type="unfinished">Nunca</translation>
</message>
@@ -2052,7 +3370,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
<name>ReceiveCoinsDialog</name>
<message>
<source>&amp;Amount:</source>
- <translation type="unfinished">&amp;Cantidad</translation>
+ <translation type="unfinished">&amp;Importe</translation>
</message>
<message>
<source>&amp;Label:</source>
@@ -2063,10 +3381,50 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
<translation type="unfinished">&amp;Mensaje</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 type="unfinished">Mensaje opcional para agregar a la solicitud de pago, el cual será mostrado cuando la solicitud esté abierta. Nota: El mensaje no se enviará con el pago a través de la red de Bitcoin.</translation>
+ </message>
+ <message>
+ <source>An optional label to associate with the new receiving address.</source>
+ <translation type="unfinished">Etiqueta opcional para asociar con la nueva dirección de recepción.</translation>
+ </message>
+ <message>
+ <source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
+ <translation type="unfinished">Usa este formulario para solicitar un pago. Todos los campos son &lt;b&gt;opcionales&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 type="unfinished">Un importe opcional para solicitar. Deje esto vacío o en cero para no solicitar una cantidad específica.</translation>
+ </message>
+ <message>
+ <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
+ <translation type="unfinished">Etiqueta opcional para asociar con la nueva dirección de recepción (utilizado por ti para identificar una factura). También esta asociado a la solicitud de pago.</translation>
+ </message>
+ <message>
+ <source>An optional message that is attached to the payment request and may be displayed to the sender.</source>
+ <translation type="unfinished">Mensaje opcional asociado a la solicitud de pago que podría ser presentado al remitente </translation>
+ </message>
+ <message>
+ <source>&amp;Create new receiving address</source>
+ <translation type="unfinished">&amp;Crear una nueva dirección de recepción</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation type="unfinished">Limpiar todos los campos del formulario.</translation>
+ </message>
+ <message>
<source>Clear</source>
<translation type="unfinished">Limpiar</translation>
</message>
<message>
+ <source>Requested payments history</source>
+ <translation type="unfinished">Historial de pagos solicitados</translation>
+ </message>
+ <message>
+ <source>Show the selected request (does the same as double clicking an entry)</source>
+ <translation type="unfinished">Mostrar la solicitud seleccionada (hace lo mismo que hacer doble clic en una entrada)</translation>
+ </message>
+ <message>
<source>Show</source>
<translation type="unfinished">Mostrar</translation>
</message>
@@ -2096,7 +3454,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
</message>
<message>
<source>Copy &amp;amount</source>
- <translation type="unfinished">Copiar &amp;cantidad</translation>
+ <translation type="unfinished">Copiar &amp;importe</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">No se pudo desbloquear el monedero.</translation>
</message>
<message>
<source>Could not generate new %1 address</source>
@@ -2115,7 +3477,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
</message>
<message>
<source>Amount:</source>
- <translation type="unfinished">Cantidad:</translation>
+ <translation type="unfinished">Importe:</translation>
</message>
<message>
<source>Label:</source>
@@ -2130,8 +3492,12 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
<translation type="unfinished">Monedero:</translation>
</message>
<message>
+ <source>Copy &amp;URI</source>
+ <translation type="unfinished">Copiar &amp;URI</translation>
+ </message>
+ <message>
<source>Copy &amp;Address</source>
- <translation type="unfinished">Copiar &amp;Dirección</translation>
+ <translation type="unfinished">Copiar &amp;dirección</translation>
</message>
<message>
<source>&amp;Verify</source>
@@ -2139,7 +3505,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
</message>
<message>
<source>Verify this address on e.g. a hardware wallet screen</source>
- <translation type="unfinished">Verifica esta dirección en la pantalla de tu billetera fría u otro dispositivo</translation>
+ <translation type="unfinished">Verifica esta dirección en la pantalla de tu monedero frío u otro dispositivo</translation>
</message>
<message>
<source>&amp;Save Image…</source>
@@ -2149,10 +3515,18 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
<source>Payment information</source>
<translation type="unfinished">Información del pago</translation>
</message>
- </context>
+ <message>
+ <source>Request payment to %1</source>
+ <translation type="unfinished">Solicitar pago a %1</translation>
+ </message>
+</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation type="unfinished">Fecha</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">Etiqueta</translation>
</message>
@@ -2164,7 +3538,19 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
<source>(no label)</source>
<translation type="unfinished">(sin etiqueta)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation type="unfinished">(sin mensaje)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation type="unfinished">(sin importe solicitado)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation type="unfinished">Solicitado</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -2173,7 +3559,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
</message>
<message>
<source>Coin Control Features</source>
- <translation type="unfinished">Características de control de la moneda</translation>
+ <translation type="unfinished">Características de control de moneda</translation>
</message>
<message>
<source>automatically selected</source>
@@ -2189,7 +3575,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
</message>
<message>
<source>Amount:</source>
- <translation type="unfinished">Cuantía:</translation>
+ <translation type="unfinished">Importe:</translation>
</message>
<message>
<source>Fee:</source>
@@ -2204,32 +3590,80 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informaciÃ
<translation type="unfinished">Cambio:</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 type="unfinished">Al activarse, si la dirección esta vacía o es inválida, las monedas serán enviadas a una nueva dirección generada.</translation>
+ </message>
+ <message>
+ <source>Custom change address</source>
+ <translation type="unfinished">Dirección de cambio personalizada</translation>
+ </message>
+ <message>
+ <source>Transaction Fee:</source>
+ <translation type="unfinished">Comisión de transacción:</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 type="unfinished">Si utilizas la comisión por defecto, la transacción puede tardar varias horas o incluso días (o nunca) en confirmarse. Considera elegir la comisión de forma manual o espera hasta que se haya validado completamente la cadena.</translation>
</message>
<message>
+ <source>Warning: Fee estimation is currently not possible.</source>
+ <translation type="unfinished">Advertencia: En este momento no se puede estimar la comisión.</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation type="unfinished">por kilobyte</translation>
</message>
<message>
+ <source>Hide</source>
+ <translation type="unfinished">Ocultar</translation>
+ </message>
+ <message>
+ <source>Recommended:</source>
+ <translation type="unfinished">Recomendado:</translation>
+ </message>
+ <message>
+ <source>Custom:</source>
+ <translation type="unfinished">Personalizado:</translation>
+ </message>
+ <message>
+ <source>Send to multiple recipients at once</source>
+ <translation type="unfinished">Enviar a múltiples destinatarios a la vez</translation>
+ </message>
+ <message>
+ <source>Add &amp;Recipient</source>
+ <translation type="unfinished">Agrega &amp;destinatario</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation type="unfinished">Limpiar todos los campos del formulario.</translation>
+ </message>
+ <message>
<source>Inputs…</source>
<translation type="unfinished">Entradas...</translation>
</message>
<message>
+ <source>Dust:</source>
+ <translation type="unfinished">Polvo:</translation>
+ </message>
+ <message>
<source>Choose…</source>
<translation type="unfinished">Elegir...</translation>
</message>
<message>
<source>Hide transaction fee settings</source>
- <translation type="unfinished">Ocultar ajustes de tarifas de transacción</translation>
+ <translation type="unfinished">Ocultar ajustes de comisión de transacción</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 rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
- <translation type="unfinished">Especifica una tarifa personalizada por kB (1.000 bytes) del tamaño virtual de la transacción.
+ <translation type="unfinished">Especifica una comisión personalizada por kB (1.000 bytes) del tamaño virtual de la transacción.
-Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por kvB" para una transacción de 500 bytes virtuales (la mitad de 1 kvB), supondría finalmente una tasa de sólo 50 satoshis.</translation>
+Nota: Dado que la comisión se calcula por cada byte, una tasa de «100 satoshis por kvB» para una transacción de 500 bytes virtuales (la mitad de 1 kvB), supondría finalmente una comisión de sólo 50 satoshis.</translation>
+ </message>
+ <message>
+ <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">Cuando hay menos volumen de transacciones que espacio en los bloques, los mineros y los nodos de retransmisión pueden imponer una comisión mínima. Pagar solo esta comisión mínima está bien, pero tenga en cuenta que esto puede resultar en una transacción nunca confirmada una vez que haya más demanda de transacciones de Bitcoin de la que la red puede procesar.</translation>
</message>
<message>
<source>A too low fee might result in a never confirming transaction (read the tooltip)</source>
@@ -2240,6 +3674,66 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<translation type="unfinished">(Comisión inteligente no inicializada todavía. Esto normalmente tarda unos pocos bloques…)</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation type="unfinished">Objetivo de tiempo de confirmación</translation>
+ </message>
+ <message>
+ <source>Enable Replace-By-Fee</source>
+ <translation type="unfinished">Habilitar 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 type="unfinished">Con Replace-By-Fee (BIP-125) puede incrementar la comisión después de haber enviado la transacción. Si no utiliza esto, se recomienda que añada una comisión mayor para compensar el riesgo adicional de que la transacción se retrase.</translation>
+ </message>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation type="unfinished">Limpiar &amp;todo</translation>
+ </message>
+ <message>
+ <source>Balance:</source>
+ <translation type="unfinished">Saldo:</translation>
+ </message>
+ <message>
+ <source>Confirm the send action</source>
+ <translation type="unfinished">Confirmar el envío</translation>
+ </message>
+ <message>
+ <source>S&amp;end</source>
+ <translation type="unfinished">&amp;Enviar</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Copiar importe</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Copiar comisión</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Copiar después de la comisión</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Copiar bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">Copiar polvo</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">Copiar cambio</translation>
+ </message>
+ <message>
+ <source>%1 (%2 blocks)</source>
+ <translation type="unfinished">%1 (%2 bloques)</translation>
+ </message>
+ <message>
<source>Sign on device</source>
<extracomment>"device" usually means a hardware wallet.</extracomment>
<translation type="unfinished">Iniciar sesión en el dispositivo</translation>
@@ -2254,8 +3748,28 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<translation type="unfinished">Configura una ruta externa al script en Opciones -&gt; Monedero</translation>
</message>
<message>
+ <source>Cr&amp;eate Unsigned</source>
+ <translation type="unfinished">Cr&amp;ear sin firmar</translation>
+ </message>
+ <message>
+ <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <translation type="unfinished">Crea una Transacción de Bitcoin Parcialmente Firmada (TBPF) para uso con p.ej. un monedero fuera de linea %1, o un monedero de hardware compatible con TBPF</translation>
+ </message>
+ <message>
+ <source> from wallet '%1'</source>
+ <translation type="unfinished">desde monedero «%1»</translation>
+ </message>
+ <message>
+ <source>%1 to '%2'</source>
+ <translation type="unfinished">%1 a «%2»</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation type="unfinished">%1 a %2</translation>
+ </message>
+ <message>
<source>To review recipient list click "Show Details…"</source>
- <translation type="unfinished">Para ver la lista de receptores haga clic en "Mostrar detalles"</translation>
+ <translation type="unfinished">Para ver la lista de receptores haga clic en «Mostrar detalles...»</translation>
</message>
<message>
<source>Sign failed</source>
@@ -2282,7 +3796,7 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
</message>
<message>
<source>PSBT saved</source>
- <translation type="unfinished">PSBT guardado </translation>
+ <translation type="unfinished">TBPF guardado </translation>
</message>
<message>
<source>External balance:</source>
@@ -2293,6 +3807,10 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<translation type="unfinished">o</translation>
</message>
<message>
+ <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
+ <translation type="unfinished">Puede incrementar la comisión más tarde (use Replace-By-Fee, BIP-125).</translation>
+ </message>
+ <message>
<source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment>
<translation type="unfinished">Por favor, revisa tu propuesta de transacción. Esto producirá una Transacción de Bitcoin Parcialmente Firmada (TBPF) que puedes guardar o copiar y después firmar p.ej. un monedero fuera de línea %1, o un monedero de hardware compatible con TBPF.</translation>
@@ -2300,12 +3818,12 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<message>
<source>Do you want to create this transaction?</source>
<extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
- <translation type="unfinished">Deseas crear esta transacción?</translation>
+ <translation type="unfinished">¿Deseas crear esta transacción?</translation>
</message>
<message>
<source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
- <translation type="unfinished">Por favor, revisa tu transacción. Puedes crear y enviar esta transacción o crear una Transacción Bitcoin Parcialmente Firmada (PSBT), que puedes guardar o copiar y luego firmar con, por ejemplo, un monedero %1 offline o un monedero hardware compatible con PSBT.</translation>
+ <translation type="unfinished">Por favor, revisa tu transacción. Puedes crear y enviar esta transacción o crear una Transacción Bitcoin Parcialmente Firmada (TBPF), que puedes guardar o copiar y luego firmar con, por ejemplo, un monedero %1 offline o un monedero hardware compatible con TBPF.</translation>
</message>
<message>
<source>Please, review your transaction.</source>
@@ -2317,17 +3835,73 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<translation type="unfinished">Comisión por transacción.</translation>
</message>
<message>
+ <source>Not signalling Replace-By-Fee, BIP-125.</source>
+ <translation type="unfinished">No usa Replace-By-Fee, BIP-125.</translation>
+ </message>
+ <message>
<source>Total Amount</source>
- <translation type="unfinished">Cantidad total</translation>
+ <translation type="unfinished">Importe total</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation type="unfinished">Confirmar el envío de monedas</translation>
+ </message>
+ <message>
+ <source>Watch-only balance:</source>
+ <translation type="unfinished">Balance solo observación:</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation type="unfinished">La dirección de envío no es válida. Por favor revísela.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation type="unfinished">El importe a pagar debe ser mayor que 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation type="unfinished">El importe sobrepasa su saldo.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation type="unfinished">El total sobrepasa su saldo cuando se incluye la comisión de envío de %1.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation type="unfinished">Dirección duplicada encontrada: las direcciones sólo deben ser utilizadas una vez.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation type="unfinished">¡Fallo al crear la transacción!</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation type="unfinished">Una comisión mayor que %1 se considera como una comisión absurdamente alta.</translation>
</message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Estimado para comenzar confirmación dentro de %n bloque.</numerusform>
+ <numerusform>Estimado para comenzar confirmación dentro de %n bloques.</numerusform>
</translation>
</message>
<message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation type="unfinished">Alerta: Dirección de Bitcoin inválida</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation type="unfinished">Alerta: Dirección de cambio desconocida</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation type="unfinished">Confirmar dirección de cambio personalizada</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 type="unfinished">La dirección que ha seleccionado para el cambio no es parte de su monedero. Parte o todos sus fondos pueden ser enviados a esta dirección. ¿Está seguro?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(sin etiqueta)</translation>
</message>
@@ -2335,20 +3909,44 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<context>
<name>SendCoinsEntry</name>
<message>
+ <source>A&amp;mount:</source>
+ <translation type="unfinished">I&amp;mporte:</translation>
+ </message>
+ <message>
+ <source>Pay &amp;To:</source>
+ <translation type="unfinished">Pagar &amp;a:</translation>
+ </message>
+ <message>
+ <source>&amp;Label:</source>
+ <translation type="unfinished">&amp;Etiqueta:</translation>
+ </message>
+ <message>
<source>Choose previously used address</source>
<translation type="unfinished">Escoger una dirección previamente usada</translation>
</message>
<message>
+ <source>The Bitcoin address to send the payment to</source>
+ <translation type="unfinished">Dirección Bitcoin a la que se enviará el pago</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation type="unfinished">Pegar dirección desde portapapeles</translation>
+ </message>
+ <message>
<source>Remove this entry</source>
<translation type="unfinished">Quitar esta entrada</translation>
</message>
<message>
<source>The amount to send in the selected unit</source>
- <translation type="unfinished">El monto a enviar en la unidad seleccionada</translation>
+ <translation type="unfinished">El importe a enviar en la unidad seleccionada</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 type="unfinished">La comisión será deducida de la cantidad enviada. El destinatario recibirá menos bitcoins que la cantidad introducida en el campo Cantidad. Si hay varios destinatarios seleccionados, la comisión será distribuida a partes iguales.</translation>
+ <translation type="unfinished">La comisión será deducida de la cantidad enviada. El destinatario recibirá menos bitcoins que la cantidad introducida en el campo Importe. Si hay varios destinatarios seleccionados, la comisión será distribuida a partes iguales.</translation>
+ </message>
+ <message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation type="unfinished">S&amp;ustraer comisión del importe.</translation>
</message>
<message>
<source>Use available balance</source>
@@ -2359,26 +3957,14 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<translation type="unfinished">Mensaje:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Esta es una solicitud de pago no autentificada.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Esta es una solicitud de pago autentificada.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Introduce una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas</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 type="unfinished">Mensaje que se agrgará al URI de Bitcoin, el cuál será almacenado con la transacción para su referencia. Nota: Este mensaje no será mandado a través de la red de Bitcoin.</translation>
- </message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Pagar a:</translation>
+ <translation type="unfinished">Mensaje que se agrgará al URI de Bitcoin, el cuál será almacenado con la transacción para su referencia. Nota: Este mensaje no será enviado a través de la red de Bitcoin.</translation>
</message>
- </context>
+</context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -2393,30 +3979,146 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<context>
<name>SignVerifyMessageDialog</name>
<message>
+ <source>Signatures - Sign / Verify a Message</source>
+ <translation type="unfinished">Firmas - Firmar / verificar un mensaje</translation>
+ </message>
+ <message>
<source>&amp;Sign Message</source>
- <translation type="unfinished">&amp;Firmar Mensaje</translation>
+ <translation type="unfinished">&amp;Firmar mensaje</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 type="unfinished">Puedes firmar los mensajes con tus direcciones para demostrar que las posees. Ten cuidado de no firmar cualquier cosa vaga, ya que los ataques de phishing pueden tratar de engañarte firmando tu identidad a través de ellos. Firma solo declaraciones totalmente detalladas con las que estés de acuerdo.</translation>
</message>
<message>
+ <source>The Bitcoin address to sign the message with</source>
+ <translation type="unfinished">La dirección Bitcoin con la que se firmó el mensaje</translation>
+ </message>
+ <message>
<source>Choose previously used address</source>
- <translation type="unfinished">Escoger dirección previamente usada</translation>
+ <translation type="unfinished">Escoger una dirección previamente usada</translation>
</message>
<message>
<source>Paste address from clipboard</source>
- <translation type="unfinished">Pega dirección desde portapapeles</translation>
+ <translation type="unfinished">Pegar dirección desde portapapeles</translation>
+ </message>
+ <message>
+ <source>Enter the message you want to sign here</source>
+ <translation type="unfinished">Escribe aquí el mensaje que deseas firmar</translation>
</message>
<message>
<source>Signature</source>
<translation type="unfinished">Firma</translation>
</message>
<message>
+ <source>Copy the current signature to the system clipboard</source>
+ <translation type="unfinished">Copiar la firma actual al portapapeles del sistema</translation>
+ </message>
+ <message>
+ <source>Sign the message to prove you own this Bitcoin address</source>
+ <translation type="unfinished">Firmar un mensaje para demostrar que se posee una dirección Bitcoin</translation>
+ </message>
+ <message>
+ <source>Sign &amp;Message</source>
+ <translation type="unfinished">Firmar &amp;mensaje</translation>
+ </message>
+ <message>
+ <source>Reset all sign message fields</source>
+ <translation type="unfinished">Limpiar todos los campos de la firma de mensaje</translation>
+ </message>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation type="unfinished">Limpiar &amp;todo</translation>
+ </message>
+ <message>
+ <source>&amp;Verify Message</source>
+ <translation type="unfinished">&amp;Verificar mensaje</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 type="unfinished">Introduzca la dirección para la firma, el mensaje (asegurándose de copiar tal cual los saltos de línea, espacios, tabulaciones, etc.) y la firma a continuación para verificar el mensaje. Tenga cuidado de no asumir más información de lo que dice el propio mensaje firmado para evitar fraudes basados en ataques de tipo man-in-the-middle. Tenga en cuenta que esto solo prueba que la parte firmante recibe con esta dirección, ¡no puede probar el envío de ninguna transacción!</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address the message was signed with</source>
+ <translation type="unfinished">Dirección Bitcoin con la que firmar el mensaje</translation>
+ </message>
+ <message>
+ <source>The signed message to verify</source>
+ <translation type="unfinished">El mensaje firmado para verificar</translation>
+ </message>
+ <message>
+ <source>The signature given when the message was signed</source>
+ <translation type="unfinished">La firma proporcionada cuando el mensaje fue firmado</translation>
+ </message>
+ <message>
+ <source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
+ <translation type="unfinished">Verifique el mensaje para comprobar que fue firmado con la dirección Bitcoin indicada</translation>
+ </message>
+ <message>
+ <source>Verify &amp;Message</source>
+ <translation type="unfinished">Verificar &amp;mensaje</translation>
+ </message>
+ <message>
+ <source>Reset all verify message fields</source>
+ <translation type="unfinished">Limpiar todos los campos de la verificación de mensaje</translation>
+ </message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation type="unfinished">Haga clic en «Firmar mensaje» para generar la firma</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation type="unfinished">La dirección introducida es inválida</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation type="unfinished">Por favor, revise la dirección e inténtelo nuevamente.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation type="unfinished">La dirección introducida no corresponde a una clave.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation type="unfinished">Se ha cancelado el desbloqueo del monedero. </translation>
+ </message>
+ <message>
+ <source>No error</source>
+ <translation type="unfinished">Sin error </translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation type="unfinished">No se dispone de la clave privada para la dirección introducida.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation type="unfinished">Falló la firma del mensaje.</translation>
+ </message>
+ <message>
<source>Message signed.</source>
<translation type="unfinished">Mensaje firmado.</translation>
</message>
- </context>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation type="unfinished">La firma no pudo decodificarse.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation type="unfinished">Por favor, compruebe la firma e inténtelo de nuevo.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation type="unfinished">La firma no coincide con el resumen del mensaje.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation type="unfinished">Falló la verificación del mensaje.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation type="unfinished">Mensaje verificado.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -2431,6 +4133,40 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<context>
<name>TransactionDesc</name>
<message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
+ <translation type="unfinished">Hay un conflicto con una transacción de %1 confirmaciones.</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/sin confirmar, en la piscina de memoria</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/sin confirmar, no en la piscina de memoria</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
+ <translation type="unfinished">abandonada</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
+ <translation type="unfinished">%1/sin confirmar</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
+ <translation type="unfinished">%1 confirmaciones</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation type="unfinished">Estado</translation>
+ </message>
+ <message>
<source>Date</source>
<translation type="unfinished">Fecha</translation>
</message>
@@ -2443,28 +4179,199 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<translation type="unfinished">Generado</translation>
</message>
<message>
+ <source>From</source>
+ <translation type="unfinished">De</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished">desconocido</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation type="unfinished">Para</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation type="unfinished">dirección propia</translation>
+ </message>
+ <message>
<source>watch-only</source>
<translation type="unfinished">Solo observación</translation>
</message>
+ <message>
+ <source>label</source>
+ <translation type="unfinished">etiqueta</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation type="unfinished">Crédito</translation>
+ </message>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>disponible en %n bloque</numerusform>
+ <numerusform>disponible en %n bloques</numerusform>
</translation>
</message>
<message>
+ <source>not accepted</source>
+ <translation type="unfinished">no aceptada</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation type="unfinished">Débito</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation type="unfinished">Total débito</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation type="unfinished">Total crédito</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation type="unfinished">Comisión por transacción.</translation>
</message>
- </context>
+ <message>
+ <source>Net amount</source>
+ <translation type="unfinished">Importe neto</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation type="unfinished">Mensaje</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation type="unfinished">Comentario</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation type="unfinished">ID transacción</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation type="unfinished">Tamaño total transacción</translation>
+ </message>
+ <message>
+ <source>Transaction virtual size</source>
+ <translation type="unfinished">Tamaño virtual transacción</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation type="unfinished">Ãndice de salida</translation>
+ </message>
+ <message>
+ <source> (Certificate was not verified)</source>
+ <translation type="unfinished"> (No se ha verificado el certificado)</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation type="unfinished">Comerciante</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 type="unfinished">Las monedas generadas deben madurar %1 bloques antes de que puedan ser gastadas. Una vez que generas este bloque, es propagado por la red para ser añadido a la cadena de bloques. Si falla el intento de añadirse en la cadena, su estado cambiará a «no aceptado» y ya no se puede gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque a los pocos segundos del tuyo.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation type="unfinished">Información de depuración</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation type="unfinished">Transacción</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation type="unfinished">Entradas</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Importe</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation type="unfinished">verdadero</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation type="unfinished">falso</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionDescDialog</name>
+ <message>
+ <source>This pane shows a detailed description of the transaction</source>
+ <translation type="unfinished">Esta ventana muestra información detallada sobre la transacción</translation>
+ </message>
+ <message>
+ <source>Details for %1</source>
+ <translation type="unfinished">Detalles para %1</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation type="unfinished">Fecha</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation type="unfinished">Tipo</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">Etiqueta</translation>
</message>
<message>
+ <source>Unconfirmed</source>
+ <translation type="unfinished">Sin confirmar</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation type="unfinished">Abandonada</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation type="unfinished">Confirmando (%1 de %2 confirmaciones recomendadas)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation type="unfinished">Confirmada (%1 confirmaciones)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation type="unfinished">En conflicto</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation type="unfinished">No disponible (%1 confirmaciones, disponible después de %2)</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation type="unfinished">Generada pero no aceptada</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation type="unfinished">Recibido con</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation type="unfinished">Recibido de</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation type="unfinished">Enviado a</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation type="unfinished">Pago a mi mismo</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation type="unfinished">Minado</translation>
+ </message>
+ <message>
<source>watch-only</source>
<translation type="unfinished">Solo observación</translation>
</message>
@@ -2472,24 +4379,100 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<source>(no label)</source>
<translation type="unfinished">(sin etiqueta)</translation>
</message>
- </context>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation type="unfinished">Estado de transacción. Pasa el ratón sobre este campo para ver el número de confirmaciones.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation type="unfinished">Fecha y hora cuando se recibió la transacción.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation type="unfinished">Tipo de transacción.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation type="unfinished">Si una dirección de solo observación está involucrada en esta transacción o no.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation type="unfinished">Descripción de la transacción definida por el usuario.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation type="unfinished">Importe sustraído o añadido al balance.</translation>
+ </message>
+</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation type="unfinished">Todo</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation type="unfinished">Hoy</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation type="unfinished">Esta semana</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation type="unfinished">Este mes</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation type="unfinished">El mes pasado </translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation type="unfinished">Este año</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation type="unfinished">Recibido con</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation type="unfinished">Enviado a</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation type="unfinished">A ti mismo</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation type="unfinished">Minado</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation type="unfinished">Otra</translation>
+ </message>
+ <message>
+ <source>Enter address, transaction id, or label to search</source>
+ <translation type="unfinished">Introduzca dirección, id de transacción o etiqueta a buscar</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation type="unfinished">Importe mínimo</translation>
+ </message>
+ <message>
<source>Range…</source>
<translation type="unfinished">Rango...</translation>
</message>
<message>
<source>&amp;Copy address</source>
- <translation type="unfinished">copiar dirección </translation>
+ <translation type="unfinished">&amp;Copiar dirección</translation>
</message>
<message>
<source>Copy &amp;label</source>
- <translation type="unfinished">copiar y etiquetar </translation>
+ <translation type="unfinished">Copiar &amp;etiqueta</translation>
</message>
<message>
<source>Copy &amp;amount</source>
- <translation type="unfinished">Copiar cantidad</translation>
+ <translation type="unfinished">Copiar &amp;importe</translation>
</message>
<message>
<source>Copy transaction &amp;ID</source>
@@ -2497,27 +4480,27 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
</message>
<message>
<source>Copy &amp;raw transaction</source>
- <translation type="unfinished">Copiar traducción en crudo</translation>
+ <translation type="unfinished">Copiar transacción en c&amp;rudo</translation>
</message>
<message>
<source>Copy full transaction &amp;details</source>
- <translation type="unfinished">Copiar la transacción entera &amp; detalles</translation>
+ <translation type="unfinished">Copiar &amp;detalles completos de la transacción</translation>
</message>
<message>
<source>&amp;Show transaction details</source>
- <translation type="unfinished">Mostrar detalles de la transacción</translation>
+ <translation type="unfinished">&amp;Mostrar detalles de la transacción</translation>
</message>
<message>
<source>Increase transaction &amp;fee</source>
- <translation type="unfinished">Incrementar la comisión de transacción</translation>
+ <translation type="unfinished">&amp;Incrementar comisión de transacción</translation>
</message>
<message>
<source>A&amp;bandon transaction</source>
- <translation type="unfinished">Abandonar transacción</translation>
+ <translation type="unfinished">A&amp;bandonar transacción</translation>
</message>
<message>
<source>&amp;Edit address label</source>
- <translation type="unfinished">Editar etiqueta de dirección</translation>
+ <translation type="unfinished">&amp;Editar etiqueta de dirección</translation>
</message>
<message>
<source>Show in %1</source>
@@ -2525,10 +4508,31 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<translation type="unfinished">Mostrar en %1</translation>
</message>
<message>
+ <source>Export Transaction History</source>
+ <translation type="unfinished">Exportar historial de transacciones</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Archivo separado por comas</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">Confirmado</translation>
</message>
<message>
+ <source>Watch-only</source>
+ <translation type="unfinished">Solo observación</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Fecha</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation type="unfinished">Tipo</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">Etiqueta</translation>
</message>
@@ -2540,7 +4544,27 @@ Nota: Dado que la tasa se calcula por cada byte, una tasa de "100 satoshis por k
<source>Exporting Failed</source>
<translation type="unfinished">La exportación falló</translation>
</message>
- </context>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation type="unfinished">Ha habido un error al intentar guardar en el histórico la transacción con %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation type="unfinished">Exportación satisfactoria</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation type="unfinished">El historial de transacciones ha sido guardado exitosamente en %1</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation type="unfinished">Rango:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation type="unfinished">a</translation>
+ </message>
+</context>
<context>
<name>WalletFrame</name>
<message>
@@ -2553,11 +4577,11 @@ Vaya a Archivo&gt; Abrir monedero para cargar un monedero.
</message>
<message>
<source>Create a new wallet</source>
- <translation type="unfinished">Crear monedero nuevo</translation>
+ <translation type="unfinished">Crea un monedero nuevo</translation>
</message>
<message>
<source>Unable to decode PSBT from clipboard (invalid base64)</source>
- <translation type="unfinished">No se puede decodificar PSBT desde el portapapeles (inválido base64)</translation>
+ <translation type="unfinished">No se puede decodificar TBPF desde el portapapeles (inválido base64)</translation>
</message>
<message>
<source>Load Transaction Data</source>
@@ -2569,27 +4593,75 @@ Vaya a Archivo&gt; Abrir monedero para cargar un monedero.
</message>
<message>
<source>PSBT file must be smaller than 100 MiB</source>
- <translation type="unfinished">El archivo PSBT debe ser más pequeño de 100 MiB</translation>
+ <translation type="unfinished">El archivo TBPF debe ser más pequeño de 100 MiB</translation>
</message>
<message>
<source>Unable to decode PSBT</source>
- <translation type="unfinished">Imposible descodificar PSBT</translation>
+ <translation type="unfinished">No es posible descodificar TBPF</translation>
</message>
</context>
<context>
<name>WalletModel</name>
<message>
+ <source>Send Coins</source>
+ <translation type="unfinished">Enviar monedas</translation>
+ </message>
+ <message>
+ <source>Fee bump error</source>
+ <translation type="unfinished">Error de incremento de la comisión</translation>
+ </message>
+ <message>
+ <source>Increasing transaction fee failed</source>
+ <translation type="unfinished">Ha fallado el incremento de la comisión de transacción.</translation>
+ </message>
+ <message>
+ <source>Do you want to increase the fee?</source>
+ <extracomment>Asks a user if they would like to manually increase the fee of a transaction that has already been created.</extracomment>
+ <translation type="unfinished">¿Desea incrementar la comisión?</translation>
+ </message>
+ <message>
+ <source>Current fee:</source>
+ <translation type="unfinished">Comisión actual:</translation>
+ </message>
+ <message>
+ <source>Increase:</source>
+ <translation type="unfinished">Incremento:</translation>
+ </message>
+ <message>
+ <source>New fee:</source>
+ <translation type="unfinished">Nueva comisión:</translation>
+ </message>
+ <message>
<source>Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
- <translation type="unfinished">Advertencia: Esto puede pagar la tasa adicional al reducir el cambio de salidas o agregar entradas, cuando sea necesario. Puede agregar una nueva salida de cambio si aún no existe. Estos cambios pueden potencialmente filtrar la privacidad.</translation>
+ <translation type="unfinished">Advertencia: Esto puede pagar la comisión adicional al reducir el cambio de salidas o agregar entradas, cuando sea necesario. Puede agregar una nueva salida de cambio si aún no existe. Potencialmente estos cambios pueden comprometer la privacidad.</translation>
+ </message>
+ <message>
+ <source>Confirm fee bump</source>
+ <translation type="unfinished">Confirmar incremento de comisión</translation>
+ </message>
+ <message>
+ <source>Can't draft transaction.</source>
+ <translation type="unfinished">No se pudo preparar la transacción.</translation>
+ </message>
+ <message>
+ <source>PSBT copied</source>
+ <translation type="unfinished">TBPF copiada </translation>
+ </message>
+ <message>
+ <source>Can't sign transaction.</source>
+ <translation type="unfinished">No se ha podido firmar la transacción.</translation>
+ </message>
+ <message>
+ <source>Could not commit transaction</source>
+ <translation type="unfinished">No se pudo confirmar la transacción</translation>
</message>
<message>
<source>Can't display address</source>
- <translation type="unfinished">No se puede mostrar la dirección
-</translation>
+ <translation type="unfinished">No se puede mostrar la dirección</translation>
</message>
<message>
<source>default wallet</source>
- <translation type="unfinished">Monedero predeterminado</translation>
+ <translation type="unfinished">monedero predeterminado</translation>
</message>
</context>
<context>
@@ -2603,9 +4675,33 @@ Vaya a Archivo&gt; Abrir monedero para cargar un monedero.
<translation type="unfinished">Exportar a un archivo los datos de esta pestaña</translation>
</message>
<message>
+ <source>Backup Wallet</source>
+ <translation type="unfinished">Respaldar monedero</translation>
+ </message>
+ <message>
<source>Wallet Data</source>
<extracomment>Name of the wallet data file format.</extracomment>
- <translation type="unfinished">Datos de la billetera </translation>
+ <translation type="unfinished">Datos del monedero </translation>
</message>
- </context>
+ <message>
+ <source>Backup Failed</source>
+ <translation type="unfinished">Copia de seguridad fallida</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation type="unfinished">Ha habido un error al intentar guardar los datos del monedero a %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation type="unfinished">Se ha completado con éxito la copia de respaldo</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation type="unfinished">Los datos del monedero se han guardado con éxito en %1.</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">Cancelar</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts
index f7f8f0e39b..7e61ba51ec 100644
--- a/src/qt/locale/bitcoin_es_CL.ts
+++ b/src/qt/locale/bitcoin_es_CL.ts
@@ -246,7 +246,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p
</message>
<message>
<source>Internal error</source>
- <translation type="unfinished">Error interno</translation>
+ <translation type="unfinished">error interno</translation>
</message>
<message>
<source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
@@ -427,10 +427,6 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p
<translation type="unfinished">Error al leer la base de datos, cerrando aplicación.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Error actualizando la base de datos chainstate</translation>
- </message>
- <message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation type="unfinished">Ha fallado la escucha en todos los puertos. Usa -listen=0 si desea esto.</translation>
</message>
@@ -546,10 +542,6 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p
<source>Unknown network specified in -onlynet: '%s'</source>
<translation type="unfinished">La red especificada en -onlynet: '%s' es desconocida</translation>
</message>
- <message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Actualizando la base de datos UTXO</translation>
- </message>
</context>
<context>
<name>BitcoinGUI</name>
@@ -1070,6 +1062,27 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(de %n GB requerido)</numerusform>
+ <numerusform>(de %n GB requeridos)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Al menos %1 GB de información será almacenado en este directorio, y seguirá creciendo a través del tiempo.</translation>
@@ -1111,10 +1124,6 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p
<translation type="unfinished">Como esta es la primera vez que se lanza el programa, puede elegir dónde %1 almacenará sus datos.</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 type="unfinished">Al hacer clic OK, %1 iniciará el proceso de descarga y procesará el blockchain completo de %4 (%2 GB), iniciando desde el la transacción más antigua %3 cuando %4 se ejecutó inicialmente.</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 type="unfinished">Esta sincronización inicial es muy exigente y puede exponer problemas de hardware con su computadora que anteriormente habían pasado desapercibidos. Cada vez que ejecuta %1, continuará la descarga donde lo dejó.</translation>
</message>
@@ -1372,14 +1381,17 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirmar restablecimiento de opciones</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Se requiere el reinicio del cliente para activar los cambios.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">El cliente será cluasurado. Quieres proceder?</translation>
</message>
<message>
@@ -2115,10 +2127,6 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Una comisión mayor que %1 se considera como una comisión absurda-mente alta.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Solicitud de pago caducada.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2186,21 +2194,9 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p
<translation type="unfinished">Mensaje:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Esta es una petición de pago no autentificada.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Esta es una petición de pago autentificada.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Introduce una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Pagar a:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -2336,30 +2332,22 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">Hay un conflicto con la traducción de las confirmaciones %1</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/no confirmado, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">en el equipo de memoria</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">no en el equipo de memoria</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">abandonado</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/no confirmado</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">confirmaciones %1</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_es_CO.ts b/src/qt/locale/bitcoin_es_CO.ts
index 68c53b9651..01d35ff59c 100644
--- a/src/qt/locale/bitcoin_es_CO.ts
+++ b/src/qt/locale/bitcoin_es_CO.ts
@@ -7,7 +7,7 @@
</message>
<message>
<source>Create a new address</source>
- <translation type="unfinished">Crea una nueva dirección</translation>
+ <translation type="unfinished">Crear una nueva dirección</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 type="unfinished">Copia la dirección seleccionada al portapapeles</translation>
+ <translation type="unfinished">Copiar la dirección seleccionada actualmente al portapapeles del sistema</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -55,7 +55,7 @@
</message>
<message>
<source>C&amp;hoose</source>
- <translation type="unfinished">Seleccione</translation>
+ <translation type="unfinished">S&amp;eleccionar</translation>
</message>
<message>
<source>Sending addresses</source>
@@ -81,7 +81,7 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation type="unfinished">Copiar etiqueta</translation>
+ <translation type="unfinished">Copiar &amp;etiqueta</translation>
</message>
<message>
<source>&amp;Edit</source>
@@ -209,7 +209,7 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
- <translation type="unfinished">El proceso de encriptación de la billetera fallo por culpa de un problema interno. Tu billetera no fue encriptada.</translation>
+ <translation type="unfinished">La encriptación de la billetera falló debido a un error interno. Su billetera no se encriptó.</translation>
</message>
<message>
<source>The supplied passphrases do not match.</source>
@@ -246,17 +246,51 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">El archivo de configuración %1 puede estar corrupto o no ser válido.</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">Excepción fuera de control</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">Se produjo un error fatal. %1 ya no puede continuar de manera segura y se cerrará.</translation>
+ </message>
+ <message>
<source>Internal error</source>
<translation type="unfinished">Error interno</translation>
</message>
- </context>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Se produjo un error interno. %1 intentará continuar de manera segura. Este es un error inesperado que se puede reportar como se describe a continuación.</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">¿Deseas restablecer los valores a la configuración predeterminada o abortar sin realizar los cambios?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Se produjo un error fatal. Comprueba que el archivo de configuración soporte escritura o intenta ejecutar el programa con -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Error: El directorio de datos "%1" especificado no existe.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">Error: No se puede analizar el archivo de configuración: %1.</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 aún no salió de forma segura...</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">desconocido</translation>
</message>
@@ -269,6 +303,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Ingresa una dirección de Bitcoin (Ejemplo: %1)</translation>
</message>
<message>
+ <source>Unroutable</source>
+ <translation type="unfinished">No enrutable</translation>
+ </message>
+ <message>
+ <source>Internal</source>
+ <translation type="unfinished">Interno</translation>
+ </message>
+ <message>
<source>Inbound</source>
<extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
<translation type="unfinished">Entrante</translation>
@@ -279,42 +321,57 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Saliente</translation>
</message>
<message>
+ <source>Full Relay</source>
+ <extracomment>Peer connection type that relays all network information.</extracomment>
+ <translation type="unfinished">Retransmisión completa</translation>
+ </message>
+ <message>
+ <source>Block Relay</source>
+ <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Retransmisión de bloque</translation>
+ </message>
+ <message>
+ <source>Address Fetch</source>
+ <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
+ <translation type="unfinished">Recuperación de dirección</translation>
+ </message>
+ <message>
<source>None</source>
<translation type="unfinished">Nada</translation>
</message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n segundo</numerusform>
+ <numerusform>%n segundos</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minuto</numerusform>
+ <numerusform>%n minutos</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n hora</numerusform>
+ <numerusform>%n horas</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n día</numerusform>
+ <numerusform>%n días</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n semana</numerusform>
+ <numerusform>%n semanas</numerusform>
</translation>
</message>
<message>
@@ -324,30 +381,102 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n año</numerusform>
+ <numerusform>%n años</numerusform>
</translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">El archivo de configuración no se puede leer</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">El archivo de configuración no se puede escribir</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">Los desarrolladores de %s</translation>
</message>
<message>
+ <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
+ <translation type="unfinished">%s corrupto. Intenta utilizar la herramienta de la billetera de bitcoin para rescatar o restaurar una copia de seguridad.</translation>
+ </message>
+ <message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished">-maxtxfee tiene un valor muy elevado! Comisiones muy grandes podrían ser pagadas en una única transacción.</translation>
</message>
<message>
+ <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
+ <translation type="unfinished">No se puede pasar de la versión %i a la versión anterior %i. La versión de la billetera no tiene cambios.</translation>
+ </message>
+ <message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation type="unfinished">No se puede bloquear el directorio de datos %s. %s probablemente ya se está ejecutando.</translation>
+ </message>
+ <message>
+ <source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
+ <translation type="unfinished">No se puede actualizar una billetera dividida no HD de la versión %i a la versión %i sin actualizar para admitir el pool de claves anterior a la división. Usa la versión %i o no especifiques la versión.</translation>
+ </message>
+ <message>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished">Distribuido bajo la licencia de software MIT, vea el archivo adjunto %s o %s</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 type="unfinished">¡Error al leer %s! Todas las claves se leyeron correctamente, pero es probable que falten los datos de la transacción o la libreta de direcciones, o que sean incorrectos.</translation>
+ </message>
+ <message>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">¡Error al leer %s! Es probable que falten los datos de la transacción o que sean incorrectos. Reescaneando billetera.</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
+ <translation type="unfinished">Error: el registro del formato del archivo de volcado es incorrecto. Se obtuvo "%s"; se esperaba "formato".</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source>
+ <translation type="unfinished">Error: el registro del identificador del archivo de volcado es incorrecto. Se obtuvo "%s"; se esperaba "%s".</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
+ <translation type="unfinished">Error: la versión del archivo volcado no es compatible. Esta versión de la billetera de bitcoin solo admite archivos de volcado de la versión 1. Se obtuvo un archivo de volcado con la versión %s</translation>
+ </message>
+ <message>
+ <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
+ <translation type="unfinished">Error: las billeteras heredadas solo admiten los tipos de dirección "legacy", "p2sh-segwit" y "bech32".</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation type="unfinished">Error al calcular la comisión. La opción "fallbackfee" está desactivada. Espera algunos bloques o activa "fallbackfee".</translation>
+ </message>
+ <message>
+ <source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
+ <translation type="unfinished">El archivo %s ya existe. Si definitivamente quieres hacerlo, quítalo primero.</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 type="unfinished">Importe inválido para -maxtxfee=&lt;amount&gt;: "%s" (debe ser al menos la comisión mínima de retransmisión de %s para evitar transacciones atascadas)</translation>
+ </message>
+ <message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">Archivo peers.dat inválido o corrupto (%s). Si crees que se trata de un error, infórmalo a %s. Como alternativa, puedes quitar el archivo (%s) (renombrarlo, moverlo o eliminarlo) para que se cree uno nuevo en el siguiente inicio.</translation>
+ </message>
+ <message>
<source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
<translation type="unfinished">La Poda se ha configurado por debajo del mínimo de %d MiB. Por favor utiliza un valor mas alto.</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">La base de datos del índice de bloques contiene un "txindex" heredado. Para borrar el espacio de disco ocupado, ejecute un -reindex completo; de lo contrario, ignore este error. Este mensaje de error no se volverá a mostrar.</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation type="unfinished">El monto de la transacción es demasiado pequeño para enviarlo después de deducir la comisión</translation>
+ </message>
+ <message>
<source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
<translation type="unfinished">Esta es la cuota de transacción que puede descartar si el cambio es más pequeño que el polvo a este nivel.</translation>
</message>
@@ -420,10 +549,6 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Error al leer la base de datos, cerrando aplicación.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Error actualizando la base de datos chainstate</translation>
- </message>
- <message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation type="unfinished">Ha fallado la escucha en todos los puertos. Usa -listen=0 si desea esto.</translation>
</message>
@@ -457,7 +582,7 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">Monto invalido para -fallbackfee=&lt;amount&gt;: '%s'</translation>
+ <translation type="unfinished">Monto inválido para -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
@@ -468,6 +593,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Máscara de red inválida especificada en -whitelist: '%s'</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Falta la cantidad</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">Necesita especificar un puerto con -whitebind: '%s'</translation>
</message>
@@ -489,7 +618,7 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>The transaction amount is too small to pay the fee</source>
- <translation type="unfinished">El monto a transferir es muy pequeño para pagar el impuesto</translation>
+ <translation type="unfinished">El monto de la transacción es demasiado pequeño para pagar la comisión</translation>
</message>
<message>
<source>The wallet will avoid paying less than the minimum relay fee.</source>
@@ -539,10 +668,6 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation type="unfinished">La red especificada en -onlynet: '%s' es desconocida</translation>
</message>
- <message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Actualizando la base de datos UTXO</translation>
- </message>
</context>
<context>
<name>BitcoinGUI</name>
@@ -564,7 +689,7 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>E&amp;xit</source>
- <translation type="unfinished">&amp;Salir</translation>
+ <translation type="unfinished">S&amp;alir</translation>
</message>
<message>
<source>Quit application</source>
@@ -572,7 +697,7 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>&amp;About %1</source>
- <translation type="unfinished">S&amp;obre %1</translation>
+ <translation type="unfinished">&amp;Acerca de %1</translation>
</message>
<message>
<source>Show information about %1</source>
@@ -580,7 +705,7 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>About &amp;Qt</source>
- <translation type="unfinished">Acerca de</translation>
+ <translation type="unfinished">Acerca de &amp;Qt</translation>
</message>
<message>
<source>Show information about Qt</source>
@@ -595,6 +720,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Crear una nueva billetera</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimizar</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Billetera:</translation>
</message>
@@ -628,18 +757,26 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">&amp;Recibir</translation>
</message>
<message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Opciones...</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet…</source>
<translation type="unfinished">&amp;Encriptar billetera…</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
- <translation type="unfinished">Cifrar las claves privadas de su monedero</translation>
+ <translation type="unfinished">Cifrar las claves privadas que pertenecen a su billetera</translation>
</message>
<message>
<source>&amp;Backup Wallet…</source>
<translation type="unfinished">&amp;Realizar copia de seguridad de la billetera</translation>
</message>
<message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;Cambiar frase de contraseña...</translation>
+ </message>
+ <message>
<source>Sign &amp;message…</source>
<translation type="unfinished">Firmar &amp;mensaje...</translation>
</message>
@@ -656,6 +793,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Verificar mensajes comprobando que están firmados con direcciones Bitcoin concretas</translation>
</message>
<message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;Cargar PSBT desde archivo...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">Abrir &amp;URI...</translation>
+ </message>
+ <message>
<source>Close Wallet…</source>
<translation type="unfinished">Cerrar Billetera...</translation>
</message>
@@ -684,6 +829,30 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Barra de pestañas</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Sincronizando encabezados (%1%)...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Sincronizando con la red...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Indexando bloques en disco...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Procesando bloques en disco...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Reindexando bloques en disco...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Conectando con pares...</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">Pide pagos (genera codigos QR and bitcoin: URls)</translation>
</message>
@@ -702,8 +871,8 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n bloque procesado del historial de transacciones.</numerusform>
+ <numerusform>%n bloques procesados del historial de transacciones.</numerusform>
</translation>
</message>
<message>
@@ -711,6 +880,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">%1 atrás</translation>
</message>
<message>
+ <source>Catching up…</source>
+ <translation type="unfinished">Poniéndose al día...</translation>
+ </message>
+ <message>
<source>Last received block was generated %1 ago.</source>
<translation type="unfinished">El último bloque recibido fue generado hace %1</translation>
</message>
@@ -731,6 +904,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Actualizado</translation>
</message>
<message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">Cargar transacción de Bitcoin parcialmente firmada</translation>
+ </message>
+ <message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">Cargar PSBT desde el &amp;portapapeles...</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">Cargar una transacción de Bitcoin parcialmente firmada desde el Portapapeles</translation>
</message>
@@ -767,6 +948,16 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Cerrar billetera</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Restaurar billetera…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Restaurar una billetera desde un archivo de copia de seguridad</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Cerrar todas las billeteras</translation>
</message>
@@ -775,6 +966,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Mostrar el mensaje de ayuda %1 para obtener una lista de los posibles comandos de Bitcoin</translation>
</message>
<message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">&amp;Ocultar valores</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">Ocultar los valores en la pestaña de vista general</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">billetera predeterminada</translation>
</message>
@@ -783,9 +982,28 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">No hay billeteras disponibles</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Datos de la billetera</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Cargar copia de seguridad de billetera</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Restaurar billetera</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nombre de la billetera </translation>
+ </message>
+ <message>
<source>&amp;Window</source>
- <translation type="unfinished">y windows
-</translation>
+ <translation type="unfinished">&amp;Ventana</translation>
</message>
<message>
<source>Zoom</source>
@@ -799,15 +1017,47 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<source>%1 client</source>
<translation type="unfinished">%1 cliente</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Ocultar </translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">M&amp;ostrar</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n conexión activa con la red Bitcoin.</numerusform>
+ <numerusform>%n conexiones activas con la red Bitcoin.</numerusform>
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Hacer clic para ver más acciones.</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Mostrar pestaña de pares</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">Deshabilitar actividad de red</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">Habilitar actividad de red</translation>
+ </message>
+ <message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Presincronizando encabezados (%1%)...</translation>
+ </message>
+ <message>
<source>Warning: %1</source>
<translation type="unfinished">Advertencia: %1</translation>
</message>
@@ -959,6 +1209,30 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Copiar Cantidad</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Copiar dirección</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Copiar &amp;etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Copiar &amp;cantidad</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Copiar &amp;identificador de transacción e índice de salidas</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">B&amp;loquear importe no gastado</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;Desbloquear importe no gastado</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Copiar cantidad</translation>
</message>
@@ -1019,6 +1293,11 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Crear Billetera</translation>
</message>
<message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">Creación de monedero&lt;b&gt;%1&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Create wallet failed</source>
<translation type="unfinished">Fallo al crear la billetera</translation>
</message>
@@ -1026,10 +1305,39 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<source>Create wallet warning</source>
<translation type="unfinished">Advertencia al crear la billetera</translation>
</message>
- </context>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">No se puede hacer una lista de firmantes</translation>
+ </message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Se encontraron demasiados firmantes externos</translation>
+ </message>
+</context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">Cargar billeteras</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">Cargando billeteras...</translation>
+ </message>
+</context>
<context>
<name>OpenWalletActivity</name>
<message>
+ <source>Open wallet failed</source>
+ <translation type="unfinished">Fallo al abrir billetera</translation>
+ </message>
+ <message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">Advertencia al abrir billetera</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">billetera predeterminada</translation>
</message>
@@ -1038,7 +1346,40 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">Abrir billetera</translation>
</message>
- </context>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">Abriendo billetera &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Restaurar billetera</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Restaurando billetera &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Error al restaurar la billetera</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Advertencia al restaurar billetera</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Mensaje al restaurar billetera</translation>
+ </message>
+</context>
<context>
<name>WalletController</name>
<message>
@@ -1046,6 +1387,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Cerrar billetera</translation>
</message>
<message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">¿Está seguro de que desea cerrar la billetera &lt;i&gt;%1&lt;/i&gt;?</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">Cerrar la billetera durante demasiado tiempo puede causar la resincronización de toda la cadena si el modo pruning está habilitado.</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Cerrar todas las billeteras</translation>
</message>
@@ -1066,7 +1415,7 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>Wallet</source>
- <translation type="unfinished">Cartera</translation>
+ <translation type="unfinished">Billetera</translation>
</message>
<message>
<source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
@@ -1097,14 +1446,35 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Crear billetera vacía</translation>
</message>
<message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">Use descriptores para la gestión de scriptPubKey</translation>
+ </message>
+ <message>
<source>Descriptor Wallet</source>
<translation type="unfinished">Descriptor de la billetera</translation>
</message>
<message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Use un dispositivo de firma externo, por ejemplo, una billetera de hardware. Configure primero el script del firmante externo en las preferencias de la billetera.</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">Firmante externo</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">Crear</translation>
</message>
- </context>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished">Compilado sin soporte de sqlite (requerido para billeteras basadas en descriptores)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Compilado sin soporte de firma externa (necesario para la firma externa)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -1144,6 +1514,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">La dirección introducida "%1" no es una dirección Bitcoin valida.</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 type="unfinished">La dirección "%1" ya existe como dirección de recepción con la etiqueta "%2" y, por lo tanto, no se puede agregar como dirección de envío.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation type="unfinished">La dirección ingresada "%1" ya está en la libreta de direcciones con la etiqueta "%2".</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">No se pudo desbloquear la billetera.</translation>
</message>
@@ -1177,6 +1555,27 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB de espacio disponible</numerusform>
+ <numerusform>%n GB de espacio disponible</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(de %n GB necesario)</numerusform>
+ <numerusform>(de %n GB necesarios)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB necesario para completar la cadena)</numerusform>
+ <numerusform>(%n GB necesarios para completar la cadena)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Al menos %1 GB de información será almacenado en este directorio, y seguirá creciendo a través del tiempo.</translation>
@@ -1189,8 +1588,8 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(suficiente para restaurar copias de seguridad de %n día de antigüedad)</numerusform>
+ <numerusform>(suficiente para restaurar copias de seguridad de %n días de antigüedad)</numerusform>
</translation>
</message>
<message>
@@ -1218,8 +1617,8 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Al ser la primera vez que se ejecuta el programa, puede elegir donde %1 almacenará sus datos.</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 type="unfinished">Al hacer clic OK, %1 iniciará el proceso de descarga y procesará el blockchain completo de %4 (%2 GB), iniciando desde el la transacción más antigua %3 cuando %4 se ejecutó inicialmente.</translation>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">Limitar el almacenamiento de cadena de bloques a</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
@@ -1230,6 +1629,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">El primer proceso de sincronización consume muchos recursos, y es posible que puedan ocurrir problemas de hardware que anteriormente no hayas notado. Cada vez que ejecutes %1 automáticamente se reiniciará el proceso de sincronización desde el punto que lo dejaste anteriormente.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Al hacer clic en OK, %1 iniciará el proceso de descarga y procesará la cadena de bloques %4 completa (%2 GB), empezando con la transacción más antigua en %3 cuando %4 se ejecutó inicialmente.</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 type="unfinished">Si elegiste la opción de limitar el tamaño del blockchain (pruning), de igual manera será descargada y procesada la información histórica, pero será eliminada al finalizar este proceso para disminuir el uso del disco duro.</translation>
</message>
@@ -1260,6 +1663,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 se está cerrando...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation type="unfinished">No apague el equipo hasta que desaparezca esta ventana.</translation>
</message>
@@ -1283,6 +1690,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Número de bloques restantes</translation>
</message>
<message>
+ <source>Unknown…</source>
+ <translation type="unfinished">Desconocido...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">calculando...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation type="unfinished">Hora del último bloque</translation>
</message>
@@ -1302,10 +1717,26 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<source>Hide</source>
<translation type="unfinished">Ocultar</translation>
</message>
- </context>
+ <message>
+ <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
+ <translation type="unfinished">%1 se está sincronizando actualmente. Descargará encabezados y bloques de pares, y los validará hasta alcanzar el extremo de la cadena de bloques.</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Desconocido. Sincronizando encabezados (%1, %2%)…</translation>
+ </message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Desconocido. Presincronizando encabezados (%1, %2%)…</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
+ <source>Open bitcoin URI</source>
+ <translation type="unfinished">Abrir URI de bitcoin</translation>
+ </message>
+ <message>
<source>Paste address from clipboard</source>
<extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
<translation type="unfinished">Pega dirección desde portapapeles</translation>
@@ -1330,6 +1761,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">&amp;Iniciar %1 al iniciar el sistema</translation>
</message>
<message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Al activar el modo pruning, se reduce considerablemente el espacio de disco necesario para almacenar las transacciones. Todos los bloques aún se validan completamente. Para revertir esta opción, se requiere descargar de nuevo toda la cadena de bloques.</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation type="unfinished">Tamaño del caché de la base de &amp;datos</translation>
</message>
@@ -1350,6 +1785,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Minimizar en vez de salir de la aplicación cuando la ventana está cerrada. Cuando se activa esta opción, la aplicación sólo se cerrará después de seleccionar Salir en el menú.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Las opciones establecidas en este diálogo serán anuladas por la línea de comandos:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Abrir el archivo de configuración %1 en el directorio de trabajo.</translation>
</message>
@@ -1370,14 +1809,52 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">&amp;Red</translation>
</message>
<message>
+ <source>Prune &amp;block storage to</source>
+ <translation type="unfinished">Habilitar el modo prune para el almacenamiento de &amp;bloques a</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Para revertir esta configuración, se debe descargar de nuevo la cadena de bloques completa.</translation>
+ </message>
+ <message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">Tamaño máximo de la caché de la base de datos. Una caché más grande puede contribuir a una sincronización más rápida, después de lo cual el beneficio es menos pronunciado para la mayoría de los casos de uso. Disminuir el tamaño de la caché reducirá el uso de la memoria. La memoria mempool no utilizada se comparte para esta caché.</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Establezca el número de hilos de verificación de scripts. Los valores negativos corresponden al número de núcleos que se desea dejar libres al sistema.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = auto, &lt;0 = deja esta cantidad de núcleos libres)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Esto le permite a usted o a una herramienta de terceros comunicarse con el nodo a través de la línea de comandos y los comandos JSON-RPC.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Activar servidor R&amp;PC</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">Cartera</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Si se resta la comisión del importe por defecto o no.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Restar &amp;comisión del importe por defecto</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">experto</translation>
</message>
@@ -1394,6 +1871,28 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Gastar cambio sin confirmar</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Activar controles de &amp;PSBT</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Si se muestran los controles de PSBT.</translation>
+ </message>
+ <message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">Firmante externo (p. ej., billetera de hardware)</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;Ruta al script del firmante externo</translation>
+ </message>
+ <message>
+ <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished">Ruta completa a un script compatible con Bitcoin Core (p. ej., C:\Descargas\hwi.exe o /Usuarios/SuUsuario/Descargas/hwi.py). Advertencia: ¡El malware podría robarle sus monedas!</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 type="unfinished">Abre automáticamente el puerto del cliente Bitcoin en el router. Esto funciona solo cuando tu router es compatible con UPnP y está habilitado.</translation>
</message>
@@ -1402,6 +1901,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Direcciona el puerto usando &amp;UPnP</translation>
</message>
<message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
+ <translation type="unfinished">Abre automáticamente el puerto del cliente de Bitcoin en el router. Esto solo funciona cuando el router es compatible con NAT-PMP y está activo. El puerto externo podría ser aleatorio</translation>
+ </message>
+ <message>
+ <source>Map port using NA&amp;T-PMP</source>
+ <translation type="unfinished">Mapear el puerto usando NA&amp;T-PMP</translation>
+ </message>
+ <message>
<source>Accept connections from outside.</source>
<translation type="unfinished">Aceptar conexiones externas.</translation>
</message>
@@ -1435,8 +1942,15 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>&amp;Window</source>
- <translation type="unfinished">y windows
-</translation>
+ <translation type="unfinished">&amp;Ventana</translation>
+ </message>
+ <message>
+ <source>Show the icon in the system tray.</source>
+ <translation type="unfinished">Mostrar el ícono en la bandeja del sistema.</translation>
+ </message>
+ <message>
+ <source>&amp;Show tray icon</source>
+ <translation type="unfinished">&amp;Mostrar el ícono de la bandeja</translation>
</message>
<message>
<source>Show only a tray icon after minimizing the window.</source>
@@ -1471,14 +1985,47 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Elige la subdivisión por defecto para mostrar cantidaded en la interfaz cuando se envien monedas</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 type="unfinished">Las URL de terceros (por ejemplo, un explorador de bloques) que aparecen en la pestaña de transacciones como elementos del menú contextual. El hash de la transacción remplaza el valor %s en la URL. Varias URL se separan con una barra vertical (|).</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;URL de transacciones de terceros</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">Mostrar o no funcionalidad de Coin Control</translation>
</message>
<message>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
+ <translation type="unfinished">Conectarse a la red Bitcoin a través de un proxy SOCKS5 independiente para los servicios onion de Tor.</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
+ <translation type="unfinished">Usar un proxy SOCKS&amp;5 independiente para comunicarse con pares a través de los servicios onion de Tor:</translation>
+ </message>
+ <message>
+ <source>Monospaced font in the Overview tab:</source>
+ <translation type="unfinished">Fuente monoespaciada en la pestaña de vista general:</translation>
+ </message>
+ <message>
+ <source>embedded "%1"</source>
+ <translation type="unfinished">"%1" insertado</translation>
+ </message>
+ <message>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">"%1" con la coincidencia más aproximada</translation>
+ </message>
+ <message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Cancela</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Compilado sin soporte de firma externa (necesario para la firma externa)</translation>
+ </message>
+ <message>
<source>default</source>
<translation type="unfinished">predeterminado</translation>
</message>
@@ -1488,14 +2035,22 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirmar reestablecimiento de las opciones</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Es necesario reiniciar el cliente para activar los cambios.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Se realizará una copia de seguridad de la configuración actual en "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">El cliente se cerrará. Desea proceder?</translation>
</message>
<message>
@@ -1509,6 +2064,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">El archivo de configuración es utilizado para especificar opciones avanzadas del usuario, que invalidan los ajustes predeterminados. Adicionalmente, cualquier opción ingresada por la línea de comandos invalidará este archivo de configuración.</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">Continuar</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">Cancelar</translation>
+ </message>
+ <message>
<source>The configuration file could not be opened.</source>
<translation type="unfinished">El archivo de configuración no pudo ser abierto.</translation>
</message>
@@ -1522,6 +2085,13 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">No se puede leer la configuración "%1", %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -1589,9 +2159,13 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>Current total balance in watch-only addresses</source>
- <translation type="unfinished">Saldo total actual en direcciones de solo reloj</translation>
+ <translation type="unfinished">Saldo total actual en direcciones de solo observación</translation>
</message>
- </context>
+ <message>
+ <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
+ <translation type="unfinished">Modo de privacidad activado para la pestaña de vista general. Para mostrar los valores, anule la selección de Configuración-&gt;Ocultar valores.</translation>
+ </message>
+</context>
<context>
<name>PSBTOperationsDialog</name>
<message>
@@ -1599,22 +2173,127 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Dialogo</translation>
</message>
<message>
+ <source>Sign Tx</source>
+ <translation type="unfinished">Firmar transacción</translation>
+ </message>
+ <message>
+ <source>Broadcast Tx</source>
+ <translation type="unfinished">Transmitir transacción</translation>
+ </message>
+ <message>
+ <source>Copy to Clipboard</source>
+ <translation type="unfinished">Copiar al portapapeles</translation>
+ </message>
+ <message>
+ <source>Save…</source>
+ <translation type="unfinished">Guardar...</translation>
+ </message>
+ <message>
<source>Close</source>
<translation type="unfinished">Cerrar</translation>
</message>
<message>
+ <source>Failed to load transaction: %1</source>
+ <translation type="unfinished">Error al cargar la transacción: %1</translation>
+ </message>
+ <message>
+ <source>Failed to sign transaction: %1</source>
+ <translation type="unfinished">Error al firmar la transacción: %1</translation>
+ </message>
+ <message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">No se pueden firmar entradas mientras la billetera está bloqueada.</translation>
+ </message>
+ <message>
+ <source>Could not sign any more inputs.</source>
+ <translation type="unfinished">No se pudo firmar más entradas.</translation>
+ </message>
+ <message>
+ <source>Signed %1 inputs, but more signatures are still required.</source>
+ <translation type="unfinished">Se firmaron %1 entradas, pero aún se requieren más firmas.</translation>
+ </message>
+ <message>
+ <source>Signed transaction successfully. Transaction is ready to broadcast.</source>
+ <translation type="unfinished">La transacción se firmó correctamente y está lista para transmitirse.</translation>
+ </message>
+ <message>
+ <source>Unknown error processing transaction.</source>
+ <translation type="unfinished">Error desconocido al procesar la transacción.</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast successfully! Transaction ID: %1</source>
+ <translation type="unfinished">¡La transacción se transmitió correctamente! Identificador de transacción: %1</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast failed: %1</source>
+ <translation type="unfinished">Error al transmitir la transacción: %1</translation>
+ </message>
+ <message>
+ <source>PSBT copied to clipboard.</source>
+ <translation type="unfinished">PSBT copiada al portapapeles.</translation>
+ </message>
+ <message>
<source>Save Transaction Data</source>
<translation type="unfinished">Guardar datos de la transacción</translation>
</message>
<message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">Transacción parcialmente firmada (binario) </translation>
+ </message>
+ <message>
+ <source>PSBT saved to disk.</source>
+ <translation type="unfinished">PSBT guardada en en el disco.</translation>
+ </message>
+ <message>
+ <source> * Sends %1 to %2</source>
+ <translation type="unfinished">* Envía %1 a %2</translation>
+ </message>
+ <message>
+ <source>Unable to calculate transaction fee or total transaction amount.</source>
+ <translation type="unfinished">No se puede calcular la comisión o el importe total de la transacción.</translation>
+ </message>
+ <message>
+ <source>Pays transaction fee: </source>
+ <translation type="unfinished">Paga comisión de transacción:</translation>
+ </message>
+ <message>
<source>Total Amount</source>
- <translation type="unfinished">Monto total</translation>
+ <translation type="unfinished">Cantidad total</translation>
</message>
<message>
<source>or</source>
<translation type="unfinished">o</translation>
</message>
<message>
+ <source>Transaction has %1 unsigned inputs.</source>
+ <translation type="unfinished">La transacción tiene %1 entradas sin firmar.</translation>
+ </message>
+ <message>
+ <source>Transaction is missing some information about inputs.</source>
+ <translation type="unfinished">A la transacción le falta información sobre entradas.</translation>
+ </message>
+ <message>
+ <source>Transaction still needs signature(s).</source>
+ <translation type="unfinished">La transacción aún necesita firma(s).</translation>
+ </message>
+ <message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Pero no se cargó ninguna billetera).</translation>
+ </message>
+ <message>
+ <source>(But this wallet cannot sign transactions.)</source>
+ <translation type="unfinished">(Pero esta billetera no puede firmar transacciones).</translation>
+ </message>
+ <message>
+ <source>(But this wallet does not have the right keys.)</source>
+ <translation type="unfinished">(Pero esta billetera no tiene las claves adecuadas).</translation>
+ </message>
+ <message>
+ <source>Transaction is fully signed and ready for broadcast.</source>
+ <translation type="unfinished">La transacción se firmó completamente y está lista para transmitirse.</translation>
+ </message>
+ <message>
<source>Transaction status is unknown.</source>
<translation type="unfinished">El estado de la transacción es desconocido.</translation>
</message>
@@ -1634,6 +2313,18 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Manejo de URI</translation>
</message>
<message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation type="unfinished">"bitcoin://" no es un URI válido. Use "bitcoin:" en su lugar.</translation>
+ </message>
+ <message>
+ <source>Cannot process payment request because BIP70 is not supported.
+Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
+If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
+ <translation type="unfinished">No se puede procesar la solicitud de pago porque no existe compatibilidad con BIP70.
+Debido a los fallos de seguridad generalizados en BIP70, se recomienda encarecidamente ignorar las instrucciones del comerciante para cambiar de billetera.
+Si recibe este error, debe solicitar al comerciante que le proporcione un URI compatible con BIP21.</translation>
+ </message>
+ <message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<translation type="unfinished">¡URI no puede ser analizado! Esto puede deberse a una dirección de Bitcoin no válida o a parámetros de URI mal formados.</translation>
</message>
@@ -1645,6 +2336,16 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<context>
<name>PeerTableModel</name>
<message>
+ <source>Peer</source>
+ <extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
+ <translation type="unfinished">Par</translation>
+ </message>
+ <message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Duración</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Dirección</translation>
@@ -1688,18 +2389,35 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<context>
<name>QRImageWidget</name>
<message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Guardar imagen...</translation>
+ </message>
+ <message>
<source>&amp;Copy Image</source>
<translation type="unfinished">&amp;Copiar imagen</translation>
</message>
<message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation type="unfinished">El URI resultante es demasiado largo, así que trate de reducir el texto de la etiqueta o el mensaje.</translation>
+ </message>
+ <message>
<source>Error encoding URI into QR Code.</source>
<translation type="unfinished">Fallo al codificar URI en código QR.</translation>
</message>
<message>
+ <source>QR code support not available.</source>
+ <translation type="unfinished">La compatibilidad con el código QR no está disponible.</translation>
+ </message>
+ <message>
<source>Save QR Code</source>
<translation type="unfinished">Guardar código QR</translation>
</message>
- </context>
+ <message>
+ <source>PNG Image</source>
+ <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment>
+ <translation type="unfinished">Imagen PNG</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1711,10 +2429,18 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">&amp;Información</translation>
</message>
<message>
+ <source>To specify a non-default location of the data directory use the '%1' option.</source>
+ <translation type="unfinished">Para especificar una ubicación no predeterminada del directorio de datos, use la opción "%1".</translation>
+ </message>
+ <message>
<source>Blocksdir</source>
<translation type="unfinished">Bloques dir</translation>
</message>
<message>
+ <source>To specify a non-default location of the blocks directory use the '%1' option.</source>
+ <translation type="unfinished">Para especificar una ubicación no predeterminada del directorio de bloques, use la opción "%1".</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation type="unfinished">Tiempo de inicio</translation>
</message>
@@ -1732,7 +2458,7 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>Block chain</source>
- <translation type="unfinished">Bloquea cadena</translation>
+ <translation type="unfinished">Cadena de bloques</translation>
</message>
<message>
<source>Current number of transactions</source>
@@ -1788,6 +2514,48 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Bloques sincronizados</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Última transacción</translation>
+ </message>
+ <message>
+ <source>The mapped Autonomous System used for diversifying peer selection.</source>
+ <translation type="unfinished">El sistema autónomo asignado que se usó para diversificar la selección de pares.</translation>
+ </message>
+ <message>
+ <source>Mapped AS</source>
+ <translation type="unfinished">SA asignado</translation>
+ </message>
+ <message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Si retransmitimos las direcciones a este par.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Retransmisión de dirección</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">El número total de direcciones recibidas desde este par que se procesaron (excluye las direcciones omitidas debido a la limitación de volumen).</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">El número total de direcciones recibidas desde este par que se omitieron (no se procesaron) debido a la limitación de volumen.</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Direcciones procesadas</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Direcciones omitidas por limitación de volumen</translation>
+ </message>
+ <message>
<source>Node window</source>
<translation type="unfinished">Ventana del nodo</translation>
</message>
@@ -1808,14 +2576,55 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Permisos</translation>
</message>
<message>
+ <source>The direction and type of peer connection: %1</source>
+ <translation type="unfinished">La dirección y el tipo de conexión entre pares: %1</translation>
+ </message>
+ <message>
+ <source>Direction/Type</source>
+ <translation type="unfinished">Dirección/Tipo</translation>
+ </message>
+ <message>
+ <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
+ <translation type="unfinished">El protocolo de red mediante el cual está conectado este par: IPv4, IPv6, Onion, I2P o CJDNS.</translation>
+ </message>
+ <message>
<source>Services</source>
<translation type="unfinished">Servicios</translation>
</message>
<message>
+ <source>Whether the peer requested us to relay transactions.</source>
+ <translation type="unfinished">Si el par nos solicitó retransmitir transacciones.</translation>
+ </message>
+ <message>
+ <source>Wants Tx Relay</source>
+ <translation type="unfinished">Desea retransmisión de transacciones</translation>
+ </message>
+ <message>
+ <source>High bandwidth BIP152 compact block relay: %1</source>
+ <translation type="unfinished">Retransmisión de bloque compacto BIP152 en modo de banda ancha: %1</translation>
+ </message>
+ <message>
+ <source>High Bandwidth</source>
+ <translation type="unfinished">Banda ancha</translation>
+ </message>
+ <message>
<source>Connection Time</source>
<translation type="unfinished">Duración de la conexión</translation>
</message>
<message>
+ <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
+ <translation type="unfinished">Tiempo transcurrido desde que se recibió de este par un nuevo bloque que superó las comprobaciones de validez iniciales.</translation>
+ </message>
+ <message>
+ <source>Last Block</source>
+ <translation type="unfinished">Último bloque</translation>
+ </message>
+ <message>
+ <source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
+ <extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
+ <translation type="unfinished">Tiempo transcurrido desde que se recibió de este par una nueva transacción aceptada en nuestra mempool.</translation>
+ </message>
+ <message>
<source>Last Send</source>
<translation type="unfinished">Ultimo envío</translation>
</message>
@@ -1880,6 +2689,53 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Salida:</translation>
</message>
<message>
+ <source>Inbound: initiated by peer</source>
+ <extracomment>Explanatory text for an inbound peer connection.</extracomment>
+ <translation type="unfinished">Entrante: iniciada por el par</translation>
+ </message>
+ <message>
+ <source>Outbound Full Relay: default</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment>
+ <translation type="unfinished">Retransmisión completa saliente: predeterminada</translation>
+ </message>
+ <message>
+ <source>Outbound Block Relay: does not relay transactions or addresses</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Retransmisión de bloque saliente: no retransmite transacciones o direcciones</translation>
+ </message>
+ <message>
+ <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
+ <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment>
+ <translation type="unfinished">Manual saliente: agregada usando las opciones de configuración %1 o %2/%3 de RPC</translation>
+ </message>
+ <message>
+ <source>Outbound Feeler: short-lived, for testing addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Feeler saliente: de corta duración, para probar direcciones</translation>
+ </message>
+ <message>
+ <source>Outbound Address Fetch: short-lived, for soliciting addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment>
+ <translation type="unfinished">Recuperación de dirección Saliente: de corta duración, para solicitar direcciones</translation>
+ </message>
+ <message>
+ <source>we selected the peer for high bandwidth relay</source>
+ <translation type="unfinished">Seleccionamos el par para la retransmisión de banda ancha</translation>
+ </message>
+ <message>
+ <source>the peer selected us for high bandwidth relay</source>
+ <translation type="unfinished">El par nos seleccionó para la retransmisión de banda ancha</translation>
+ </message>
+ <message>
+ <source>no high bandwidth relay selected</source>
+ <translation type="unfinished">No se seleccionó la retransmisión de banda ancha</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Copiar dirección</translation>
+ </message>
+ <message>
<source>&amp;Disconnect</source>
<translation type="unfinished">&amp;Desconectar</translation>
</message>
@@ -1888,6 +2744,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">1 &amp;hora</translation>
</message>
<message>
+ <source>1 d&amp;ay</source>
+ <translation type="unfinished">1 &amp;día</translation>
+ </message>
+ <message>
<source>1 &amp;week</source>
<translation type="unfinished">1 semana</translation>
</message>
@@ -1896,6 +2756,11 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">1 año</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Copiar IP/Máscara de red</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Desbloquear</translation>
</message>
@@ -1908,6 +2773,36 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Ejecutando comando con cualquier cartera</translation>
</message>
<message>
+ <source>Executing command using "%1" wallet</source>
+ <translation type="unfinished">Ejecutar comando usando la billetera "%1"</translation>
+ </message>
+ <message>
+ <source>Welcome to the %1 RPC console.
+Use up and down arrows to navigate history, and %2 to clear screen.
+Use %3 and %4 to increase or decrease the font size.
+Type %5 for an overview of available commands.
+For more information on using this console, type %6.
+
+%7WARNING: 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.%8</source>
+ <extracomment>RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</extracomment>
+ <translation type="unfinished">Te damos la bienvenida a la consola RPC de %1.
+Utiliza las flechas hacia arriba y abajo para navegar por el historial, y %2 para borrar la pantalla.
+Utiliza %3 y %4 para aumentar o disminuir el tamaño de la fuente.
+Escribe %5 para ver los comandos disponibles.
+Para obtener más información sobre cómo usar esta consola, escribe %6.
+
+%7 ADVERTENCIA: Los estafadores han estado activos diciendo a los usuarios que escriban comandos aquí, robando el contenido de sus monederos. No uses esta consola sin entender completamente las ramificaciones de un comando.%8</translation>
+ </message>
+ <message>
+ <source>Executing…</source>
+ <extracomment>A console message indicating an entered command is currently being executed.</extracomment>
+ <translation type="unfinished">Ejecutando...</translation>
+ </message>
+ <message>
+ <source>(peer: %1)</source>
+ <translation type="unfinished">(par: %1)</translation>
+ </message>
+ <message>
<source>Yes</source>
<translation type="unfinished">Si</translation>
</message>
@@ -1924,6 +2819,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Prohibir para</translation>
</message>
<message>
+ <source>Never</source>
+ <translation type="unfinished">Nunca</translation>
+ </message>
+ <message>
<source>Unknown</source>
<translation type="unfinished">Desconocido</translation>
</message>
@@ -1959,6 +2858,18 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Monto opcional a solicitar. Deja este campo vacío o en cero si no quieres definir un monto específico.</translation>
</message>
<message>
+ <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
+ <translation type="unfinished">Una etiqueta opcional para asociar con la nueva dirección de recepción (utilizada por ti para identificar una factura). También se adjunta a la solicitud de pago.</translation>
+ </message>
+ <message>
+ <source>An optional message that is attached to the payment request and may be displayed to the sender.</source>
+ <translation type="unfinished">Un mensaje opcional que se adjunta a la solicitud de pago y que puede mostrarse al remitente.</translation>
+ </message>
+ <message>
+ <source>&amp;Create new receiving address</source>
+ <translation type="unfinished">&amp;Crear una nueva dirección de recepción</translation>
+ </message>
+ <message>
<source>Clear all fields of the form.</source>
<translation type="unfinished">Limpiar todos los campos del formulario.</translation>
</message>
@@ -1991,13 +2902,37 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Copiar &amp;URI</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Copiar dirección</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Copiar &amp;etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy &amp;message</source>
+ <translation type="unfinished">Copiar &amp;mensaje</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Copiar &amp;cantidad</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">No se pudo desbloquear la billetera.</translation>
</message>
- </context>
+ <message>
+ <source>Could not generate new %1 address</source>
+ <translation type="unfinished">No se pudo generar nueva dirección %1</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>Request payment to …</source>
+ <translation type="unfinished">Solicitar pago a...</translation>
+ </message>
+ <message>
<source>Address:</source>
<translation type="unfinished">Dirección:</translation>
</message>
@@ -2026,6 +2961,18 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">&amp;Copia dirección</translation>
</message>
<message>
+ <source>&amp;Verify</source>
+ <translation type="unfinished">&amp;Verificar</translation>
+ </message>
+ <message>
+ <source>Verify this address on e.g. a hardware wallet screen</source>
+ <translation type="unfinished">Verifica esta dirección, por ejemplo, en la pantalla de una billetera de hardware</translation>
+ </message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Guardar imagen...</translation>
+ </message>
+ <message>
<source>Payment information</source>
<translation type="unfinished">Información del pago</translation>
</message>
@@ -2105,12 +3052,20 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Cambio:</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 type="unfinished">Si se activa, pero la dirección de cambio está vacía o es inválida, el cambio se enviará a una dirección generada recientemente.</translation>
+ </message>
+ <message>
<source>Custom change address</source>
<translation type="unfinished">Dirección de cambio personalizada</translation>
</message>
<message>
<source>Transaction Fee:</source>
- <translation type="unfinished">Comisión transacción:</translation>
+ <translation type="unfinished">Comisión de transacción:</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 type="unfinished">Si usas la opción "fallbackfee", la transacción puede tardar varias horas o días en confirmarse (o nunca hacerlo). Considera elegir la comisión de forma manual o espera hasta que hayas validado la cadena completa.</translation>
</message>
<message>
<source>Warning: Fee estimation is currently not possible.</source>
@@ -2145,22 +3100,62 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Limpiar todos los campos del formulario.</translation>
</message>
<message>
+ <source>Inputs…</source>
+ <translation type="unfinished">Entradas...</translation>
+ </message>
+ <message>
<source>Dust:</source>
<translation type="unfinished">Polvo:</translation>
</message>
<message>
+ <source>Choose…</source>
+ <translation type="unfinished">Elegir...</translation>
+ </message>
+ <message>
<source>Hide transaction fee settings</source>
- <translation type="unfinished">Esconder ajustes de la tarifa de transacción</translation>
+ <translation type="unfinished">Ocultar configuración de la comisión de transacción</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 rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation type="unfinished">Especifica una comisión personalizada por kB (1000 bytes) del tamaño virtual de la transacción.
+
+Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por kvB" para una transacción de 500 bytes virtuales (la mitad de 1 kvB) produciría, en última instancia, una comisión de solo 50 satoshis.</translation>
+ </message>
+ <message>
+ <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">Cuando hay menos volumen de transacciones que espacio en los bloques, los mineros y los nodos de retransmisión pueden aplicar una comisión mínima. Está bien pagar solo esta comisión mínima, pero ten en cuenta que esto puede ocasionar que una transacción nunca se confirme una vez que haya más demanda de transacciones de Bitcoin de la que puede procesar la red.</translation>
+ </message>
+ <message>
+ <source>A too low fee might result in a never confirming transaction (read the tooltip)</source>
+ <translation type="unfinished">Si la comisión es demasiado baja, es posible que la transacción nunca se confirme (leer la información sobre herramientas).</translation>
+ </message>
+ <message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source>
+ <translation type="unfinished">(La comisión inteligente no se ha inicializado todavía. Esto tarda normalmente algunos bloques…)</translation>
</message>
<message>
<source>Confirmation time target:</source>
<translation type="unfinished">Objetivo de tiempo de confirmación</translation>
</message>
<message>
+ <source>Enable Replace-By-Fee</source>
+ <translation type="unfinished">Activar "Reemplazar-por-comisión"</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 type="unfinished">Con la función "Reemplazar-por-comisión" (BIP-125), puedes aumentar la comisión de una transacción después de enviarla. Sin esta, es posible que se recomiende una comisión más alta para compensar el mayor riesgo de retraso de la transacción.</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation type="unfinished">&amp;Borra todos</translation>
</message>
<message>
+ <source>Balance:</source>
+ <translation type="unfinished">Saldo:</translation>
+ </message>
+ <message>
<source>Confirm the send action</source>
<translation type="unfinished">Confirma el envio</translation>
</message>
@@ -2201,22 +3196,98 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">%1 (%2 bloques)</translation>
</message>
<message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">Firmar en el dispositivo</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">Conecta primero tu billetera de hardware.</translation>
+ </message>
+ <message>
+ <source>Set external signer script path in Options -&gt; Wallet</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Establecer la ruta al script del firmante externo en "Opciones -&gt; Billetera"</translation>
+ </message>
+ <message>
+ <source>Cr&amp;eate Unsigned</source>
+ <translation type="unfinished">Cr&amp;ear transacción sin firmar</translation>
+ </message>
+ <message>
+ <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <translation type="unfinished">Crea una transacción de Bitcoin parcialmente firmada (PSBT) para usarla, por ejemplo, con una billetera %1 sin conexión o una billetera de hardware compatible con PSBT.</translation>
+ </message>
+ <message>
<source> from wallet '%1'</source>
<translation type="unfinished">desde la billetera '%1'</translation>
</message>
<message>
+ <source>%1 to '%2'</source>
+ <translation type="unfinished">%1 a '%2'</translation>
+ </message>
+ <message>
<source>%1 to %2</source>
<translation type="unfinished">%1 a %2</translation>
</message>
<message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">Para consultar la lista de destinatarios, haz clic en "Mostrar detalles..."</translation>
+ </message>
+ <message>
+ <source>Sign failed</source>
+ <translation type="unfinished">Error de firma</translation>
+ </message>
+ <message>
+ <source>External signer not found</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">No se encontró el dispositivo firmante externo</translation>
+ </message>
+ <message>
+ <source>External signer failure</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Error de firmante externo</translation>
+ </message>
+ <message>
<source>Save Transaction Data</source>
<translation type="unfinished">Guardar datos de la transacción</translation>
</message>
<message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">Transacción parcialmente firmada (binario) </translation>
+ </message>
+ <message>
+ <source>PSBT saved</source>
+ <translation type="unfinished">PSBT guardada</translation>
+ </message>
+ <message>
+ <source>External balance:</source>
+ <translation type="unfinished">Saldo externo:</translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">o</translation>
</message>
<message>
+ <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
+ <translation type="unfinished">Puedes aumentar la comisión después (indica "Reemplazar-por-comisión", BIP-125).</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment>
+ <translation type="unfinished">Revisa por favor la propuesta de transacción. Esto producirá una transacción de Bitcoin parcialmente firmada (PSBT) que puedes guardar o copiar y, luego, firmar; por ejemplo, una billetera %1 sin conexión o una billetera de hardware compatible con PSBT.</translation>
+ </message>
+ <message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">¿Quieres crear esta transacción?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Revisa por favor la transacción. Puedes crear y enviar esta transacción de Bitcoin parcialmente firmada (PSBT), que además puedes guardar o copiar y, luego, firmar; por ejemplo, una billetera %1 sin conexión o una billetera de hardware compatible con PSBT.</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Por favor, revise su transacción.</translation>
@@ -2226,14 +3297,22 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Comisión de transacción</translation>
</message>
<message>
+ <source>Not signalling Replace-By-Fee, BIP-125.</source>
+ <translation type="unfinished">No indica remplazar-por-comisión, BIP-125.</translation>
+ </message>
+ <message>
<source>Total Amount</source>
- <translation type="unfinished">Monto total</translation>
+ <translation type="unfinished">Cantidad total</translation>
</message>
<message>
<source>Confirm send coins</source>
<translation type="unfinished">Confirmar el envió de monedas</translation>
</message>
<message>
+ <source>Watch-only balance:</source>
+ <translation type="unfinished">Saldo solo de observación:</translation>
+ </message>
+ <message>
<source>The recipient address is not valid. Please recheck.</source>
<translation type="unfinished">La dirección de envío no es válida. Por favor revisala.</translation>
</message>
@@ -2261,15 +3340,11 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Una comisión mayor que %1 se considera como una comisión absurda-mente alta.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Solicitud de pago expirada</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Se estima que empiece a confirmarse dentro de %n bloque.</numerusform>
+ <numerusform>Se estima que empiece a confirmarse dentro de %n bloques.</numerusform>
</translation>
</message>
<message>
@@ -2324,6 +3399,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Quitar esta entrada</translation>
</message>
<message>
+ <source>The amount to send in the selected unit</source>
+ <translation type="unfinished">El importe que se enviará en la unidad seleccionada</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 type="unfinished">La comisión se deducirá del monto del envío. El destinatario recibirá menos bitcoins que los que ingreses en el campo de cantidad. Si se seleccionan varios destinatarios, la comisión se divide por igual.</translation>
+ </message>
+ <message>
<source>S&amp;ubtract fee from amount</source>
<translation type="unfinished">Restar comisiones del monto.</translation>
</message>
@@ -2336,29 +3419,25 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Mensaje:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Esta es una petición de pago no autentificada.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Esta es una petición de pago autentificada.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Introduce una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas</translation>
</message>
<message>
- <source>Pay To:</source>
- <translation type="unfinished">Pagar a:</translation>
+ <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 type="unfinished">Un mensaje que se adjuntó al Bitcoin: URI que se almacenará con la transacción a modo de referencia. Nota: Este mensaje no se enviará por la red de Bitcoin.</translation>
</message>
- </context>
+</context>
<context>
<name>SendConfirmationDialog</name>
<message>
<source>Send</source>
<translation type="unfinished">Enviar</translation>
</message>
- </context>
+ <message>
+ <source>Create Unsigned</source>
+ <translation type="unfinished">Crear sin firmar</translation>
+ </message>
+</context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
@@ -2370,6 +3449,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">&amp;Firmar Mensaje</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 type="unfinished">Puedes firmar mensajes o acuerdos con tus direcciones para demostrar que puedes recibir los bitcoins que se envíen a ellas. Ten cuidado de no firmar cosas confusas o al azar, ya que los ataques de phishing pueden tratar de engañarte para que les envíes la firma con tu identidad. Firma solo declaraciones totalmente detalladas con las que estés de acuerdo.</translation>
+ </message>
+ <message>
<source>The Bitcoin address to sign the message with</source>
<translation type="unfinished">Dirección Bitcoin con la que firmar el mensaje</translation>
</message>
@@ -2414,10 +3497,22 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">&amp;Firmar Mensaje</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 type="unfinished">Ingresa la dirección del destinatario, el mensaje (recuerda copiar los saltos de línea, espacios, tabulaciones, etc. con exactitud) y la firma a continuación para verificar el mensaje. Ten cuidado de no leer en la firma más de lo que está en el mensaje firmado en sí, para evitar ser víctima de un engaño por ataque de intermediario. Ten en cuenta que esto solo demuestra que el firmante recibe con la dirección; no puede demostrar la condición de remitente de ninguna transacción.</translation>
+ </message>
+ <message>
<source>The Bitcoin address the message was signed with</source>
<translation type="unfinished">La dirección Bitcoin con la que se firmó el mensaje</translation>
</message>
<message>
+ <source>The signed message to verify</source>
+ <translation type="unfinished">El mensaje firmado para verificar</translation>
+ </message>
+ <message>
+ <source>The signature given when the message was signed</source>
+ <translation type="unfinished">La firma que se dio cuando el mensaje se firmó</translation>
+ </message>
+ <message>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
<translation type="unfinished">Verifica el mensaje para asegurar que fue firmado con la dirección de Bitcoin especificada.</translation>
</message>
@@ -2487,33 +3582,46 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
</context>
<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished">(presiona q para apagar y seguir luego)</translation>
+ </message>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">presiona q para apagar </translation>
+ </message>
+</context>
+<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">Hay un conflicto con la traducción de las confirmaciones %1</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/no confirmado, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">en el equipo de memoria</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/sin confirmar, en el pool de memoria</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">no en el equipo de memoria</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/sin confirmar, no está en el pool de memoria</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">abandonado</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/no confirmado</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">confirmaciones %1</translation>
</message>
<message>
@@ -2563,8 +3671,8 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>madura en %n bloque más</numerusform>
+ <numerusform>madura en %n bloques más</numerusform>
</translation>
</message>
<message>
@@ -2601,21 +3709,33 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
</message>
<message>
<source>Transaction ID</source>
- <translation type="unfinished">Identificador de transacción (ID)</translation>
+ <translation type="unfinished">Identificador de transacción</translation>
</message>
<message>
<source>Transaction total size</source>
<translation type="unfinished">Tamaño total de transacción</translation>
</message>
<message>
+ <source>Transaction virtual size</source>
+ <translation type="unfinished">Tamaño virtual de transacción</translation>
+ </message>
+ <message>
<source>Output index</source>
<translation type="unfinished">Indice de salida</translation>
</message>
<message>
+ <source> (Certificate was not verified)</source>
+ <translation type="unfinished">(No se verificó el certificado)</translation>
+ </message>
+ <message>
<source>Merchant</source>
<translation type="unfinished">Vendedor</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 type="unfinished">Las monedas generadas deben madurar %1 bloques antes de que se puedan gastar. Cuando generaste este bloque, se transmitió a la red para agregarlo a la cadena de bloques. Si no logra entrar a la cadena, su estado cambiará a "no aceptado" y no se podrá gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque a pocos segundos del tuyo.</translation>
+ </message>
+ <message>
<source>Debug information</source>
<translation type="unfinished">Información de depuración</translation>
</message>
@@ -2734,6 +3854,14 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Tipo de transacción.</translation>
</message>
<message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation type="unfinished">Si una dirección de solo observación está involucrada en esta transacción o no.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation type="unfinished">Intención o propósito de la transacción definidos por el usuario.</translation>
+ </message>
+ <message>
<source>Amount removed from or added to balance.</source>
<translation type="unfinished">Cantidad restada o añadida al balance</translation>
</message>
@@ -2785,10 +3913,63 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Otra</translation>
</message>
<message>
+ <source>Enter address, transaction id, or label to search</source>
+ <translation type="unfinished">Ingresa la dirección, el identificador de transacción o la etiqueta para buscar</translation>
+ </message>
+ <message>
<source>Min amount</source>
<translation type="unfinished">Cantidad mínima</translation>
</message>
<message>
+ <source>Range…</source>
+ <translation type="unfinished">Rango...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Copiar dirección</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Copiar &amp;etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Copiar &amp;cantidad</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">Copiar &amp;ID de transacción</translation>
+ </message>
+ <message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">Copiar transacción &amp;raw</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">Copiar &amp;detalles completos de la transacción</translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">&amp;Mostrar detalles de la transacción</translation>
+ </message>
+ <message>
+ <source>Increase transaction &amp;fee</source>
+ <translation type="unfinished">Aumentar &amp;comisión de transacción</translation>
+ </message>
+ <message>
+ <source>A&amp;bandon transaction</source>
+ <translation type="unfinished">A&amp;bandonar transacción</translation>
+ </message>
+ <message>
+ <source>&amp;Edit address label</source>
+ <translation type="unfinished">&amp;Editar etiqueta de dirección</translation>
+ </message>
+ <message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Mostrar en %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Exportar historial de transacciones</translation>
</message>
@@ -2826,6 +4007,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Exportación fallida</translation>
</message>
<message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation type="unfinished">Ocurrió un error al intentar guardar el historial de transacciones en %1.</translation>
+ </message>
+ <message>
<source>Exporting Successful</source>
<translation type="unfinished">Exportación exitosa</translation>
</message>
@@ -2845,14 +4030,38 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<context>
<name>WalletFrame</name>
<message>
+ <source>No wallet has been loaded.
+Go to File &gt; Open Wallet to load a wallet.
+- OR -</source>
+ <translation type="unfinished">No se cargó ninguna billetera.
+Ir a Archivo &gt; Abrir billetera para cargar una.
+- OR -</translation>
+ </message>
+ <message>
<source>Create a new wallet</source>
<translation type="unfinished">Crear una nueva billetera</translation>
</message>
<message>
+ <source>Unable to decode PSBT from clipboard (invalid base64)</source>
+ <translation type="unfinished">No se puede decodificar PSBT desde el portapapeles (Base64 inválido)</translation>
+ </message>
+ <message>
<source>Load Transaction Data</source>
<translation type="unfinished">Cargar datos de la transacción</translation>
</message>
- </context>
+ <message>
+ <source>Partially Signed Transaction (*.psbt)</source>
+ <translation type="unfinished">Transacción firmada parcialmente (*.psbt)</translation>
+ </message>
+ <message>
+ <source>PSBT file must be smaller than 100 MiB</source>
+ <translation type="unfinished">El archivo PSBT debe ser más pequeño de 100 MiB</translation>
+ </message>
+ <message>
+ <source>Unable to decode PSBT</source>
+ <translation type="unfinished">No es posible decodificar PSBT</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
<message>
@@ -2885,10 +4094,22 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Nueva comisión:</translation>
</message>
<message>
+ <source>Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
+ <translation type="unfinished">Advertencia: Esta acción puede pagar la comisión adicional al reducir las salidas de cambio o agregar entradas, cuando sea necesario. Asimismo, puede agregar una nueva salida de cambio si aún no existe una. Estos cambios pueden filtrar potencialmente información privada.</translation>
+ </message>
+ <message>
<source>Confirm fee bump</source>
<translation type="unfinished">Confirmar incremento de comisión</translation>
</message>
<message>
+ <source>Can't draft transaction.</source>
+ <translation type="unfinished">No se puede crear un borrador de la transacción.</translation>
+ </message>
+ <message>
+ <source>PSBT copied</source>
+ <translation type="unfinished">PSBT copiada</translation>
+ </message>
+ <message>
<source>Can't sign transaction.</source>
<translation type="unfinished">No se ha podido firmar la transacción.</translation>
</message>
@@ -2897,6 +4118,10 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">No se pudo confirmar la transacción</translation>
</message>
<message>
+ <source>Can't display address</source>
+ <translation type="unfinished">No se puede mostrar la dirección</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">billetera predeterminada</translation>
</message>
@@ -2916,6 +4141,11 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<translation type="unfinished">Respaldar monedero</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Datos de la billetera</translation>
+ </message>
+ <message>
<source>Backup Failed</source>
<translation type="unfinished">Ha fallado el respaldo</translation>
</message>
@@ -2931,5 +4161,9 @@ Firmar solo es posible con direcciones del tipo 'Legacy'.</translation>
<source>The wallet data was successfully saved to %1.</source>
<translation type="unfinished">Los datos del monedero se han guardado con éxito en %1.</translation>
</message>
- </context>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">Cancelar</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts
index b46a80e380..8f1af68541 100644
--- a/src/qt/locale/bitcoin_es_DO.ts
+++ b/src/qt/locale/bitcoin_es_DO.ts
@@ -70,6 +70,11 @@
<translation type="unfinished">Estas son tus direcciones Bitcoin para realizar pagos. Verifica siempre el monto y la dirección de recepción antes de enviar monedas. </translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Estas son tus direcciones de Bitcoin para recibir pagos. Utilice el botón 'Crear nueva dirección de recepción' en la pestaña Recibir para crear nuevas direcciones. La firma solo es posible con direcciones del tipo 'legacy'</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">Copiar dirección</translation>
</message>
@@ -86,6 +91,11 @@
<translation type="unfinished">Exportar lista de direcciones</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Archivo separado por comas</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">Tuvimos un problema al guardar la dirección en la lista %1. Intenta de Nuevo.</translation>
@@ -129,6 +139,10 @@
<translation type="unfinished">Repetir nueva frase de contraseña</translation>
</message>
<message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">Mostrar frase de contraseña</translation>
+ </message>
+ <message>
<source>Encrypt wallet</source>
<translation type="unfinished">Cifrar monedero</translation>
</message>
@@ -162,6 +176,30 @@
<translation type="unfinished">Monedero cifrado</translation>
</message>
<message>
+ <source>Enter the new passphrase for 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 type="unfinished">Ingrese la nueva frase de contraseña para la billetera&lt;br/&gt;. Utilice una frase de cont&lt;b&gt;raseñade diez o más caracteres&lt;/b&gt; aleatorios o och&lt;b&gt;o o más palab&lt;/b&gt;ras.</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase for the wallet.</source>
+ <translation type="unfinished">Ingrese la frase de contraseña antigua y la nueva frase de contraseña para la billetera</translation>
+ </message>
+ <message>
+ <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation type="unfinished">Recuerda que cifrar tu billetera no puede proteger completamente tus bitcoins de ser robados por malware que infecte tu computadora.</translation>
+ </message>
+ <message>
+ <source>Wallet to be encrypted</source>
+ <translation type="unfinished">Billetera para ser cifrada</translation>
+ </message>
+ <message>
+ <source>Your wallet is about to be encrypted. </source>
+ <translation type="unfinished">Tu monedero va a ser cifrado</translation>
+ </message>
+ <message>
+ <source>Your wallet is now encrypted. </source>
+ <translation type="unfinished">Tu monedero está ahora cifrado</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 type="unfinished">IMPORTANTE: Cualquier copia de seguridad que haya realizado previamente de su archivo de monedero debe reemplazarse con el nuevo archivo de monedero cifrado. Por razones de seguridad, las copias de seguridad previas del archivo de monedero no cifradas serán inservibles en cuanto comience a usar el nuevo monedero cifrado.</translation>
</message>
@@ -195,6 +233,24 @@
</message>
</context>
<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation type="unfinished">IP/Máscara de red</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation type="unfinished">Prohibido hasta</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">Error interno</translation>
+ </message>
+ </context>
+<context>
<name>QObject</name>
<message>
<source>Error: Specified data directory "%1" does not exist.</source>
@@ -385,6 +441,14 @@
<translation type="unfinished">Mostrar información acerca de Qt</translation>
</message>
<message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Crear monedero nuevo</translation>
+ </message>
+ <message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">Minimizar</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation type="unfinished">Enviar monedas a una dirección Bitcoin</translation>
</message>
@@ -405,6 +469,10 @@
<translation type="unfinished">&amp;Recibir</translation>
</message>
<message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;Cifrar monedero</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">Encriptar las llaves privadas que pertenecen a tu billetera</translation>
</message>
@@ -699,6 +767,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -861,10 +950,12 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirme el restablecimiento de las opciones</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Reinicio del cliente para activar cambios.</translation>
</message>
<message>
@@ -1342,10 +1433,6 @@
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Introduce una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Paga a:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -1466,10 +1553,12 @@
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/no confirmado</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 confirmaciones</translation>
</message>
<message>
@@ -1709,6 +1798,11 @@
<translation type="unfinished">Exportar historial de transacciones</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Archivo separado por comas</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">Confirmado</translation>
</message>
@@ -1754,6 +1848,13 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Crear monedero nuevo</translation>
+ </message>
+ </context>
+<context>
<name>WalletModel</name>
<message>
<source>Send Coins</source>
diff --git a/src/qt/locale/bitcoin_es_VE.ts b/src/qt/locale/bitcoin_es_VE.ts
index bf9e557a9f..8cb4efe6bf 100644
--- a/src/qt/locale/bitcoin_es_VE.ts
+++ b/src/qt/locale/bitcoin_es_VE.ts
@@ -70,6 +70,12 @@
<translation type="unfinished">Estas son sus direcciones Bitcoin para enviar pagos. Compruebe siempre la cantidad y la dirección de recibo antes de transferir monedas.</translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Lista de tus direcciones de Bitcoin para recibir pagos. Para la creacion de una nueva direccion seleccione en la pestana "recibir" la opcion "Crear nueva direccion"
+Registrarse solo es posible utilizando una direccion tipo "Legal"</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">Copiar dirección</translation>
</message>
@@ -749,6 +755,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -915,10 +942,12 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirme el restablecimiento de las opciones</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Reinicio del cliente para activar cambios.</translation>
</message>
<message>
@@ -1294,10 +1323,6 @@
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Introduce una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Paga a:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts
index beba4e31f9..8cbd5358db 100644
--- a/src/qt/locale/bitcoin_et.ts
+++ b/src/qt/locale/bitcoin_et.ts
@@ -70,6 +70,11 @@
<translation type="unfinished">Need on sinu Bitcoin aadressid maksete saatmiseks. Ennem müntide saatmist kontrolli alati summat ja makse saaja aadressi.</translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Need on sinu Bitcoin aadressid makse vastuvõtuks.Kasuta ‘Loo uus vastuvõttu aadress’ nuppu vastuvõtmise vahekaardis, et luua uus aadress. Allkirjastamine on võimalik ainult 'pärand' tüüpi aadressidega.</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">&amp;Kopeeri Aadress</translation>
</message>
@@ -457,10 +462,22 @@
<translation type="unfinished">&amp;Valikud</translation>
</message>
<message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;Krüpteeri Rahakott...</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">Krüpteeri oma rahakoti privaatvõtmed</translation>
</message>
<message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;Tagavara Rahakott...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;Muuda Salasõna...</translation>
+ </message>
+ <message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
<translation type="unfinished">Omandi tõestamiseks allkirjasta sõnumid oma Bitcoini aadressiga</translation>
</message>
@@ -469,6 +486,14 @@
<translation type="unfinished">Kinnita sõnumid kindlustamaks et need allkirjastati määratud Bitcoini aadressiga</translation>
</message>
<message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">Sulge Rahakott...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">Loo Rahakott...</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation type="unfinished">&amp;Fail</translation>
</message>
@@ -485,6 +510,10 @@
<translation type="unfinished">Vahelehe tööriistariba</translation>
</message>
<message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Sünkroniseerin võrguga...</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">Loo maksepäring (genereerib QR koodid ja bitcoini: URId)</translation>
</message>
@@ -528,6 +557,10 @@
<translation type="unfinished">Ajakohane</translation>
</message>
<message>
+ <source>Open Wallet</source>
+ <translation type="unfinished">Ava Rahakott</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Aken</translation>
</message>
@@ -702,6 +735,14 @@
</message>
</context>
<context>
+ <name>OpenWalletActivity</name>
+ <message>
+ <source>Open Wallet</source>
+ <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
+ <translation type="unfinished">Ava Rahakott</translation>
+ </message>
+ </context>
+<context>
<name>CreateWalletDialog</name>
<message>
<source>Wallet</source>
@@ -757,6 +798,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -906,6 +968,7 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Kinnita valikute algseadistamine</translation>
</message>
<message>
@@ -1370,10 +1433,6 @@
<source>The total exceeds your balance when the %1 transaction fee is included.</source>
<translation type="unfinished">Summa koos tehingu tasuga %1 ületab sinu jääki.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Maksepäring aegunud.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -1420,10 +1479,6 @@
<source>Message:</source>
<translation type="unfinished">Sõnum:</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Maksa :</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -1552,10 +1607,12 @@
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/kinnitamata</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 kinnitust</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_eu.ts b/src/qt/locale/bitcoin_eu.ts
index b9bd7cd38a..c215936b0e 100644
--- a/src/qt/locale/bitcoin_eu.ts
+++ b/src/qt/locale/bitcoin_eu.ts
@@ -70,6 +70,12 @@
<translation type="unfinished">Hauek dira zuk dirua jaso dezaketen Bitcoin helbideak. Egiaztatu beti diru-kopurua eta dirua jasoko duen helbidea zuzen egon daitezen, txanponak bidali baino lehen.</translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Hauek dira ordainketak jasotzeko zure Bitcoin helbideak. Jaso taulako 'Jasotzeko helbide berri bat sortu' botoia erabili helbide berri bat sortzeko.
+Sinatzea 'legacy' motako helbideekin soilik da posible</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">&amp;Helbidea kopiatu</translation>
</message>
@@ -86,6 +92,11 @@
<translation type="unfinished">Helbide lista esportatu</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Komaz bereizitako fitxategia</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">Akats bat egon da helbide lista %1-ean gordetzen sahiatzean. Mesedez, saiatu berriro.</translation>
@@ -233,6 +244,17 @@
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">Ranaway exception</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">Barne errorea</translation>
+ </message>
+ </context>
+<context>
<name>QObject</name>
<message>
<source>Error: %1</source>
@@ -246,6 +268,18 @@
<source>Amount</source>
<translation type="unfinished">Kopurua</translation>
</message>
+ <message>
+ <source>Internal</source>
+ <translation type="unfinished">Barnekoa</translation>
+ </message>
+ <message>
+ <source>%1 d</source>
+ <translation type="unfinished">%1 e</translation>
+ </message>
+ <message>
+ <source>%1 h</source>
+ <translation type="unfinished">%1 o</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
@@ -295,6 +329,70 @@
<source>Done loading</source>
<translation type="unfinished">Zamaketa amaitua</translation>
</message>
+ <message>
+ <source>Importing…</source>
+ <translation type="unfinished">Inportatzen...</translation>
+ </message>
+ <message>
+ <source>Loading wallet…</source>
+ <translation type="unfinished">Diruzorroa kargatzen...</translation>
+ </message>
+ <message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Zenbatekoa falta da</translation>
+ </message>
+ <message>
+ <source>No addresses available</source>
+ <translation type="unfinished">Ez dago helbiderik eskuragarri</translation>
+ </message>
+ <message>
+ <source>Replaying blocks…</source>
+ <translation type="unfinished">Blokeak errepikatzen...</translation>
+ </message>
+ <message>
+ <source>Rescanning…</source>
+ <translation type="unfinished">Bereskaneatzen...</translation>
+ </message>
+ <message>
+ <source>Starting network threads…</source>
+ <translation type="unfinished">Sareko hariak abiarazten...</translation>
+ </message>
+ <message>
+ <source>The source code is available from %s.</source>
+ <translation type="unfinished">Iturri kodea %s-tik dago eskuragarri.</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation type="unfinished">Transakzio kantitatea txikiegia da kuota ordaintzeko.</translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation type="unfinished">Hau software esperimentala da</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation type="unfinished">transakzio kopurua txikiegia</translation>
+ </message>
+ <message>
+ <source>Transaction too large</source>
+ <translation type="unfinished">Transakzio luzeegia</translation>
+ </message>
+ <message>
+ <source>Unable to generate initial keys</source>
+ <translation type="unfinished">hasierako giltzak sortzeko ezgai</translation>
+ </message>
+ <message>
+ <source>Unable to generate keys</source>
+ <translation type="unfinished">Giltzak sortzeko ezgai</translation>
+ </message>
+ <message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">Blokeak egiaztatzen...</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)…</source>
+ <translation type="unfinished">Diruzorroak egiaztatzen...</translation>
+ </message>
</context>
<context>
<name>BitcoinGUI</name>
@@ -347,6 +445,10 @@
<translation type="unfinished">Diruzorro berri bat sortu</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimizatu</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Diruzorroa:</translation>
</message>
@@ -380,18 +482,62 @@
<translation type="unfinished">&amp;Jaso</translation>
</message>
<message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Aukerak...</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;Diruzorroa enkriptatu...</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">Zure diru-zorroari dagozkion giltza pribatuak enkriptatu.</translation>
</message>
<message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">Diruzorroaren &amp;segurtasun kopia egin...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;aldatu pasahitza</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">sinatu &amp;mezua</translation>
+ </message>
+ <message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
<translation type="unfinished">Sinatu mezuak Bitcoinen helbideekin, jabetza frogatzeko.</translation>
</message>
<message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">Mezua &amp;balioztatu</translation>
+ </message>
+ <message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
<translation type="unfinished">Egiaztatu mesua Bitcoin helbide espezifikoarekin erregistratu direla ziurtatzeko</translation>
</message>
<message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;kargatu PSBT fitxategitik...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">Ireki&amp;URI...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">Diruzorroa itxi...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">Diruzorroa sortu...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">Diru-zorro guztiak itxi...</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation type="unfinished">&amp;Artxiboa</translation>
</message>
@@ -408,6 +554,26 @@
<translation type="unfinished">Fitxen tresna-barra</translation>
</message>
<message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Sarearekin sinkronizatzen...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Diskoko blokeak indexatzen...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Diskoko blokeak prozesatzen...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Diskoko blokeak berzerrendatzen</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Pareekin konektatzen...</translation>
+ </message>
+ <message>
<source>Show the list of used sending addresses and labels</source>
<translation type="unfinished"> Bidalketa-helbideen eta etiketen zerrenda erakutsi</translation>
</message>
@@ -431,6 +597,10 @@
<translation type="unfinished">%1 atzetik</translation>
</message>
<message>
+ <source>Catching up…</source>
+ <translation type="unfinished">Harrapatzen...</translation>
+ </message>
+ <message>
<source>Last received block was generated %1 ago.</source>
<translation type="unfinished">Jasotako azken blokea duela %1 sortu zen.</translation>
</message>
@@ -459,6 +629,10 @@
<translation type="unfinished">Partzialki sinatutako Bitcoin transakzioa kargatu</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">kargatu PSBT arbeletik...</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">Partzialki sinatutako Bitcoin transakzioa kargatu arbeletik</translation>
</message>
@@ -503,6 +677,11 @@
<translation type="unfinished">Ez dago diru-zorrorik eskura</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Diruzorroaren izena</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Lehioa</translation>
</message>
@@ -518,6 +697,14 @@
<source>%1 client</source>
<translation type="unfinished">%1 bezeroa</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Ezkutatu</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">E&amp;rakutsi</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
@@ -527,6 +714,11 @@
</translation>
</message>
<message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Erakutxi kideen fitxa</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Akatsa: %1</translation>
</message>
@@ -674,10 +866,22 @@
<translation type="unfinished">zenbatekoaren kopia</translation>
</message>
<message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiatu &amp;Etiketa</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Kopia kopurua</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Kopiatu kuota</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Kopia kuotaren ondoren</translation>
+ </message>
+ <message>
<source>Copy bytes</source>
<translation type="unfinished">Kopiatu byte-ak</translation>
</message>
@@ -718,6 +922,11 @@
<translation type="unfinished">Diruzorroa sortu</translation>
</message>
<message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">Diru-zorroa sortzen&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
<source>Create wallet failed</source>
<translation type="unfinished">Diruzorroa sortzen hutsegitea</translation>
</message>
@@ -725,8 +934,25 @@
<source>Create wallet warning</source>
<translation type="unfinished">Diru-zorroa sortzearen buruzko oharra</translation>
</message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Ezin dira sinatzaileak zerrendatu</translation>
+ </message>
</context>
<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">Kargatu diruzorroak</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">Diruzorroak kargatzen...</translation>
+ </message>
+</context>
+<context>
<name>OpenWalletActivity</name>
<message>
<source>Open wallet failed</source>
@@ -745,7 +971,12 @@
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">Diruzorroa zabaldu</translation>
</message>
- </context>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">&lt;b&gt;%1&lt;/b&gt; diruzorroa irekitzen ...</translation>
+ </message>
+</context>
<context>
<name>WalletController</name>
<message>
@@ -756,7 +987,11 @@
<source>Close all wallets</source>
<translation type="unfinished">Diruzorro guztiak itxi</translation>
</message>
- </context>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">Ziur diruzorro guztiak itxi nahi dituzula?</translation>
+ </message>
+</context>
<context>
<name>CreateWalletDialog</name>
<message>
@@ -784,10 +1019,18 @@
<translation type="unfinished">Desgaitu gako pribatuak</translation>
</message>
<message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">Egin diruzorro hutsa...</translation>
+ </message>
+ <message>
<source>Descriptor Wallet</source>
<translation type="unfinished">Deskriptorearen zorroa</translation>
</message>
<message>
+ <source>External signer</source>
+ <translation type="unfinished">Kanpo sinatzailea</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">Sortu</translation>
</message>
@@ -830,13 +1073,46 @@
<context>
<name>FreespaceChecker</name>
<message>
+ <source>A new data directory will be created.</source>
+ <translation type="unfinished">Datu direktorio berria sortuko da.</translation>
+ </message>
+ <message>
<source>name</source>
<translation type="unfinished">izena</translation>
</message>
- </context>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation type="unfinished">Bidea existitzen da, eta ez da direktorioa.</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation type="unfinished">Ezin da datu direktoria hemen sortu.</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -856,7 +1132,19 @@
<source>Welcome to %1.</source>
<translation type="unfinished">Ongietorri %1-ra</translation>
</message>
- </context>
+ <message>
+ <source> GB</source>
+ <translation type="unfinished">GB</translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation type="unfinished">Erabili datu direktorio lehenetsia</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation type="unfinished">Erabili datu direktorio pertsonalizatu bat:</translation>
+ </message>
+</context>
<context>
<name>HelpMessageDialog</name>
<message>
@@ -873,6 +1161,13 @@
</message>
</context>
<context>
+ <name>ShutdownWindow</name>
+ <message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1Itzaltzen ari da...</translation>
+ </message>
+ </context>
+<context>
<name>ModalOverlay</name>
<message>
<source>Form</source>
@@ -883,6 +1178,14 @@
<translation type="unfinished">Gainerako blokeen kopurua.</translation>
</message>
<message>
+ <source>Unknown…</source>
+ <translation type="unfinished">Ezezaguna...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">kalkulatzen...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation type="unfinished">Azken blokearen unea</translation>
</message>
@@ -891,6 +1194,10 @@
<translation type="unfinished">Aurrerapena</translation>
</message>
<message>
+ <source>Progress increase per hour</source>
+ <translation type="unfinished">Aurrerapenaren igoera orduko</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation type="unfinished">Izkutatu</translation>
</message>
@@ -1011,10 +1318,12 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Berretsi aukeren berrezarpena</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Bezeroa berrabiarazi behar da aldaketak aktibatzeko.</translation>
</message>
<message>
@@ -1054,21 +1363,69 @@
<translation type="unfinished">Ez dago eskuragarri:</translation>
</message>
<message>
+ <source>Balances</source>
+ <translation type="unfinished">Saldoa</translation>
+ </message>
+ <message>
<source>Total:</source>
<translation type="unfinished">Guztira:</translation>
</message>
+ <message>
+ <source>Your current total balance</source>
+ <translation type="unfinished">Zure oraingo erabateko saldoa</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation type="unfinished">Gastagarria:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation type="unfinished">Transakzio berriak</translation>
+ </message>
</context>
<context>
<name>PSBTOperationsDialog</name>
<message>
+ <source>Dialog</source>
+ <translation type="unfinished">Elkarrizketa</translation>
+ </message>
+ <message>
+ <source>Sign Tx</source>
+ <translation type="unfinished">Sinatu Tx</translation>
+ </message>
+ <message>
<source>Copy to Clipboard</source>
<translation type="unfinished">Kopiatu arbelera</translation>
</message>
<message>
+ <source>Save…</source>
+ <translation type="unfinished">Gorde...</translation>
+ </message>
+ <message>
<source>Close</source>
<translation type="unfinished">Itxi</translation>
</message>
- </context>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">Gorde transakzioko data</translation>
+ </message>
+ <message>
+ <source>PSBT saved to disk.</source>
+ <translation type="unfinished">PSBT diskoan gorde da.</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">Kopuru osoa</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">edo</translation>
+ </message>
+ <message>
+ <source>Transaction status is unknown.</source>
+ <translation type="unfinished">Transakzioaren egoera ezezaguna da.</translation>
+ </message>
+</context>
<context>
<name>PaymentServer</name>
<message>
@@ -1084,6 +1441,21 @@
<translation type="unfinished">Erabiltzaile agentea</translation>
</message>
<message>
+ <source>Peer</source>
+ <extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
+ <translation type="unfinished">Kidea</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment>
+ <translation type="unfinished">Bidalia</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have received from the peer.</extracomment>
+ <translation type="unfinished">Jasoa</translation>
+ </message>
+ <message>
<source>Address</source>
<extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
<translation type="unfinished">Helbidea</translation>
@@ -1093,10 +1465,103 @@
<extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment>
<translation type="unfinished">Mota</translation>
</message>
+ <message>
+ <source>Network</source>
+ <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment>
+ <translation type="unfinished">Sarea</translation>
+ </message>
</context>
<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Gorde irudia...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation type="unfinished">&amp;kopiatu irudia</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation type="unfinished">Gorde QR kodea</translation>
+ </message>
+ <message>
+ <source>PNG Image</source>
+ <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment>
+ <translation type="unfinished">PNG irudia</translation>
+ </message>
+</context>
+<context>
<name>RPCConsole</name>
<message>
+ <source>Client version</source>
+ <translation type="unfinished">Bezeroaren bertsioa</translation>
+ </message>
+ <message>
+ <source>&amp;Information</source>
+ <translation type="unfinished">&amp;Informazioa</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation type="unfinished">Orokorra</translation>
+ </message>
+ <message>
+ <source>Datadir</source>
+ <translation type="unfinished">Datu direktorioa</translation>
+ </message>
+ <message>
+ <source>Blocksdir</source>
+ <translation type="unfinished">Blokeen direktorioa</translation>
+ </message>
+ <message>
+ <source>Startup time</source>
+ <translation type="unfinished">Abiatzeko ordua</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished">Sarea</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished">Izena</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation type="unfinished">Konexio kopurua</translation>
+ </message>
+ <message>
+ <source>Wallet: </source>
+ <translation type="unfinished">Diruzorroa:</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation type="unfinished">(bat ere ez)</translation>
+ </message>
+ <message>
+ <source>&amp;Reset</source>
+ <translation type="unfinished">&amp;Berrezarri</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation type="unfinished">Jasoa</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation type="unfinished">Bidalia</translation>
+ </message>
+ <message>
+ <source>&amp;Peers</source>
+ <translation type="unfinished">&amp;Kideak</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation type="unfinished">Debekatutako kideak</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation type="unfinished">Bertsioa</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">Erabiltzaile agentea</translation>
</message>
@@ -1105,10 +1570,39 @@
<translation type="unfinished">Adabegiaren leihoa</translation>
</message>
<message>
+ <source>Permissions</source>
+ <translation type="unfinished">Baimenak</translation>
+ </message>
+ <message>
+ <source>Services</source>
+ <translation type="unfinished">Zerbitzuak</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation type="unfinished">Azken blokearen unea</translation>
</message>
<message>
+ <source>Clear console</source>
+ <translation type="unfinished">Garbitu kontsola</translation>
+ </message>
+ <message>
+ <source>&amp;Disconnect</source>
+ <translation type="unfinished">&amp;Deskonektatu</translation>
+ </message>
+ <message>
+ <source>Executing…</source>
+ <extracomment>A console message indicating an entered command is currently being executed.</extracomment>
+ <translation type="unfinished">Exekutatzen...</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished">Bai</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished">Ez</translation>
+ </message>
+ <message>
<source>To</source>
<translation type="unfinished">Ra</translation>
</message>
@@ -1116,7 +1610,15 @@
<source>From</source>
<translation type="unfinished">Tik</translation>
</message>
- </context>
+ <message>
+ <source>Never</source>
+ <translation type="unfinished">Inoiz ez</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation type="unfinished">Ezezaguna</translation>
+ </message>
+</context>
<context>
<name>ReceiveCoinsDialog</name>
<message>
@@ -1132,6 +1634,30 @@
<translation type="unfinished">&amp;Mezua:</translation>
</message>
<message>
+ <source>Clear all fields of the form.</source>
+ <translation type="unfinished">Garbitu formularioko eremu guztiak.</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation type="unfinished">Garbitu</translation>
+ </message>
+ <message>
+ <source>Show</source>
+ <translation type="unfinished">Erakutsi</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation type="unfinished">Ezabatu</translation>
+ </message>
+ <message>
+ <source>Copy &amp;URI</source>
+ <translation type="unfinished">Kopiatu &amp;URI</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiatu &amp;Etiketa</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">Ezin da diruzorroa desblokeatu.</translation>
</message>
@@ -1139,10 +1665,18 @@
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>Address:</source>
+ <translation type="unfinished">Helbidea:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation type="unfinished">Kopurua:</translation>
</message>
<message>
+ <source>Label:</source>
+ <translation type="unfinished">Etiketa:</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation type="unfinished">Mezua:</translation>
</message>
@@ -1151,9 +1685,25 @@
<translation type="unfinished">Diruzorroa:</translation>
</message>
<message>
+ <source>Copy &amp;URI</source>
+ <translation type="unfinished">Kopiatu &amp;URI</translation>
+ </message>
+ <message>
<source>Copy &amp;Address</source>
<translation type="unfinished">&amp;Helbidea kopiatu</translation>
</message>
+ <message>
+ <source>&amp;Verify</source>
+ <translation type="unfinished">&amp;Egiaztatu</translation>
+ </message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Gorde irudia...</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation type="unfinished">Ordainketaren informazioa</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -1173,7 +1723,15 @@
<source>(no label)</source>
<translation type="unfinished">(izendapenik ez)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation type="unfinished">(mezurik ez)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation type="unfinished">Eskatua</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1181,6 +1739,10 @@
<translation type="unfinished">Txanponak bidali</translation>
</message>
<message>
+ <source>automatically selected</source>
+ <translation type="unfinished">automatikoki aukeratua</translation>
+ </message>
+ <message>
<source>Quantity:</source>
<translation type="unfinished">Zenbat:</translation>
</message>
@@ -1205,18 +1767,42 @@
<translation type="unfinished">Bueltak:</translation>
</message>
<message>
+ <source>Transaction Fee:</source>
+ <translation type="unfinished">Transakzio kuota:</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation type="unfinished">Kilobyteko</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation type="unfinished">Izkutatu</translation>
</message>
<message>
+ <source>Recommended:</source>
+ <translation type="unfinished">Gomendatutakoa:</translation>
+ </message>
+ <message>
+ <source>Custom:</source>
+ <translation type="unfinished">Neurrira:</translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation type="unfinished">Hainbat jasotzaileri batera bidali</translation>
</message>
<message>
+ <source>Clear all fields of the form.</source>
+ <translation type="unfinished">Garbitu formularioko eremu guztiak.</translation>
+ </message>
+ <message>
<source>Dust:</source>
<translation type="unfinished">Hautsa:</translation>
</message>
<message>
+ <source>Choose…</source>
+ <translation type="unfinished">Aukeratu...</translation>
+ </message>
+ <message>
<source>Balance:</source>
<translation type="unfinished">Saldoa:</translation>
</message>
@@ -1225,6 +1811,10 @@
<translation type="unfinished">Bidalketa berretsi</translation>
</message>
<message>
+ <source>S&amp;end</source>
+ <translation type="unfinished">Bidali</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Kopia kopurua</translation>
</message>
@@ -1233,6 +1823,14 @@
<translation type="unfinished">zenbatekoaren kopia</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Kopiatu kuota</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Kopia kuotaren ondoren</translation>
+ </message>
+ <message>
<source>Copy bytes</source>
<translation type="unfinished">Kopiatu byte-ak</translation>
</message>
@@ -1245,6 +1843,49 @@
<translation type="unfinished">Kopiatu aldaketa</translation>
</message>
<message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">Sinatu gailuan</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">Konektatu zure hardware diruzorroa lehenago.</translation>
+ </message>
+ <message>
+ <source>Sign failed</source>
+ <translation type="unfinished">Sinadurak hutsegitea</translation>
+ </message>
+ <message>
+ <source>External signer not found</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Kanpo sinatzailea ez da aurkitu</translation>
+ </message>
+ <message>
+ <source>External signer failure</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Kanpo sinatzailearen hutsegitea</translation>
+ </message>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">Gorde transakzioko data</translation>
+ </message>
+ <message>
+ <source>PSBT saved</source>
+ <translation type="unfinished">PSBT gordeta</translation>
+ </message>
+ <message>
+ <source>External balance:</source>
+ <translation type="unfinished">Kanpo saldoa:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">edo</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">Kopuru osoa</translation>
+ </message>
+ <message>
<source>Confirm send coins</source>
<translation type="unfinished">Txanponen bidalketa berretsi</translation>
</message>
@@ -1279,6 +1920,10 @@
<translation type="unfinished">&amp;Etiketa:</translation>
</message>
<message>
+ <source>Choose previously used address</source>
+ <translation type="unfinished">Aukeratu lehenago aukeraturiko helbidea</translation>
+ </message>
+ <message>
<source>Paste address from clipboard</source>
<translation type="unfinished">Arbeletik helbidea itsatsi</translation>
</message>
@@ -1286,18 +1931,38 @@
<source>Message:</source>
<translation type="unfinished">Mezua:</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Honi ordaindu:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
+ <source>Choose previously used address</source>
+ <translation type="unfinished">Aukeratu lehenago aukeraturiko helbidea</translation>
+ </message>
+ <message>
<source>Paste address from clipboard</source>
<translation type="unfinished">Arbeletik helbidea itsatsi</translation>
</message>
<message>
+ <source>Enter the message you want to sign here</source>
+ <translation type="unfinished">Sartu sinatu nahi duzun mezua hemen</translation>
+ </message>
+ <message>
+ <source>Signature</source>
+ <translation type="unfinished">Sinadura</translation>
+ </message>
+ <message>
+ <source>Copy the current signature to the system clipboard</source>
+ <translation type="unfinished">Kopiatu oraingo sinadura sistemaren arbelera</translation>
+ </message>
+ <message>
+ <source>Sign &amp;Message</source>
+ <translation type="unfinished">Sinatu &amp;Mezua</translation>
+ </message>
+ <message>
+ <source>&amp;Verify Message</source>
+ <translation type="unfinished">&amp;Egiaztatu mezua</translation>
+ </message>
+ <message>
<source>No error</source>
<translation type="unfinished">Ez dago errorerik</translation>
</message>
@@ -1313,19 +1978,30 @@
<source>Please check the signature and try again.</source>
<translation type="unfinished">Mesedez, begiratu sinadura eta saiatu berriro.</translation>
</message>
- </context>
+ <message>
+ <source>Message verification failed.</source>
+ <translation type="unfinished">Mezuen egiaztatzeak huts egin du</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation type="unfinished">Mezua egiaztatua.</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">abandonatuta</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/konfirmatu gabe</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 konfirmazio</translation>
</message>
<message>
@@ -1407,7 +2083,15 @@
<source>Amount</source>
<translation type="unfinished">Kopurua</translation>
</message>
- </context>
+ <message>
+ <source>true</source>
+ <translation type="unfinished">egia</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation type="unfinished">faltsua</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
@@ -1430,6 +2114,10 @@
<translation type="unfinished">Izendapen</translation>
</message>
<message>
+ <source>Unconfirmed</source>
+ <translation type="unfinished">Baieztatu gabea</translation>
+ </message>
+ <message>
<source>Confirmed (%1 confirmations)</source>
<translation type="unfinished">Konfirmatuta (%1 konfirmazio)</translation>
</message>
@@ -1529,6 +2217,15 @@
<translation type="unfinished">Kopuru minimoa</translation>
</message>
<message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiatu &amp;Etiketa</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Komaz bereizitako fitxategia</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">Berretsia</translation>
</message>
@@ -1571,6 +2268,18 @@
<translation type="unfinished">Txanponak bidali</translation>
</message>
<message>
+ <source>Current fee:</source>
+ <translation type="unfinished">Oraingo kuota:</translation>
+ </message>
+ <message>
+ <source>New fee:</source>
+ <translation type="unfinished">Kuota berria:</translation>
+ </message>
+ <message>
+ <source>PSBT copied</source>
+ <translation type="unfinished">PSBT kopiatua</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">Diruzorro lehenetsia</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts
index 77f73f70d8..030b8fdf00 100644
--- a/src/qt/locale/bitcoin_fa.ts
+++ b/src/qt/locale/bitcoin_fa.ts
@@ -3,15 +3,15 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">برای ویرایش نشانی یا برچسب زدن کلیک ‌راست کنید</translation>
+ <translation type="unfinished">برای ویرایش نشانی یا برچسب راست-کلیک کنید</translation>
</message>
<message>
<source>Create a new address</source>
- <translation type="unfinished">آدرس جدید ایجاد کنید</translation>
+ <translation type="unfinished">یک آدرس جدید ایجاد کنید</translation>
</message>
<message>
<source>&amp;New</source>
- <translation type="unfinished">و جدید</translation>
+ <translation type="unfinished">&amp;جدید</translation>
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
@@ -27,7 +27,7 @@
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation type="unfinished">حذ٠آدرس ‌انتخاب شده از Ùهرست</translation>
+ <translation type="unfinished">حذ٠آدرس ‌انتخاب شده ÛŒ جاری از Ùهرست</translation>
</message>
<message>
<source>Enter address or label to search</source>
@@ -39,13 +39,21 @@
</message>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">صدور</translation>
+ <translation type="unfinished">&amp;صدور</translation>
</message>
<message>
<source>&amp;Delete</source>
<translation type="unfinished">حذÙ</translation>
</message>
<message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">آدرس را برای ارسال کوین وارد کنید</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">آدرس را برای دریاÙت کوین وارد کنید</translation>
+ </message>
+ <message>
<source>C&amp;hoose</source>
<translation type="unfinished">انتخاب</translation>
</message>
@@ -160,7 +168,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">هشدار: اگر کی٠پول خود را رمزگذاری کنید Ùˆ عبارت خود را گام کنید ØŒ این کار را انجام Ù…ÛŒ دهید &lt;b&gt;تمام کویت های خود را از دست &lt;/b&gt;استÙاده کنید!
+ <translation type="unfinished">هشدار: اگر کی٠پول خود را رمزگذاری کنید و عبارت خود را گم کنید ، &lt;b&gt;تمام کویت های خود را از دست &lt;/b&gt;خواهید داد!
</translation>
</message>
<message>
@@ -251,12 +259,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
- <source>Runaway exception</source>
- <translation type="unfinished">استثناء Ùراری (این استثناء نشان دهنده این است Ú©Ù‡ هسته بیتکوین نتوانست چیزی را در Ú©ÛŒÙ(والت) بنویسد.)</translation>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Ùایل تنظیمات %1 ممکن است خراب یا نامعتبر باشد.</translation>
</message>
<message>
- <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <translation type="unfinished"> خطای تخریب کننده ای روی داده است.%1 نمیتواند بصورت ایمن ادامه پیدا کند و پایان می یابد.</translation>
+ <source>Runaway exception</source>
+ <translation type="unfinished">استثناء Ùراری (این استثناء نشان دهنده این است Ú©Ù‡ هسته بیتکوین نتوانست چیزی را در Ú©ÛŒÙ(والت) بنویسد.)</translation>
</message>
<message>
<source>Internal error</source>
@@ -367,31 +375,31 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n second(s)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n minute(s)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n hour(s)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n day(s)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n week(s)</numerusform>
</translation>
</message>
<message>
@@ -401,7 +409,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n year(s)</numerusform>
</translation>
</message>
<message>
@@ -591,10 +599,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">خطا در خواندن رکورد بعدی از پایگاه داده کی٠پول</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">خطا در بارگذاری پایگاه داده ها</translation>
- </message>
- <message>
<source>Error: Couldn't create cursor into database</source>
<translation type="unfinished">خطا: مکان نما در پایگاه داده ایجاد نشد</translation>
</message>
@@ -692,10 +696,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">توصیÙگرهای Ùایل به اندازه کاÙÛŒ در دسترس نیست</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">حالت Prune با -coinstatsindex ناسازگار است.</translation>
- </message>
- <message>
<source>Pruning blockstore…</source>
<translation type="unfinished">هرس بلوک Ùروشی…</translation>
</message>
@@ -773,6 +773,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">حجم تراکنش خیلی زیاد است</translation>
</message>
<message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">قادر به پیدا کردن UTXO برای ورودی جانبی نیست.</translation>
+ </message>
+ <message>
<source>Unable to generate initial keys</source>
<translation type="unfinished">نمیتوان کلید های اولیه را تولید کرد.</translation>
</message>
@@ -802,10 +806,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">قوانین جدید ناشناخته Ùعال شد (‌%iversionbit)</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">ارتقا دادن پایگاه داده UTXO</translation>
- </message>
- <message>
<source>Verifying blocks…</source>
<translation type="unfinished">در حال تأیید بلوک‌ها…</translation>
</message>
@@ -934,6 +934,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">پیام تایید</translation>
</message>
<message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">پیام ها را تأیید کنید تا مطمئن شوید با آدرس های مشخص شده بیت کوین امضا شده اند
+ </translation>
+ </message>
+ <message>
<source>&amp;Load PSBT from file…</source>
<translation type="unfinished">بارگیری PSBT از پرونده</translation>
</message>
@@ -1012,7 +1017,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>سابقه تراکنش بلوک(های) %n پردازش شد.</numerusform>
</translation>
</message>
<message>
@@ -1086,6 +1091,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">کی٠پول را ببندید</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">بازیابی کی٠پول…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">بازیابی یک کی٠پول از یک Ùایل پشتیبان</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">همه‌ی کی٠پول‌ها را ببند</translation>
</message>
@@ -1099,6 +1114,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">هیچ کی٠پولی در دسترس نمی باشد</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">داده های کی٠پول</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">بارگیری پشتیبان‌گیری کی٠پول</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">بازیابی کی٠پول</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">نام کی٠پول</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">پنجره</translation>
</message>
@@ -1114,11 +1149,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">کلاینت: %1</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">مخÙÛŒ Ú©Ù†</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n اتصال(های) Ùعال به شبکه بیت کوین.</numerusform>
</translation>
</message>
<message>
@@ -1142,6 +1181,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ùعال‌سازی Ùعالیت شبکه</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">پیش‌همگام‌سازی سرصÙحه‌ها (%1%)…</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">خطا: %1</translation>
</message>
@@ -1399,6 +1442,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">نمی‌توان امضاکنندگان را Ùهرست کرد</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">تعداد زیادی امضاکننده خارجی پیدا شد</translation>
+ </message>
</context>
<context>
<name>LoadWalletsActivity</name>
@@ -1441,6 +1488,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">بازیابی کی٠پول</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">بازیابی کی٠پول &lt;b&gt;%1&lt;/b&gt; ...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">بازیابی کی٠پول انجام نشد</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">هشدار بازیابی کی٠پول</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">بازیابی پیام کی٠پول</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1472,7 +1547,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
- <translation type="unfinished">کی٠پول را رمز نگاری نمائید. کی٠پول با کلمات رمز انتخاب خودتان رمز نگاری خواهد شد</translation>
+ <translation type="unfinished">کی٠پول را رمز نگاری نمائید. کی٠پول با کلمات رمز دلخواه شما رمز نگاری خواهد شد</translation>
</message>
<message>
<source>Encrypt Wallet</source>
@@ -1593,13 +1668,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Bitcoin</source>
<translation type="unfinished">بیت کوین</translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(%1 گیگابایت لازم است)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n گیگابایت Ùضای موجود</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 برای زنجیر کامل نیاز است)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(از %n گیگابایت مورد نیاز)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n گیگابایت برای زنجیره کامل مورد نیاز است)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1613,7 +1698,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(برای بازیابی نسخه‌های پشتیبان %n روز (های) قدیمی کاÙÛŒ است)</numerusform>
</translation>
</message>
<message>
@@ -1649,6 +1734,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">گیگابایت</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">وقتی تأیید را کلیک می‌کنید، %1 شروع به دانلود و پردازش زنجیره بلاک %4 کامل (%2 گیگابایت) می‌کند که با اولین تراکنش‌ها در %3 شروع می‌شود که %4 در ابتدا راه‌اندازی می شود.</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 type="unfinished">اگر تصمیم بگیرید Ú©Ù‡ Ùضای ذخیره سازی زنجیره بلوک (هرس) را محدود کنید ØŒ داده های تاریخی باید بارگیری Ùˆ پردازش شود ØŒ اما اگر آن را حذ٠کنید ØŒ اگر شما دیسک Ú©Ù… استÙاده کنید.
 </translation>
@@ -1740,6 +1829,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">ناشناخته. هماهنگ‌سازی سربرگ‌ها (%1، %2%) </translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">ناشناس. پیش‌همگام‌سازی سرصÙحه‌ها (%1ØŒ %2% )…</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -1776,6 +1869,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">اندازه کش پایگاه داده.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">گزینه های تنظیم شده در این Ú¯Ùتگو توسط خط Ùرمان لغو Ù…ÛŒ شوند:</translation>
+ </message>
+ <message>
<source>Open Configuration File</source>
<translation type="unfinished">بازکردن Ùایل پیکربندی</translation>
</message>
@@ -2004,15 +2101,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">باز نشانی گزینه ها را تأیید کنید
  </translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">کلاینت نیازمند ریست شدن است برای Ùعال کردن تغییرات</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">تنظیمات Ùعلی در "%1" پشتیبان گیری خواهد شد.</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">کلاینت خاموش خواهد شد.آیا میخواهید ادامه دهید؟</translation>
</message>
<message>
@@ -2053,6 +2158,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">نمی توان تنظیم "%1"، %2 را خواند.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2168,6 +2280,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">یا</translation>
</message>
<message>
+ <source>Transaction has %1 unsigned inputs.</source>
+ <translation type="unfinished">%1Transaction has unsigned inputs.</translation>
+ </message>
+ <message>
<source>Transaction still needs signature(s).</source>
<translation type="unfinished">عملیات هنوز به امضا(ها) نیاز دارد.</translation>
</message>
@@ -2229,6 +2345,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">همتا </translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">سن</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">مسیر</translation>
@@ -2405,29 +2526,22 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Whether we relay addresses to this peer.</source>
- <extracomment>Tooltip text for the Address Relay field in the peer details area.</extracomment>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished"> ما آدرس‌ها را به این همتا ارسال می‌کنیم.</translation>
</message>
<message>
<source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">رله آدرس</translation>
</message>
<message>
- <source>Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Processed field in the peer details area.</extracomment>
- <translation type="unfinished">تعداد کل آدرس‌های پردازش شده، به استثنای آدرس‌هایی که به دلیل محدودیت نرخ حذ٠شده‌اند.</translation>
- </message>
- <message>
<source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
<translation type="unfinished">آدرس ها پردازش شد</translation>
</message>
<message>
- <source>Total number of addresses dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area.</extracomment>
- <translation type="unfinished">تعداد Ú©Ù„ آدرس‌ها به دلیل محدودیت نرخ کاهش یاÙت.</translation>
- </message>
- <message>
<source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
<translation type="unfinished">آدرس ها با نرخ محدود</translation>
</message>
<message>
@@ -3028,7 +3142,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Copy amount</source>
- <translation type="unfinished">مقدار کپی</translation>
+ <translation type="unfinished">کپی مقدار</translation>
</message>
<message>
<source>Copy fee</source>
@@ -3167,14 +3281,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">کارمزد بیشتر از %1 است,این یعنی کارمزد خیلی زیادی در نظر گرÙته شده است.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">درخواست پرداخت منقضی شد یا تاریخ آن گذشت.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
</translation>
</message>
<message>
@@ -3238,25 +3348,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>Message:</source>
<translation type="unfinished">پیام:</translation>
</message>
- <message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">این یک درخواست پرداخت غیرمجاز است.
- </translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">این یک درخواست پرداخت معتبر است.
- </translation>
- </message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">پرداخت کردن</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">یادداشت:</translation>
- </message>
-</context>
+ </context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -3421,14 +3513,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<name>TransactionDesc</name>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">رها شده</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/تأیید نشده</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 تأییدیه</translation>
</message>
<message>
@@ -3478,7 +3573,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>matures in %n more block(s)</numerusform>
</translation>
</message>
<message>
@@ -3859,11 +3954,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<name>WalletView</name>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">صدور</translation>
+ <translation type="unfinished">&amp;صدور</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation type="unfinished">داده های موجود در برگه Ùعلی را به یک Ùایل صادر کنید</translation>
+ <translation type="unfinished">خروجی گرÙتن داده‌ها از برگه ÛŒ کنونی در یک پوشه</translation>
</message>
<message>
<source>Backup Wallet</source>
diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts
index c1321b0bd4..112926f7b0 100644
--- a/src/qt/locale/bitcoin_fi.ts
+++ b/src/qt/locale/bitcoin_fi.ts
@@ -246,6 +246,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Asetustiedosto %1 saattaa olla vioittunut tai virheellinen.</translation>
+ </message>
+ <message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
<translation type="unfinished">Peruuttamaton virhe on tapahtunut. %1 ei voi enää jatkaa turvallisesti ja sammutetaan.</translation>
</message>
@@ -332,36 +336,36 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n sekunti</numerusform>
+ <numerusform>%n sekuntia</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minuutti</numerusform>
+ <numerusform>%n minuuttia</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n tunti</numerusform>
+ <numerusform>%n tuntia</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n päivä</numerusform>
+ <numerusform>%n päivää</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n viikko</numerusform>
+ <numerusform>%n viikkoa</numerusform>
</translation>
</message>
<message>
@@ -371,8 +375,8 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n vuosi</numerusform>
+ <numerusform>%n vuotta</numerusform>
</translation>
</message>
</context>
@@ -419,10 +423,6 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Virhe: Dump-tiedoston versio ei ole tuettu. Tämä bitcoin-lompakon versio tukee vain version 1 dump-tiedostoja. Annetun dump-tiedoston versio %s</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Virhe: Saapuvien yhteyksien kuuntelu epäonnistui (kuuntelu palautti virheen %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Siirtomaksun arviointi epäonnistui. Odota muutama lohko tai käytä -fallbackfee -valintaa..</translation>
</message>
@@ -603,10 +603,6 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Virhe seuraavan tietueen lukemisessa lompakon tietokannasta</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Virhe päivittäessä chainstate-tietokantaa</translation>
- </message>
- <message>
<source>Error: Couldn't create cursor into database</source>
<translation type="unfinished">Virhe: Tietokantaan ei voitu luoda kursoria.</translation>
</message>
@@ -715,8 +711,8 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Pitää määritellä portti argumentilla -whitebind: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Välityspalvelinta ei ole määritetty. Käytä -proxy=&lt;ip&gt; tai -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Osoitteita ei ole saatavilla</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -727,10 +723,6 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Karsintaa ei voi toteuttaa negatiivisella arvolla.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Karsintatila ei ole yhteenopiva -coinstatsindex:n kanssa.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">Karsittu tila ei ole yhteensopiva -txindex:n kanssa.</translation>
</message>
@@ -887,10 +879,6 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Lokikategoriaa %s=%s ei tueta.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Päivitetään UTXO-tietokantaa</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">User Agent -kommentti (%s) sisältää turvattomia merkkejä.</translation>
</message>
@@ -1105,8 +1093,8 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Käsitelty %n lohko rahansiirtohistoriasta.</numerusform>
+ <numerusform>Käsitelty %n lohkoa rahansiirtohistoriasta.</numerusform>
</translation>
</message>
<message>
@@ -1206,6 +1194,16 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Lompakoita ei ole saatavilla</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Lompakkotiedot</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Lompakon nimi</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Ikkuna</translation>
</message>
@@ -1221,12 +1219,16 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<source>%1 client</source>
<translation type="unfinished">%1-asiakas</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Piilota</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n aktiivinen yhteys Bitcoin-verkkoon.</numerusform>
+ <numerusform>%n aktiivista yhteyttä Bitcoin-verkkoon.</numerusform>
</translation>
</message>
<message>
@@ -1420,6 +1422,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Kopioi &amp;määrä</translation>
</message>
<message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;Avaa käyttämättömien lukitus</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Kopioi lukumäärä</translation>
</message>
@@ -1500,7 +1506,7 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<source>Can't list signers</source>
<translation type="unfinished">Allekirjoittajia ei voida listata</translation>
</message>
-</context>
+ </context>
<context>
<name>LoadWalletsActivity</name>
<message>
@@ -1706,13 +1712,26 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(%1 GB tarvitaan)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB tarvitaan koko ketjuun)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(tarvitaan %n GB)</numerusform>
+ <numerusform>(tarvitaan %n GB)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(tarvitaan %n GB koko ketjua varten)</numerusform>
+ <numerusform>(tarvitaan %n GB koko ketjua varten)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1759,10 +1778,6 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Tämä on ensimmäinen kerta, kun %1 on käynnistetty, joten voit valita data-hakemiston paikan.</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 type="unfinished">Kun valitset OK, %1 aloittaa lataamaan ja käsittelemään koko %4 lohkoketjua (%2GB) aloittaen ensimmäisestä siirrosta %3 jolloin %4 käynnistettiin ensimmäistä kertaa.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Rajoita lohkoketjun tallennus</translation>
</message>
@@ -1875,7 +1890,7 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Tuntematon. Synkronoidaan järjestysnumeroita (%1,%2%)...</translation>
</message>
-</context>
+ </context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -1972,6 +1987,11 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Näin sinä tai kolmannen osapuolen työkalu voi kommunikoida solmun kanssa komentorivi- ja JSON-RPC-komentojen avulla.</translation>
</message>
<message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Aktivoi R&amp;PC serveri</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">&amp;Lompakko</translation>
</message>
@@ -1992,6 +2012,11 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">&amp;Käytä varmistamattomia vaihtorahoja</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Aktivoi &amp;PSBT kontrollit</translation>
+ </message>
+ <message>
<source>External Signer (e.g. hardware wallet)</source>
<translation type="unfinished">Ulkopuolinen allekirjoittaja (esim. laitelompakko)</translation>
</message>
@@ -2116,10 +2141,6 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">lähin vastaavuus "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Seuraavat komentorivillä tai asetustiedostossa annetut määritykset menevät tässä ikkunassa asetettujen asetusten edelle:</translation>
- </message>
- <message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Peruuta</translation>
</message>
@@ -2138,14 +2159,17 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Varmista asetusten palautus</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Ohjelman uudelleenkäynnistys aktivoi muutokset.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Asiakasohjelma sammutetaan. Haluatko jatkaa?</translation>
</message>
<message>
@@ -2374,6 +2398,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio
<translation type="unfinished">Siirto tarvitsee vielä allekirjoituksia.</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Mutta lompakkoa ei ole ladattu.)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Mutta tämä lompakko ei voi allekirjoittaa siirtoja.)</translation>
</message>
@@ -2626,6 +2654,10 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr
<translation type="unfinished">Synkronoidut lohkot</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Viimeisin transaktio</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">Kartoitettu autonominen järjestelmä, jota käytetään monipuolistamaan solmuvalikoimaa</translation>
</message>
@@ -3210,6 +3242,11 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr
<translation type="unfinished">%1 (%2 lohkoa)</translation>
</message>
<message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">Allekirjoita laitteella</translation>
+ </message>
+ <message>
<source>Connect your hardware wallet first.</source>
<translation type="unfinished">Yhdistä lompakkolaitteesi ensin.</translation>
</message>
@@ -3231,6 +3268,10 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr
<translation type="unfinished"> lompakosta '%1'</translation>
</message>
<message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">Tarkastellaksesi vastaanottajalistaa klikkaa "Näytä Lisätiedot..."</translation>
+ </message>
+ <message>
<source>Sign failed</source>
<translation type="unfinished">Allekirjoittaminen epäonnistui</translation>
</message>
@@ -3327,10 +3368,6 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">%1:tä ja korkeampaa siirtokulua pidetään mielettömän korkeana.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Maksupyyntö vanhentui.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -3410,14 +3447,6 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr
<translation type="unfinished">Viesti:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Tämä on todentamaton maksupyyntö.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Tämä on todennettu maksupyyntö.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Aseta nimi tälle osoitteelle lisätäksesi sen käytettyjen osoitteiden listalle.</translation>
</message>
@@ -3425,14 +3454,6 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr
<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 type="unfinished">Viesti joka liitettiin bitcoin: URI:iin tallennetaan rahansiirtoon viitteeksi. Tätä viestiä ei lähetetä Bitcoin-verkkoon.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Saaja:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Muistio:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3594,35 +3615,31 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr
<source>(press q to shutdown and continue later)</source>
<translation type="unfinished">(paina q lopettaaksesi ja jatkaaksesi myöhemmin)</translation>
</message>
- </context>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">paina q sammuttaaksesi</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">ristiriidassa maksutapahtumalle, jolla on %1 varmistusta</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/varmistamaton, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">muistialtaassa</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">ei muistialtaassa</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">hylätty</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/vahvistamaton</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 vahvistusta</translation>
</message>
<message>
@@ -3942,6 +3959,10 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr
<translation type="unfinished">Kopioi &amp;määrä</translation>
</message>
<message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">Kopio transaktio &amp;ID</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Vie rahansiirtohistoria</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fil.ts b/src/qt/locale/bitcoin_fil.ts
index 98081e07c4..9b9229f720 100644
--- a/src/qt/locale/bitcoin_fil.ts
+++ b/src/qt/locale/bitcoin_fil.ts
@@ -324,10 +324,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Error sa pagbabasa %s! Nabasa nang tama ang lahat ng mga key, ngunit ang data ng transaksyon o mga entry sa address book ay maaaring nawawala o hindi tama.</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Kamalian: Nabigo ang pakikinig sa mga papasok na koneksyon (ang listen ay nagbalik ng error %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Nabigo ang pagtatantya ng bayad. Hindi pinagana ang Fallbackfee. Maghintay ng ilang mga block o paganahin -fallbackfee.</translation>
</message>
@@ -464,10 +460,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kamalian sa pagbabasa mula sa database, nag-shu-shut down.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Kamalian sa pag-u-upgrade ng chainstate database</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Kamalian: Ang disk space ay mababa para sa %s</translation>
</message>
@@ -636,10 +628,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Hindi suportadong logging category %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Nag-u-upgrade ng UTXO database</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Ang komento ng User Agent (%s) ay naglalaman ng hindi ligtas na mga character.</translation>
</message>
@@ -699,6 +687,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Gumawa ng Bagong Pitaka</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Pagliitin</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Walet:</translation>
</message>
@@ -732,6 +724,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tumanggap</translation>
</message>
<message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Opsyon</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">I-encrypt ang private keys na kabilang sa iyong walet</translation>
</message>
@@ -847,6 +843,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Walang magagamit na mga walet</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Pangalan ng Pitaka</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">Window</translation>
</message>
@@ -866,8 +867,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n aktibong konekyson sa network ng Bitcoin</numerusform>
+ <numerusform>%n mga aktibong koneksyon sa network ng Bitcoin</numerusform>
</translation>
</message>
<message>
@@ -997,6 +998,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kopyahin ang halaga</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopyahin and address</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopyahin ang &amp;label</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopyahin ang &amp;halaga</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Kopyahin ang &amp;ID ng transaksyon at output index</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Kopyahin ang dami</translation>
</message>
@@ -1215,6 +1232,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Kahit na %1 GB na datos ay maiimbak sa direktoryong ito, ito ay lalaki sa pagtagal.</translation>
@@ -1260,10 +1298,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Dahil ngayon lang nilunsad ang programang ito, maaari mong piliin kung saan maiinbak ng %1 ang data nito.</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 type="unfinished">Pagkatapos mong mag-click ng OK, %1 ay magsisimulang mag-download at mag-proseso ng buong blockchain (%2GB) magmula sa pinakaunang transaksyon sa %3 nuong ang %4 ay paunang nilunsad.</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 type="unfinished">Maraming pangangailangan ang itong paunang sinkronisasyon at maaaring ilantad ang mga problema sa hardware ng iyong computer na hindi dating napansin. Tuwing pagaganahin mo ang %1, ito'y magpapatuloy mag-download kung saan ito tumigil.</translation>
</message>
@@ -1516,10 +1550,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kung magpapakita ng mga tampok ng kontrol ng coin o hindi</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Ang mga nakatakdang opyson sa dialog na ito ay ma-o-override ng command line o sa configuration file:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">OK</translation>
</message>
@@ -1533,14 +1563,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Kumpirmahin ang pag-reset ng mga opsyon</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Kailangan i-restart ang kliyente upang ma-activate ang mga pagbabago.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Ang kliyente ay papatayin. Nais mo bang magpatuloy?</translation>
</message>
<message>
@@ -1972,6 +2005,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Labas:</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Kopyahin and address</translation>
+ </message>
+ <message>
<source>&amp;Disconnect</source>
<translation type="unfinished">Idiskonekta</translation>
</message>
@@ -2107,6 +2145,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kopyahin ang URI</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopyahin and address</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopyahin ang &amp;label</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopyahin ang &amp;halaga</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">Hindi magawang ma-unlock ang walet.</translation>
</message>
@@ -2392,10 +2442,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Ang bayad na mas mataas sa %1 ay itinuturing na napakataas na bayad.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Ang hiling ng bayad ay nag-expire na.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2471,14 +2517,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Mensahe:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Ito ay isang unauthenticated na hiling ng bayad.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Ito ay isang authenticated na hiling ng bayad.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Mag-enter ng label para sa address na ito upang idagdag ito sa listahan ng mga gamit na address.</translation>
</message>
@@ -2486,11 +2524,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<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 type="unfinished">Mensahe na nakalakip sa bitcoin: URI na kung saan maiimbak kasama ang transaksyon para sa iyong sanggunian. Tandaan: Ang mensaheng ito ay hindi ipapadala sa network ng Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Magbayad Sa:</translation>
- </message>
- </context>
+</context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -2637,30 +2671,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">sumalungat sa isang transaksyon na may %1 pagkumpirma</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/hindi nakumpirma, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">nasa memory pool</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">wala sa memory pool</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">inabandona</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/hindi nakumpirma</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 pagkumpirma</translation>
</message>
<message>
@@ -2932,6 +2958,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Minimum na halaga</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopyahin and address</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopyahin ang &amp;label</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopyahin ang &amp;halaga</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">I-export ang Kasaysayan ng Transaksyon</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts
index cedecd674e..e680f22ad3 100644
--- a/src/qt/locale/bitcoin_fr.ts
+++ b/src/qt/locale/bitcoin_fr.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">Cliquer à droite pour modifier l’adresse ou l’étiquette</translation>
+ <translation type="unfinished">Clic droit pour modifier l'adresse ou l'étiquette</translation>
</message>
<message>
<source>Create a new address</source>
@@ -72,8 +72,8 @@
<message>
<source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
Signing is only possible with addresses of the type 'legacy'.</source>
- <translation type="unfinished">Ce sont vos adresses Bitcoin pour recevoir des paiements. Utilisez le bouton « Créer une nouvelle adresse de réception » dans l’onglet Recevoir afin de créer de nouvelles adresses.
-Il n’est possible de signer qu’avec les adresses de type « legacy ».</translation>
+ <translation type="unfinished">Il s'agit de vos adresses Bitcoin pour la réception des paiements. Utilisez le bouton "Créer une nouvelle adresse de réception" dans l'onglet "Recevoir" pour créer de nouvelles adresses.
+La signature n'est possible qu'avec les adresses de type "traditionnelles".</translation>
</message>
<message>
<source>&amp;Copy Address</source>
@@ -229,7 +229,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Warning: The Caps Lock key is on!</source>
- <translation type="unfinished">Avertissement : La touche Verr. Maj. est activée !</translation>
+ <translation type="unfinished">Avertissement : La touche Verr. Maj. est activée</translation>
</message>
</context>
<context>
@@ -246,8 +246,12 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Le fichier de configuration %1 est peut-être corrompu ou invalide.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
- <translation type="unfinished">Exception fugitive</translation>
+ <translation type="unfinished">Exception excessive</translation>
</message>
<message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
@@ -255,7 +259,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Internal error</source>
- <translation type="unfinished">Erreur interne</translation>
+ <translation type="unfinished">erreur interne</translation>
</message>
<message>
<source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
@@ -303,6 +307,10 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Saisir une adresse Bitcoin (p. ex. %1)</translation>
</message>
<message>
+ <source>Ctrl+W</source>
+ <translation type="unfinished">Ctrl-W</translation>
+ </message>
+ <message>
<source>Unroutable</source>
<translation type="unfinished">Non routable</translation>
</message>
@@ -364,7 +372,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform>%n seconde</numerusform>
+ <numerusform>%n second</numerusform>
<numerusform>%n secondes</numerusform>
</translation>
</message>
@@ -403,8 +411,8 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform>%n an</numerusform>
- <numerusform>%n ans</numerusform>
+ <numerusform>%n année</numerusform>
+ <numerusform>%n années</numerusform>
</translation>
</message>
<message>
@@ -444,7 +452,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <translation type="unfinished">La valeur -maxtxfee est très élevée ! Des frais aussi élevés pourraient être payés en une seule transaction.</translation>
+ <translation type="unfinished">La valeur -maxtxfee est très élevée. Des frais aussi élevés pourraient être payés en une seule transaction.</translation>
</message>
<message>
<source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
@@ -456,7 +464,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
- <translation type="unfinished">Impossible de mettre à niveau un porte-monnaie divisé non-HD de la version %i vers la version %i sans mettre à niveau pour prendre en charge la réserve de clés antérieure à la division. Veuillez utiliser la version %i ou ne pas indiquer de version.</translation>
+ <translation type="unfinished">Impossible de mettre à niveau un porte-monnaie divisé non-HD de la version %i vers la version %i sans mise à niveau pour prendre en charge la réserve de clés antérieure à la division. Veuillez utiliser la version %i ou ne pas indiquer de version.</translation>
</message>
<message>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
@@ -468,23 +476,23 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
- <translation type="unfinished">Erreur de lecture de %s : soit les données de la transaction manquent soit elles sont incorrectes. Réanalysez le porte-monnaie.</translation>
+ <translation type="unfinished">Erreur de lecture de %s : soit les données de la transaction manquent soit elles sont incorrectes. Réanalyse du porte-monnaie.</translation>
</message>
<message>
<source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
<translation type="unfinished">Erreur : L’enregistrement du format du fichier de vidage est incorrect. Est « %s », mais « format » est attendu. </translation>
</message>
<message>
+ <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source>
+ <translation type="unfinished">Erreur : L’enregistrement de l’identificateur du fichier de vidage est incorrect. Est « %s », mais « %s » est attendu. </translation>
+ </message>
+ <message>
<source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
<translation type="unfinished">Erreur : La version du fichier de vidage n’est pas prise en charge. Cette version de bitcoin-wallet ne prend en charge que les fichiers de vidage version 1. Le fichier de vidage obtenu est de la version %s.</translation>
</message>
<message>
<source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
- <translation type="unfinished">Erreur : les porte-monnaie hérités ne prennent en charge que les types d’adresse « legacy », « p2sh-segwit », et « bech32 ».</translation>
- </message>
- <message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Erreur : L’écoute des connexions entrantes a échoué (l’écoute a retourné l’erreur %s)</translation>
+ <translation type="unfinished">Erreur : les porte-monnaie hérités ne prennent en charge que les types d’adresse « legacy », « p2sh-segwit », et « bech32 »</translation>
</message>
<message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
@@ -531,8 +539,12 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">L’élagage est configuré au-dessous du minimum de %d Mio. Veuillez utiliser un nombre plus élevé.</translation>
</message>
<message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">Le mode Prune est incompatible avec -reindex-chainstate. Utilisez plutôt full -reindex.</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 type="unfinished">Élagage : la dernière synchronisation de porte-monnaie va par-delà les données élaguées. Vous devez -reindex (réindexer, télécharger de nouveau toute la chaîne de blocs en cas de nœud élagué)</translation>
+ <translation type="unfinished">Élagage : la dernière synchronisation de porte-monnaie va par-delà les données élaguées. Vous devez -reindex (réindexer, télécharger de nouveau toute la chaîne de blocs en cas de nœud élagué)</translation>
</message>
<message>
<source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
@@ -544,19 +556,19 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
- <translation type="unfinished">La base de données d’indexation des blocs comprend un « txindex » hérité. Pour libérer l’espace disque occupé, exécuter un -reindex complet ou ignorez cette erreur. Ce message d’erreur ne sera pas affiché de nouveau.</translation>
+ <translation type="unfinished">La base de données d’indexation des blocs comprend un « txindex » hérité. Pour libérer l’espace disque occupé, exécutez un -reindex complet ou ignorez cette erreur. Ce message d’erreur ne sera pas affiché de nouveau.</translation>
</message>
<message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
- <translation type="unfinished">Le montant transactionnel est trop bas pour être envoyé une fois que les frais ont été déduits</translation>
+ <translation type="unfinished">Le montant de la transaction est trop bas pour être envoyé une fois que les frais ont été déduits</translation>
</message>
<message>
<source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source>
- <translation type="unfinished">Cette erreur pourrait survenir si ce porte-monnaie n’avait pas été fermé proprement et s’il avait été chargé en dernier avec une nouvelle version de Berkeley DB. Si c’est le cas, veuillez utiliser le logiciel qui a chargé ce porte-monnaie en dernier.</translation>
+ <translation type="unfinished">Cette erreur pourrait survenir si ce porte-monnaie n’a pas été fermé proprement et s’il a été chargé en dernier avec une nouvelle version de Berkeley DB. Si c’est le cas, veuillez utiliser le logiciel qui a chargé ce porte-monnaie en dernier.</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 type="unfinished">Ceci est une préversion de test - son utilisation est entièrement à vos risques - ne pas l’utiliser pour miner ou pour des applications marchandes</translation>
+ <translation type="unfinished">Ceci est une préversion de test — son utilisation est entièrement à vos risques — ne l’utilisez pour miner ou pour des applications marchandes</translation>
</message>
<message>
<source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
@@ -579,12 +591,24 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Impossible de relire les blocs. Vous devrez reconstruire la base de données avec -reindex-chainstate.</translation>
</message>
<message>
+ <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source>
+ <translation type="unfinished">Le format de fichier porte-monnaie « %s » indiqué est inconnu. Veuillez soit indiquer « bdb » soit « sqlite ».</translation>
+ </message>
+ <message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">Format de base de données chainstate non pris en charge trouvé. Veuillez redémarrer avec -reindex-chainstate. Cela reconstruira la base de données chainstate.</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Portefeuille créé avec succès. Le type de portefeuille hérité est obsolète et la prise en charge de la création et de l'ouverture de portefeuilles hérités sera supprimée à l'avenir.</translation>
+ </message>
+ <message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
<translation type="unfinished">Avertissement : Le format du fichier de vidage de porte-monnaie « %s » ne correspond pas au format « %s » indiqué dans la ligne de commande.</translation>
</message>
<message>
<source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
- <translation type="unfinished">Avertissement : Des clés privées ont été détectées dans le porte-monnaie {%s}, dont les clés privées sont désactivées</translation>
+ <translation type="unfinished">Avertissement : Des clés privées ont été détectées dans le porte-monnaie {%s} avec des clés privées désactivées</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>
@@ -600,7 +624,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>%s is set very high!</source>
- <translation type="unfinished">La valeur %s est très élevée !</translation>
+ <translation type="unfinished">La valeur %s est très élevée</translation>
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
@@ -631,20 +655,100 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">La mise à niveau -txindex lancée par une version précédente ne peut pas être achevée. Redémarrez la version précédente ou exécutez un -reindex complet.</translation>
</message>
<message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s a demandé d’écouter sur le port %u. Ce port est considéré comme « mauvais » et il est par conséquent improbable que des pairs Bitcoin Core y soient connectés. Consulter doc/p2p-bad-ports.md pour plus de précisions et une liste complète.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">L'option -reindex-chainstate n'est pas compatible avec -blockfilterindex. Veuillez désactiver temporairement blockfilterindex lors de l'utilisation de -reindex-chainstate, ou remplacez -reindex-chainstate par -reindex pour reconstruire complètement tous les index.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">L'option -reindex-chainstate n'est pas compatible avec -coinstatsindex. Veuillez désactiver temporairement coinstatsindex lors de l'utilisation de -reindex-chainstate, ou remplacer -reindex-chainstate par -reindex pour reconstruire complètement tous les index.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">L'option -reindex-chainstate n'est pas compatible avec -txindex. Veuillez désactiver temporairement txindex lors de l'utilisation de -reindex-chainstate, ou remplacez -reindex-chainstate par -reindex pour reconstruire complètement tous les index.</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">Supposé valide : la dernière synchronisation du portefeuille va au-delà des données de bloc disponibles. Vous devez attendre la chaîne de validation en arrière-plan pour télécharger plus de blocs.</translation>
+ </message>
+ <message>
<source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
- <translation type="unfinished">Il est impossible de fournir des connexions particulières et en même temps demander à addrman de trouver les connexions sortantes.</translation>
+ <translation type="unfinished">Il est impossible d’indiquer des connexions précises et en même temps de demander à addrman de trouver les connexions sortantes.</translation>
</message>
<message>
<source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
<translation type="unfinished">Erreur de chargement de %s : le porte-monnaie signataire externe est chargé sans que la prise en charge de signataires externes soit compilée</translation>
</message>
<message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Erreur : les données du carnet d'adresses dans le portefeuille ne peuvent pas être identifiées comme appartenant à des portefeuilles migrés</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">Erreur : Descripteurs en double créés lors de la migration. Votre portefeuille est peut-être corrompu.</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Erreur : la transaction %s dans le portefeuille ne peut pas être identifiée comme appartenant aux portefeuilles migrés</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">Erreur : Impossible de produire des descripteurs pour cet ancien portefeuille. Assurez-vous d'abord que le portefeuille est déverrouillé</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Échec de renommage du fichier peers.dat invalide. Veuillez le déplacer ou le supprimer, puis réessayer.</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">Options incompatibles : -dnsseed=1 a été explicitement spécifié, mais -onlynet interdit les connexions à IPv4/IPv6</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">Connexions sortantes limitées à Tor (-onlynet=onion) mais le proxy pour atteindre le réseau Tor est explicitement interdit : -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">Connexions sortantes limitées à Tor (-onlynet=onion) mais le proxy pour atteindre le réseau Tor n'est pas fourni : aucun des -proxy, -onion ou -listenonion n'est donné</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">Descripteur non reconnu trouvé. Chargement du portefeuille %s
+
+Le portefeuille a peut-être été créé sur une version plus récente.
+Veuillez essayer d'exécuter la dernière version du logiciel.
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">Niveau de journalisation spécifique à une catégorie non pris en charge -loglevel=%s. -loglevel=&lt;category&gt;:&lt;loglevel&gt; attendu. Catégories valides : %s. Niveaux de journalisation valides : %s.</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+Impossible de nettoyer la migration en erreur</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Impossible de restaurer la sauvegarde du portefeuille.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">Paramètre de configuration pour %s qui n’est appliqué sur le réseau %s que s’il se trouve dans la section [%s].</translation>
</message>
<message>
<source>Copyright (C) %i-%i</source>
- <translation type="unfinished">Tous droits réservés (C) %i-%i</translation>
+ <translation type="unfinished">Tous droits réservés © %i à %i</translation>
</message>
<message>
<source>Corrupted block database detected</source>
@@ -660,7 +764,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Disk space is too low!</source>
- <translation type="unfinished">L’espace disque est trop faible !</translation>
+ <translation type="unfinished">L’espace disque est trop faible</translation>
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
@@ -672,7 +776,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Dump file %s does not exist.</source>
- <translation type="unfinished">Le fichier de vidage %s n’existe pas</translation>
+ <translation type="unfinished">Le fichier de vidage %s n’existe pas.</translation>
</message>
<message>
<source>Error creating %s</source>
@@ -684,7 +788,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Error initializing wallet database environment %s!</source>
- <translation type="unfinished">Erreur d’initialisation de l’environnement de la base de données du porte-monnaie %s !</translation>
+ <translation type="unfinished">Erreur d’initialisation de l’environnement de la base de données du porte-monnaie %s </translation>
</message>
<message>
<source>Error loading %s</source>
@@ -712,15 +816,19 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Error reading from database, shutting down.</source>
- <translation type="unfinished">Erreur de lecture de la base de données, fermeture en cours.</translation>
+ <translation type="unfinished">Erreur de lecture de la base de données, fermeture en cours</translation>
</message>
<message>
<source>Error reading next record from wallet database</source>
<translation type="unfinished">Erreur de lecture de l’enregistrement suivant de la base de données du porte-monnaie</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Erreur de mise à niveau de la base de données d’état de la chaîne</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">Erreur : Impossible d'ajouter watchonly tx au portefeuille watchonly</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">Erreur : impossible de supprimer les transactions surveillées uniquement</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
@@ -735,6 +843,10 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Erreur : La somme de contrôle du fichier de vidage ne correspond pas. Calculée %s, attendue %s</translation>
</message>
<message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">Erreur : Échec de la création d'un nouveau portefeuille watchonly</translation>
+ </message>
+ <message>
<source>Error: Got key that was not hex: %s</source>
<translation type="unfinished">Erreur : La clé obtenue n’était pas hexadécimale : %s</translation>
</message>
@@ -752,19 +864,47 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Error: No %s addresses available.</source>
- <translation type="unfinished">Erreur : Aucune adresse %s n’est disponible</translation>
+ <translation type="unfinished">Erreur : Aucune adresse %s n’est disponible.</translation>
+ </message>
+ <message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">Erreur : Tous les txs watchonly n'ont pas pu être supprimés</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">Erreur : ce portefeuille utilise déjà SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">Erreur : Ce portefeuille est déjà un portefeuille de descripteur</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">Erreur : Impossible de commencer à lire tous les enregistrements de la base de données</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">Erreur : impossible de faire une sauvegarde de votre portefeuille</translation>
</message>
<message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">Erreur : Impossible d’analyser la version %u en tant que uint32_t</translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">Erreur : impossible de lire tous les enregistrement dans la base de données</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">Erreur : Impossible de supprimer les données du carnet d'adresses watchonly</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
<translation type="unfinished">Erreur : Impossible d’écrire l’enregistrement dans le nouveau porte-monnaie</translation>
</message>
<message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
- <translation type="unfinished">Échec d'écoute sur n’importe quel port. Utiliser -listen=0 si vous voulez le faire.</translation>
+ <translation type="unfinished">Échec d'écoute sur tous les ports. Si cela est voulu, utiliser -listen=0.</translation>
</message>
<message>
<source>Failed to rescan the wallet during initialization</source>
@@ -791,6 +931,10 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Bloc de genèse incorrect ou introuvable. Mauvais datadir pour le réseau ?</translation>
</message>
<message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation type="unfinished">Échec d’initialisation du test de cohérence. %s est en cours de fermeture.</translation>
+ </message>
+ <message>
<source>Input not found or already spent</source>
<translation type="unfinished">L’entrée est introuvable ou a déjà été dépensée</translation>
</message>
@@ -800,7 +944,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Invalid -i2psam address or hostname: '%s'</source>
- <translation type="unfinished">L’adresse ou le nom d’hôte -i2psam est invalide :« %s »</translation>
+ <translation type="unfinished">L’adresse ou le nom d’hôte -i2psam est invalide : « %s »</translation>
</message>
<message>
<source>Invalid -onion address or hostname: '%s'</source>
@@ -828,15 +972,19 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
- <translation type="unfinished">Le montant est invalide pour -paytxfee=&lt;montant&gt; : « %s » (doit être au moins %s)</translation>
+ <translation type="unfinished">Le montant est invalide pour -paytxfee=&lt;amount&gt; : « %s » (doit être au moins %s)</translation>
</message>
<message>
<source>Invalid netmask specified in -whitelist: '%s'</source>
<translation type="unfinished">Le masque réseau indiqué dans -whitelist est invalide : « %s »</translation>
</message>
<message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">L'écoute des connexions entrantes a échoué (l'écoute a renvoyé une erreur %s)</translation>
+ </message>
+ <message>
<source>Loading P2P addresses…</source>
- <translation type="unfinished">Chargement des adresses P2P…</translation>
+ <translation type="unfinished">Chargement des adresses P2P…</translation>
</message>
<message>
<source>Loading banlist…</source>
@@ -860,31 +1008,23 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Need to specify a port with -whitebind: '%s'</source>
- <translation type="unfinished">Un port doit être précisé avec -whitebind : « %s »</translation>
+ <translation type="unfinished">Un port doit être indiqué avec -whitebind : « %s »</translation>
</message>
<message>
<source>No addresses available</source>
<translation type="unfinished">Aucune adresse n’est disponible</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Aucun serveur mandataire n’est indiqué. Utilisez -proxy=&lt;ip&gt; ou -proxy=&lt;ip:port&gt;</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">Trop peu de descripteurs de fichiers sont disponibles.</translation>
</message>
<message>
<source>Prune cannot be configured with a negative value.</source>
- <translation type="unfinished">L’élagage ne peut pas être configuré avec une valeur négative.</translation>
- </message>
- <message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Le mode élagage n’est pas compatible avec -coinstatsindex.</translation>
+ <translation type="unfinished">L’élagage ne peut pas être configuré avec une valeur négative</translation>
</message>
<message>
<source>Prune mode is incompatible with -txindex.</source>
- <translation type="unfinished">Le mode élagage n’est pas compatible avec -txindex.</translation>
+ <translation type="unfinished">Le mode élagage n’est pas compatible avec -txindex</translation>
</message>
<message>
<source>Pruning blockstore…</source>
@@ -916,11 +1056,11 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source>
- <translation type="unfinished">SQLiteDatabase : l’ID de l’application est inattendu. %u était attendu, %u été retourné</translation>
+ <translation type="unfinished">SQLiteDatabase : l’ID de l’application est inattendu. %u attendu, %u retourné</translation>
</message>
<message>
<source>Section [%s] is not recognized.</source>
- <translation type="unfinished">La section [%s] n’est pas reconnue.</translation>
+ <translation type="unfinished">La section [%s] n’est pas reconnue</translation>
</message>
<message>
<source>Signing transaction failed</source>
@@ -940,7 +1080,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Specified blocks directory "%s" does not exist.</source>
- <translation type="unfinished">Le répertoire des blocs indiqué « %s » n’existe pas.</translation>
+ <translation type="unfinished">Le répertoire des blocs indiqué « %s » n’existe pas</translation>
</message>
<message>
<source>Starting network threads…</source>
@@ -952,7 +1092,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>The specified config file %s does not exist</source>
- <translation type="unfinished">Le fichier de configuration %s n’existe pas</translation>
+ <translation type="unfinished">Le fichier de configuration indiqué %s n’existe pas</translation>
</message>
<message>
<source>The transaction amount is too small to pay the fee</source>
@@ -1003,18 +1143,26 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">La transaction est trop grosse</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">Impossible d'allouer de la mémoire pour -maxsigcachesize : '%s' MB</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
- <translation type="unfinished">Impossible de se lier à %s sur cet ordinateur (bind a retourné l’erreur %s)</translation>
+ <translation type="unfinished">Impossible de se lier à %s sur cet ordinateur (la liaison a retourné l’erreur %s)</translation>
</message>
<message>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
- <translation type="unfinished">Impossible de se lier à %s sur cet ordinateur. %s fonctionne probablement déjà.</translation>
+ <translation type="unfinished">Impossible de se lier à %s sur cet ordinateur. %s fonctionne probablement déjà</translation>
</message>
<message>
<source>Unable to create the PID file '%s': %s</source>
<translation type="unfinished">Impossible de créer le fichier PID « %s » : %s</translation>
</message>
<message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">Impossible de trouver UTXO pour l'entrée externe</translation>
+ </message>
+ <message>
<source>Unable to generate initial keys</source>
<translation type="unfinished">Impossible de générer les clés initiales</translation>
</message>
@@ -1035,16 +1183,20 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Impossible de démarrer le serveur HTTP. Consulter le journal de débogage pour plus de précisions.</translation>
</message>
<message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">Impossible de décharger le portefeuille avant de migrer</translation>
+ </message>
+ <message>
<source>Unknown -blockfilterindex value %s.</source>
- <translation type="unfinished">Valeur -blockfilterindex inconnue %s.</translation>
+ <translation type="unfinished">La valeur -blockfilterindex %s est inconnue.</translation>
</message>
<message>
<source>Unknown address type '%s'</source>
- <translation type="unfinished">Type d’adresse inconnu « %s »</translation>
+ <translation type="unfinished">Le type d’adresse « %s » est inconnu</translation>
</message>
<message>
<source>Unknown change type '%s'</source>
- <translation type="unfinished">Le type de monnaie est inconnu « %s »</translation>
+ <translation type="unfinished">Le type de monnaie « %s » est inconnu</translation>
</message>
<message>
<source>Unknown network specified in -onlynet: '%s'</source>
@@ -1055,16 +1207,16 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Les nouvelles règles inconnues sont activées (versionbit %i)</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">La catégorie de journalisation n’est pas prise en charge %s=%s.</translation>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">Niveau de journalisation global non pris en charge -loglevel=%s. Valeurs valides : %s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Mise à niveau de la base de données UTXO</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">La catégorie de journalisation %s=%s n’est pas prise en charge</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
- <translation type="unfinished">Le commentaire de l’agent utilisateur (%s) comporte des caractères dangereux.</translation>
+ <translation type="unfinished">Le commentaire de l’agent utilisateur (%s) comporte des caractères dangereux</translation>
</message>
<message>
<source>Verifying blocks…</source>
@@ -1172,7 +1324,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>&amp;Backup Wallet…</source>
- <translation type="unfinished">&amp;auvegarder le porte-monnaie…</translation>
+ <translation type="unfinished">&amp;Sauvegarder le porte-monnaie…</translation>
</message>
<message>
<source>&amp;Change Passphrase…</source>
@@ -1184,7 +1336,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation type="unfinished">Signer les messages avec vos adresses Bitcoin pour prouver que vous les détenez</translation>
+ <translation type="unfinished">Signer les messages avec vos adresses Bitcoin pour prouver que vous les détenez</translation>
</message>
<message>
<source>&amp;Verify message…</source>
@@ -1196,7 +1348,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>&amp;Load PSBT from file…</source>
- <translation type="unfinished">&amp;Charger une TBSP d’un fichier…</translation>
+ <translation type="unfinished">&amp;Charger la TBSP d’un fichier…</translation>
</message>
<message>
<source>Open &amp;URI…</source>
@@ -1204,15 +1356,15 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Close Wallet…</source>
- <translation type="unfinished">Fermer le portefeuille...</translation>
+ <translation type="unfinished">Fermer le porte-monnaie…</translation>
</message>
<message>
<source>Create Wallet…</source>
- <translation type="unfinished">Créer le portefeuille...</translation>
+ <translation type="unfinished">Créer un porte-monnaie…</translation>
</message>
<message>
<source>Close All Wallets…</source>
- <translation type="unfinished">Fermer tous les portefeuilles...</translation>
+ <translation type="unfinished">Fermer tous les porte-monnaie…</translation>
</message>
<message>
<source>&amp;File</source>
@@ -1232,7 +1384,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Syncing Headers (%1%)…</source>
- <translation type="unfinished">Synchronisation des en-têtes (%1)…</translation>
+ <translation type="unfinished">Synchronisation des en-têtes (%1%)…</translation>
</message>
<message>
<source>Synchronizing with network…</source>
@@ -1273,8 +1425,8 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform>%n bloc d’historique transactionnel a été traité.</numerusform>
- <numerusform>%n blocs d’historique transactionnel ont été traités.</numerusform>
+ <numerusform>%n bloc traité de l'historique des transactions.</numerusform>
+ <numerusform>%n bloc(s) traité(s) de l'historique des transactions.</numerusform>
</translation>
</message>
<message>
@@ -1283,7 +1435,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Catching up…</source>
- <translation type="unfinished">Rattrapage en cours…</translation>
+ <translation type="unfinished">Rattrapage…</translation>
</message>
<message>
<source>Last received block was generated %1 ago.</source>
@@ -1354,12 +1506,22 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Fermer le porte-monnaie</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Restaurer un portefeuille...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Restaurer un portefeuille depuis un fichier de récupération</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Fermer tous les porte-monnaie</translation>
</message>
<message>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
- <translation type="unfinished">Afficher le message d’aide de %1 pour obtenir la liste des options possibles de ligne de commande Bitcoin</translation>
+ <translation type="unfinished">Afficher le message d’aide de %1 pour obtenir la liste des options possibles en ligne de commande Bitcoin</translation>
</message>
<message>
<source>&amp;Mask values</source>
@@ -1378,6 +1540,26 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Aucun porte-monnaie n’est disponible</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Données du porte-monnaie</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Charger la Sauvegarde du Portefeuille</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Restaurer le portefeuille</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nom du porte-monnaie</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Fenêtre</translation>
</message>
@@ -1405,8 +1587,8 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform>%n connexion active avec le réseau Bitcoin.</numerusform>
- <numerusform>%n connexions actives avec le réseau Bitcoin.</numerusform>
+ <numerusform>%n connexion active au réseau Bitcoin.</numerusform>
+ <numerusform>%n connexion(s) active(s) au réseau Bitcoin.</numerusform>
</translation>
</message>
<message>
@@ -1430,6 +1612,10 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Activer l’activité réseau</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Pré-synchronisation des en-têtes (%1%)...</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Erreur : %1</translation>
</message>
@@ -1684,6 +1870,10 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<source>Can't list signers</source>
<translation type="unfinished">Impossible de lister les signataires</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Trop de signataires externes trouvés</translation>
+ </message>
</context>
<context>
<name>LoadWalletsActivity</name>
@@ -1724,6 +1914,34 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Restaurer le portefeuille</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Restauration du Portefeuille &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Échec de la restauration du portefeuille</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Avertissement de restauration du portefeuille</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Message de restauration du portefeuille</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1898,13 +2116,26 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</context>
<context>
<name>Intro</name>
- <message>
- <source>%1 GB of space available</source>
- <translation type="unfinished">%1 Go d’espace disponible</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n Go d’espace disponible</numerusform>
+ <numerusform>%n Go d’espace disponible</numerusform>
+ </translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(sur %1 Go nécessaires)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(de %n GB néccesaire)</numerusform>
+ <numerusform>(de %n GB neccesaires)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform> (%n GB nécessaire pour la chaîne complète)</numerusform>
+ <numerusform>(%n GB necessaires pour la chaîne complète)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1918,8 +2149,8 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform>(suffisant pour restaurer les sauvegardes âgées de %n jour)</numerusform>
- <numerusform>(suffisant pour restaurer les sauvegardes âgées de %n jours)</numerusform>
+ <numerusform>(suffisant pour restaurer les sauvegardes %n jour vieux)</numerusform>
+ <numerusform>(suffisant pour restaurer les sauvegardes %n jours vieux)</numerusform>
</translation>
</message>
<message>
@@ -1951,10 +2182,6 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Comme le logiciel est lancé pour la première fois, vous pouvez choisir où %1 stockera ses données.</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 type="unfinished">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>Limit block chain storage to</source>
<translation type="unfinished">Limiter l’espace de stockage de chaîne de blocs à</translation>
</message>
@@ -1971,6 +2198,10 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Cette synchronisation initiale est très exigeante et pourrait exposer des problèmes matériels dans votre ordinateur passés inaperçus auparavant. Chaque fois que vous exécuterez %1, le téléchargement reprendra où il s’était arrêté.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Lorsque vous cliquez sur OK, %1 commencera à télécharger et à traiter la chaîne de blocs %4 complète (%2 GB) en commençant par les premières transactions lors %3 du %4 lancement initial.</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 type="unfinished">Si vous avez choisi de limiter le stockage de la chaîne de blocs (élagage), les données historiques doivent quand même être téléchargées et traitées, mais seront supprimées par la suite pour minimiser l’utilisation de votre espace disque.</translation>
</message>
@@ -2025,7 +2256,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Unknown…</source>
- <translation type="unfinished">Inconnus…</translation>
+ <translation type="unfinished">Inconnu…</translation>
</message>
<message>
<source>calculating…</source>
@@ -2063,6 +2294,10 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Inconnu. Synchronisation des en-têtes (%1, %2 %)…</translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Inconnue. En-têtes de pré-synchronisation (%1, %2%)…</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -2119,6 +2354,10 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">Quand la fenêtre est fermée, la réduire au lieu de quitter l’application. Si cette option est activée, l’application ne sera fermée qu’en sélectionnant Quitter dans le menu.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Les options définies dans cette boîte de dialogue sont remplacées par la ligne de commande :</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Ouvrir le fichier de configuration %1 du répertoire de travail.</translation>
</message>
@@ -2336,7 +2575,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
- <translation type="unfinished">Utiliser un mandataire SOCKS&amp;5 séparé pour atteindre les pairs par les services oignon de Tor.</translation>
+ <translation type="unfinished">Utiliser un mandataire SOCKS&amp;5 séparé pour atteindre les pairs par les services oignon de Tor :</translation>
</message>
<message>
<source>Monospaced font in the Overview tab:</source>
@@ -2351,10 +2590,6 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
<translation type="unfinished">correspondance la plus proche « %1 »</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Les options définies dans cette boîte de dialogue sont remplacées par la ligne de commande ou par le fichier de configuration :</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">&amp;Valider</translation>
</message>
@@ -2377,14 +2612,22 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirmer la réinitialisation des options</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Le redémarrage du client est exigé pour activer les changements.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Les paramètres courants seront sauvegardés à "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Le client sera arrêté. Voulez-vous continuer ?</translation>
</message>
<message>
@@ -2423,6 +2666,13 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Impossible de lire le paramètre "%1", %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2553,7 +2803,7 @@ Il n’est possible de signer qu’avec les adresses de type « legacy ».</tr
</message>
<message>
<source>Unknown error processing transaction.</source>
- <translation type="unfinished">Erreur inconnue lors de traitement de la transaction.</translation>
+ <translation type="unfinished">Erreur inconnue lors de traitement de la transaction</translation>
</message>
<message>
<source>Transaction broadcast successfully! Transaction ID: %1</source>
@@ -2659,7 +2909,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
- <translation type="unfinished">L’URI ne peut pas être analysée ! Cela peut être causé par une adresse Bitcoin invalide ou par des paramètres d’URI mal formés.</translation>
+ <translation type="unfinished">L’URI ne peut pas être analysée. Cela peut être causé par une adresse Bitcoin invalide ou par des paramètres d’URI mal formés.</translation>
</message>
<message>
<source>Payment request file handling</source>
@@ -2679,6 +2929,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">Pair</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Âge</translation>
+ </message>
+ <message>
<source>Sent</source>
<extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment>
<translation type="unfinished">Envoyé</translation>
@@ -2865,29 +3120,32 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Whether we relay addresses to this peer.</source>
- <extracomment>Tooltip text for the Address Relay field in the peer details area.</extracomment>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Reliez ou non des adresses à ce pair.</translation>
</message>
<message>
<source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Relais d’adresses</translation>
</message>
<message>
- <source>Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Processed field in the peer details area.</extracomment>
- <translation type="unfinished">Nombre total d’adresses traitées, excluant celles abandonnées en raison de la limite de débit.</translation>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Le nombre total d'adresses reçues de cet homologue qui ont été traitées (exclut les adresses qui ont été supprimées en raison de la limitation du débit).</translation>
</message>
<message>
- <source>Addresses Processed</source>
- <translation type="unfinished">Adresses traitées</translation>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Le nombre total d'adresses reçues de cet homologue qui ont été supprimées (non traitées) en raison de la limitation du débit.</translation>
</message>
<message>
- <source>Total number of addresses dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area.</extracomment>
- <translation type="unfinished">Nombre total d’adresses abandonnées en raison de la limite de débit.</translation>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Adresses traitées</translation>
</message>
<message>
<source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
<translation type="unfinished">Adresses ciblées par la limite de débit</translation>
</message>
<message>
@@ -2932,7 +3190,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Wants Tx Relay</source>
- <translation type="unfinished">Veut Tx relai</translation>
+ <translation type="unfinished">Veut relayer les transactions</translation>
</message>
<message>
<source>High bandwidth BIP152 compact block relay: %1</source>
@@ -3358,7 +3616,7 @@ Pour plus de précisions sur cette console, tapez %6.
</message>
<message>
<source>Insufficient funds!</source>
- <translation type="unfinished">Les fonds sont insuffisants !</translation>
+ <translation type="unfinished">Les fonds sont insuffisants</translation>
</message>
<message>
<source>Quantity:</source>
@@ -3663,15 +3921,18 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi
</message>
<message>
<source>Transaction creation failed!</source>
- <translation type="unfinished">Échec de création de la transaction !</translation>
+ <translation type="unfinished">Échec de création de la transaction</translation>
</message>
<message>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Des frais supérieurs à %1 sont considérés comme ridiculement élevés.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">La demande de paiement a expiré.</translation>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation type="unfinished">
+ <numerusform>Estimation pour commencer la confirmation dans le %n bloc.</numerusform>
+ <numerusform>Estimation pour commencer la confirmation dans le(s) %n bloc(s).</numerusform>
+ </translation>
</message>
<message>
<source>Warning: Invalid Bitcoin address</source>
@@ -3710,7 +3971,7 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi
</message>
<message>
<source>Choose previously used address</source>
- <translation type="unfinished">Choisir une adresse déjà utilisée</translation>
+ <translation type="unfinished">Choisir une adresse utilisée précédemment</translation>
</message>
<message>
<source>The Bitcoin address to send the payment to</source>
@@ -3718,7 +3979,7 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi
</message>
<message>
<source>Paste address from clipboard</source>
- <translation type="unfinished">Coller l’adresse du presse-papiers</translation>
+ <translation type="unfinished">Collez l’adresse du presse-papiers</translation>
</message>
<message>
<source>Remove this entry</source>
@@ -3745,14 +4006,6 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi
<translation type="unfinished">Message :</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Cette demande de paiement n’est pas authentifiée.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Cette demande de paiement est authentifiée.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Saisir une étiquette pour cette adresse afin de l’ajouter à la liste d’adresses utilisées</translation>
</message>
@@ -3760,14 +4013,6 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi
<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 type="unfinished">Un message qui était joint à l’URI bitcoin: et qui sera stocké avec la transaction pour référence. Note : Ce message ne sera pas envoyé par le réseau Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Payer à :</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Mémo :</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3804,7 +4049,7 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi
</message>
<message>
<source>Paste address from clipboard</source>
- <translation type="unfinished">Coller l’adresse du presse-papiers</translation>
+ <translation type="unfinished">Collez l’adresse du presse-papiers</translation>
</message>
<message>
<source>Enter the message you want to sign here</source>
@@ -3927,7 +4172,7 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi
</message>
<message>
<source>press q to shutdown</source>
- <translation type="unfinished">appuyer sur q pour fermer</translation>
+ <translation type="unfinished">Appuyer sur q pour fermer</translation>
</message>
</context>
<context>
@@ -3941,26 +4186,27 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">est en conflit avec une transaction ayant %1 confirmations</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/non confirmées, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">dans la réserve de mémoire</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/non confirmé, dans le pool de mémoire</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">pas dans la réserve de mémoire</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/non confirmé, pas dans le pool de mémoire</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">abandonnée</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/non confirmée</translation>
</message>
<message>
@@ -4002,8 +4248,8 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform>arrivera à maturité dans %n bloc</numerusform>
- <numerusform>arrivera à maturité dans %n blocs</numerusform>
+ <numerusform>matures dans %n bloc supplémentaire</numerusform>
+ <numerusform>matures dans %n blocs supplémentaires</numerusform>
</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_ga.ts b/src/qt/locale/bitcoin_ga.ts
index 3b9c3fdceb..16bd74831d 100644
--- a/src/qt/locale/bitcoin_ga.ts
+++ b/src/qt/locale/bitcoin_ga.ts
@@ -381,10 +381,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<translation type="unfinished">Earráid ag léamh %s! Léigh gach eochair i gceart, ach d’fhéadfadh sonraí idirbhirt nó iontrálacha leabhar seoltaí a bheidh in easnamh nó mícheart.</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Earráid: Theip ar éisteacht le naisc teacht-isteach (chuir éist earráid %s ar ais)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Theip ar mheastachán táillí. Tá fallbackfee díchumasaithe. Fan cúpla bloc nó cumasaigh -fallbackfee.</translation>
</message>
@@ -557,10 +553,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<translation type="unfinished">Earráid ag léamh ón mbunachar sonraí, ag múchadh.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Earráid ag uasghrádú bunachar sonraí chainstate</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Earráid: Tá spás ar diosca íseal do %s</translation>
</message>
@@ -637,10 +629,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<translation type="unfinished">Is gá port a shainiú le -whitebind: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Níl seachfhreastalaí sainithe. Úsáid -proxy=&lt;ip&gt; nó -proxy=&lt;ip:port&gt;.</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">Níl dóthain tuairisceoirí comhaid ar fáil.</translation>
</message>
@@ -785,10 +773,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<translation type="unfinished">Catagóir logáil gan tacaíocht %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Ag uasghrádú bunachar sonraí UTXO</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Tá carachtair neamhshábháilte i nóta tráchta (%s) Gníomhaire Úsáideora.</translation>
</message>
@@ -1017,6 +1001,11 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<translation type="unfinished">Níl aon sparán ar fáil</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Ainm Sparán</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Fuinneog</translation>
</message>
@@ -1455,6 +1444,30 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(de %n GB teastáil)</numerusform>
+ <numerusform>(de %n GB teastáil)</numerusform>
+ <numerusform>(de %n GB teastáil)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB teastáil do slabhra iomlán)</numerusform>
+ <numerusform>(%n GB teastáil do slabhra iomlán)</numerusform>
+ <numerusform>(%n GB teastáil do slabhra iomlán)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Ar a laghad stórálfar %1 GB de shonraí sa comhadlann seo, agus fásfaidh sé le himeacht ama.</translation>
@@ -1501,10 +1514,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<translation type="unfinished">Mar gurb é seo an chéad uair a lainseáil an clár, is féidir leat a roghnú cá stórálfaidh %1 a chuid sonraí.</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 type="unfinished">Nuair a chliceálann tú Togha, tosóidh %1 ag íoslódáil agus ag próiseáil an blocshlabhra iomlán %4 (%2GB) ag tosú leis na hidirbhearta is luaithe %3 nuair a lainseáil %4 i dtosach.</translation>
- </message>
- <message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">Teastaíonn an blocshlabhra iomlán a íoslódáil arís chun an socrú seo a fhilleadh. Tá sé níos sciobtha an slabhra iomlán a íoslódáil ar dtús agus é a bhearradh níos déanaí. Díchumasaíodh roinnt ardgnéithe.</translation>
</message>
@@ -1777,10 +1786,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<translation type="unfinished">Úsáid seachfhreastalaí SOCKS5 ar leith chun sroicheadh piaraí trí sheirbhísí Tor oinniún:</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Tá na roghanna socraithe sa dialóg seo sáraithe ag líne na n-orduithe nó sa chomhad cumraíochta:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">&amp;Togha</translation>
</message>
@@ -1798,14 +1803,17 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Deimhnigh athshocrú roghanna</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Atosú cliant ag teastáil chun athruithe a ghníomhachtú.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Múchfar an cliant. Ar mhaith leat dul ar aghaidh?</translation>
</message>
<message>
@@ -2827,10 +2835,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Meastar gur táille áiféiseach ard í táille níos airde ná %1.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Iarratas íocaíocht éagtha.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2911,14 +2915,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<translation type="unfinished">Teachtaireacht:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Iarratas íocaíocht neamhfíordheimhnithe é seo.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Iarratas íocaíocht fíordheimhnithe é seo.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Iontráil lipéad don seoladh seo chun é a chur le liosta na seoltaí úsáidte</translation>
</message>
@@ -2926,14 +2922,6 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<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 type="unfinished">Teachtaireacht a bhí ceangailte leis an bitcoin: URI a stórálfar leis an idirbheart le haghaidh do thagairt. Nóta: Ní sheolfar an teachtaireacht seo thar líonra Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Ãoc chuig:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Meamram:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3093,30 +3081,22 @@ Ní féidir síniú ach le seoltaí 'oidhreachta'.</translation>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">faoi choimhlint le idirbheart le %1 dearbhuithe</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/neamhdheimhnithe, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">i linn cuimhne</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">ní i linn cuimhne</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">tréigthe</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/neamhdheimhnithe</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 dearbhuithe</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_gd.ts b/src/qt/locale/bitcoin_gd.ts
index 53e45eff30..63a59d6fe8 100644
--- a/src/qt/locale/bitcoin_gd.ts
+++ b/src/qt/locale/bitcoin_gd.ts
@@ -113,6 +113,11 @@
<source>Information</source>
<translation type="unfinished">Fiosrachadh</translation>
</message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Ainm Wallet</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
@@ -141,6 +146,33 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_gl.ts b/src/qt/locale/bitcoin_gl.ts
index c032ef7407..72cf96a006 100644
--- a/src/qt/locale/bitcoin_gl.ts
+++ b/src/qt/locale/bitcoin_gl.ts
@@ -706,6 +706,27 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -856,6 +877,7 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirmar opcións de restaurar</translation>
</message>
<message>
@@ -1221,10 +1243,6 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation>
<source>The total exceeds your balance when the %1 transaction fee is included.</source>
<translation type="unfinished">O total sobrepasa o teu balance cando se inclúe a tarifa de transacción %1.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Solicitude de pagamento expirada.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -1279,10 +1297,6 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Introduce unha etiqueta para esta dirección para engadila á listaxe de direccións empregadas</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Pagar A:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -1403,10 +1417,12 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation>
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/sen confirmar</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 confirmacións</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_gl_ES.ts b/src/qt/locale/bitcoin_gl_ES.ts
index 87277251d1..807e8870b9 100644
--- a/src/qt/locale/bitcoin_gl_ES.ts
+++ b/src/qt/locale/bitcoin_gl_ES.ts
@@ -233,11 +233,22 @@
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">Erro interno</translation>
+ </message>
+ </context>
+<context>
<name>QObject</name>
<message>
<source>Amount</source>
<translation type="unfinished">Cantidade</translation>
</message>
+ <message>
+ <source>Internal</source>
+ <translation type="unfinished">Interno</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
@@ -332,6 +343,10 @@
<translation type="unfinished">Crear unha nova carteira</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimizar</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Carteira:</translation>
</message>
@@ -365,6 +380,10 @@
<translation type="unfinished">&amp;Recibir</translation>
</message>
<message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Opcións...</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">Encripta as claves privadas que pertencen á túa carteira</translation>
</message>
@@ -373,6 +392,10 @@
<translation type="unfinished">Asina mensaxes cos teus enderezos de Bitcoin para probar que che pertencen</translation>
</message>
<message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;Verifica a mensaxe...</translation>
+ </message>
+ <message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
<translation type="unfinished">Verifica mensaxes para asegurar que foron asinados cos enderezos de Bitcoin especificados</translation>
</message>
@@ -484,6 +507,11 @@
<translation type="unfinished">Non hai carteiras dispoñibles</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nome da Carteira</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Xanela</translation>
</message>
@@ -571,7 +599,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation type="unfinished">A carteira está &lt;b&gt;encriptada&lt;/b&gt; e actualmente &lt;b&gt;bloqueada&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">Mensaxe orixinal:</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -643,6 +675,10 @@
<translation type="unfinished">Copiar cantidade</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Copiar enderezo</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Copiar cantidade</translation>
</message>
@@ -749,6 +785,10 @@
<translation type="unfinished">Encriptar Carteira</translation>
</message>
<message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">Opcións avanzadas</translation>
+ </message>
+ <message>
<source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
<translation type="unfinished">Desactiva as claves privadas para esta carteira. Carteiras con claves privadas desactivadas non terán claves privadas e polo tanto non poderan ter unha semente HD ou claves privadas importadas. Esto é ideal para carteiras de solo visualización.</translation>
</message>
@@ -823,6 +863,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -832,15 +893,30 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Unknown…</source>
+ <translation type="unfinished">Descoñecido...</translation>
+ </message>
+ </context>
+<context>
<name>OptionsDialog</name>
<message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Xanela</translation>
</message>
+ <message>
+ <source>Continue</source>
+ <translation type="unfinished">Continuar</translation>
+ </message>
</context>
<context>
<name>PSBTOperationsDialog</name>
<message>
+ <source>Save…</source>
+ <translation type="unfinished">Gardar...</translation>
+ </message>
+ <message>
<source>Close</source>
<translation type="unfinished">Pechar</translation>
</message>
@@ -854,15 +930,31 @@
</message>
</context>
<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Gardar Imaxe...</translation>
+ </message>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>Node window</source>
<translation type="unfinished">Xanela de Nodo</translation>
</message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Copiar enderezo</translation>
+ </message>
</context>
<context>
<name>ReceiveCoinsDialog</name>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Copiar enderezo</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">Non se puido desbloquear a carteira.</translation>
</message>
@@ -877,6 +969,10 @@
<source>Wallet:</source>
<translation type="unfinished">Carteira:</translation>
</message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Gardar Imaxe...</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -995,6 +1091,10 @@
<context>
<name>TransactionView</name>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Copiar enderezo</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">Confirmada</translation>
</message>
diff --git a/src/qt/locale/bitcoin_gu.ts b/src/qt/locale/bitcoin_gu.ts
index 857c06e12d..c2f50e5b77 100644
--- a/src/qt/locale/bitcoin_gu.ts
+++ b/src/qt/locale/bitcoin_gu.ts
@@ -92,6 +92,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">સરનામાં ની સૂચિ નો નિકાસ કરો</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">અલà«àªªàªµàª¿àª°àª¾àª®àª¥à«€ વિભાજિત ફાઇલ</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation type="unfinished">નિકાસ ની પà«àª°à«àª°àª¾àª•à«àª°àª¿àª¯àª¾ નિષà«àª«àª³ ગયેલ છે</translation>
</message>
@@ -239,6 +244,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -304,6 +330,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>TransactionView</name>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">અલà«àªªàªµàª¿àª°àª¾àª®àª¥à«€ વિભાજિત ફાઇલ</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">ચિઠà«àª à«€</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ha.ts b/src/qt/locale/bitcoin_ha.ts
new file mode 100644
index 0000000000..bf0bafd74d
--- /dev/null
+++ b/src/qt/locale/bitcoin_ha.ts
@@ -0,0 +1,273 @@
+<TS version="2.1" language="ha">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation type="unfinished">Danna dama don gyara adireshi ko labil</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation type="unfinished">Ƙirƙiri sabon adireshi</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation type="unfinished">Sabontawa</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation type="unfinished">Kwafi adireshin da aka zaɓa a halin yanzu domin yin amfani dashi</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation type="unfinished">&amp;Kwafi</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation type="unfinished">C&amp;Rasa</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">Share adireshin da aka zaɓa a halin yanzu daga jerin </translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">Shigar da adireshi ko lakabi don bincika</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Fitar da bayanan da ke cikin shafin na yanzu zuwa fayil</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp; Fitarwa</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation type="unfinished">&amp;Sharewa</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">zaɓi adireshin don aika tsabar kudi</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">Zaɓi adireshin don karɓar kuɗi internet da shi</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation type="unfinished">adireshin aikawa</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation type="unfinished">Adireshi da za a karba dashi</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 type="unfinished">WaÉ—annan adiresoshin Bitcoin ne don tura kuÉ—i bitcoin . ka tabbatar da cewa adreshin daidai ne kamin ka tura abua a ciki</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Waɗannan adiresoshin Bitcoin ne don karɓar kuɗi. Yi amfani da maɓallin 'Ƙirƙiri sabon adireshin karɓa' a cikin shafin karɓa don ƙirƙirar sababbin adireshi.
+zaka iya shiga ne kawai da adiresoshin 'na musamman' kawai.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished">&amp;Kwafi Adireshin</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">Kwafi &amp; Lakabi</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;Gyara</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">Fitarwar Jerin Adreshi</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">waƙafin rabuwar fayil</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
+ <translation type="unfinished">An sami kuskure wajen ƙoƙarin ajiye jerin adireshi zuwa 1 %1. Da fatan za a sake gwadawa.</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">Ba a yi nasarar fitarwa ba</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">Adireshi</translation>
+ </message>
+ </context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Unlock wallet</source>
+ <translation type="unfinished">Bude Walet</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject</name>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>BitcoinGUI</name>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>Intro</name>
+ <message>
+ <source>Bitcoin</source>
+ <translation type="unfinished">Bitkoin</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(sufficient to restore backups %n day(s) old)</source>
+ <extracomment>Explanatory text on the capability of the current prune target.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ <message>
+ <source>Address</source>
+ <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
+ <translation type="unfinished">Adireshi</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">waƙafin rabuwar fayil</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">Adireshi</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">Ba a yi nasarar fitarwa ba</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp; Fitarwa</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Fitar da bayanan da ke cikin shafin na yanzu zuwa fayil</translation>
+ </message>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts
index 71d42a1345..af9ff2bdc2 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 type="unfinished">לחיצה על הלחצן הימני בעכבר לעריכת הכתובת ×ו התווית</translation>
+ <translation type="unfinished">לחץ על הלחצן הימני בעכבר לעריכת הכתובת ×ו התווית</translation>
</message>
<message>
<source>Create a new address</source>
@@ -15,7 +15,7 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation type="unfinished">העתקת ×ת הכתובת המסומנת ללוח</translation>
+ <translation type="unfinished">העתק ×ת הכתובת המסומנת ללוח</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -430,10 +430,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">שגי××” בנסיון ×œ×§×¨×•× ×ת %s! כל המפתחות נקר×ו נכונה, ×ך נתוני העסקה ×ו הכתובות יתכן שחסרו ×ו שגויי×.</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">שגי××”: ×”××–× ×” לתקשורת × ×›×  סת נכשלה (×”×”××–× ×” מחזירה שגי××” %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">×מדן גובה עמלה נכשל. Fallbackfee  מנוטרל. יש להמתין מספר ×‘×œ×•×§×™× ×ו לשפעל ×ת -fallbackfee</translation>
</message>
@@ -590,10 +586,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">שגי×ת קרי××” ממסד הנתוני×. סוגר ×ת התהליך.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">שגי×ת שידרוג מסד ×”× ×ª×•× ×™× ×©×œ מצב השרשרת chainstate</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">שגי××”: שטח הדיסק קטן מדי עובר %s</translation>
</message>
@@ -670,10 +662,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">יש לציין פתחה ×¢× â€Ž-whitebind:†'%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">×œ× ×”×•×’×“×¨ פרוקסי. יש להשתמש ב־‎ -proxy=&lt;ip&gt; ×ו ב־‎ -proxy=&lt;ip:port&gt;.</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">×ין מספיק מידע על הקובץ</translation>
</message>
@@ -802,10 +790,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">קטגורית ×¨×™×©×•× ×‘×œ×•×’ ש××™× ×” נמתמכת %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">שדרוג מ×גר נתוני UTXO </translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">הערת צד המשתמש (%s) כוללת ×ª×•×•×™× ×©××™× × ×‘×˜×•×—×™×.</translation>
</message>
@@ -930,6 +914,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">×מת הודעות כדי להבטיח שהן נחתמו ×¢× ×›×ª×•×‘×ª ביטקוין מסוימות</translation>
</message>
<message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">פתיחת הקישור</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">סגירת ×רנק</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">יצירת ×רנק</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">סגירת כל ×”×רנקי×</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation type="unfinished">&amp;קובץ</translation>
</message>
@@ -946,6 +946,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">סרגל ×›×œ×™× ×œ×©×•× ×™×•×ª</translation>
</message>
<message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">בסנכרון ×¢× ×”×¨×©×ª</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">מתחבר לעמיתי×</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">בקשת ×ª×©×œ×•×ž×™× (יצירה של ×§×•×“×™× ×ž×¡×•×’ QR וסכימות כתובות מש×ב של :bitcoin)</translation>
</message>
@@ -973,6 +981,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1 מ×חור</translation>
</message>
<message>
+ <source>Catching up…</source>
+ <translation type="unfinished">×ž×©×œ×™× ×¤×¢×¨×™×</translation>
+ </message>
+ <message>
<source>Last received block was generated %1 ago.</source>
<translation type="unfinished">המקטע ×”×חרון שהתקבל נוצר לפני %1.</translation>
</message>
@@ -1037,6 +1049,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">סגירת ×רנק</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">שחזור ×רנק</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">שחזור ×רנק מקובץ גיבוי</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">סגירת כל ×”×רנקי×</translation>
</message>
@@ -1062,6 +1084,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">×ין ××¨× ×§×™× ×–×ž×™× ×™×</translation>
</message>
<message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">טעינת גיבוי ×”×רנק</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">×©× ×”×רנק</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;חלון</translation>
</message>
@@ -1503,6 +1535,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Bitcoin</source>
<translation type="unfinished">ביטקוין</translation>
</message>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(מתוך %n ג׳יגה-בייט נדרשי×)</numerusform>
+ <numerusform>(מתוך %n ג׳יגה-בייט נדרשי×)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(ג׳יגה-בייט %n נדרש לשרשרת המל××”)</numerusform>
+ <numerusform>(%n ג׳יגה-בייט × ×“×¨×©×™× ×œ×©×¨×©×¨×ª המל××”)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">לפחות %1 ג״ב של × ×ª×•× ×™× ×™×וחסנו בתיקייה זו, ×•×”× ×™×’×“×œ×• ×¢× ×”×–×ž×Ÿ.</translation>
@@ -1548,10 +1601,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">כיוון שזו ההפעלה הר×שונה של התכנית, ניתן לבחור היכן ×™×וחסן המידע של %1.</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 type="unfinished">בעת לחיצה על ×ישור, %1 יחל בהורדה ועיבוד מל××™× ×©×œ שרשרת ×”×ž×§×˜×¢×™× %4 (%2 ג״ב) החל מההעברות הר×שונות ב־%3 ×¢× ×”×”×©×§×” הר×שונית של %4.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">הגבלת ×חסון בלוקצ'יין ל</translation>
</message>
@@ -1848,10 +1897,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">השתמש בפרוקסי נפרד SOCKS&amp;5 להגעה ×œ×¢×ž×™×ª×™× ×“×¨×š שרותי השכבות של Tor :</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">×פשרויות שמוגדרות בדי×לוג ×”×–×” נדרסות ×¢"×™ שורת הפקודה ×ו קובץ הקונפיגורציה</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">&amp;×ישור</translation>
</message>
@@ -1869,14 +1914,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">×ישור ×יפוס ×”×פשרויות</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">נדרשת הפעלה מחדש של הלקוח כדי להפעיל ×ת השינויי×.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">הלקוח יכבה. להמשיך?</translation>
</message>
<message>
@@ -2903,10 +2951,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">עמלה מעל ×œ×¡×›×•× ×©×œ %1 נחשבת לעמלה גבוהה ב×ופן מוגז×.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">בקשת ×”×ª×©×œ×•× ×¤×’×”.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2986,14 +3030,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">הודעה:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">זוהי בקשת ×ª×©×œ×•× ×œ× ×ž×ומתת.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">זוהי בקשה מ×ומתת לתשלו×.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">יש לתת תווית לכתובת זו כדי להוסיף ×ותה לרשימת הכתובות בשימוש</translation>
</message>
@@ -3001,14 +3037,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<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 type="unfinished">הודעה שצורפה לביטקוין: כתובת שת×וחסן בהעברה לצורך מעקב מצדך. לתשומת לבך: הודעה זו ×œ× ×ª×™×©×œ×— ברשת הביטקוין.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">×ª×©×œ×•× ×œ×˜×•×‘×ª:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">תזכורת:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3168,30 +3196,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">ישנה סתירה ×¢× ×¢×¡×§×” שעברה %1 ×ימותי×</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/×œ× ×ž×ומתי×, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">במ×גר הזיכרון</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">×œ× ×‘×ž×גר הזיכרון</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">ננטש</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/×œ× ×ž×ומתי×</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 ×ימותי×</translation>
</message>
<message>
@@ -3659,7 +3679,7 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation type="unfinished">שמירת ×”× ×ª×•× ×™× ×ž×”×œ×©×•× ×™×ª הנוכחית לקובץ</translation>
+ <translation type="unfinished">×™×¦×•× ×”× ×ª×•× ×™× ×‘×œ×©×•× ×™×ª הנוכחית לקובץ</translation>
</message>
<message>
<source>Backup Wallet</source>
diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts
index 1073d6b2f5..64f36d6da9 100644
--- a/src/qt/locale/bitcoin_hr.ts
+++ b/src/qt/locale/bitcoin_hr.ts
@@ -70,6 +70,12 @@
<translation type="unfinished">Ovo su vaše Bitcoin adrese za slanje novca. Uvijek provjerite iznos i adresu primatelja prije slanja novca.</translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Ovo su vaše Bitcoin adrese za primanje sredstava. Koristite 'Kreiraj novu adresu za primanje' u tabu Primite kako biste kreirali nove adrese.
+Potpisivanje je moguće samo sa 'legacy' adresama. </translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">&amp;Kopirajte adresu</translation>
</message>
@@ -86,6 +92,11 @@
<translation type="unfinished">Izvezite listu adresa</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Datoteka podataka odvojenih zarezima (*.csv)</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">Došlo je do pogreške kod spremanja liste adresa na %1. Molimo pokušajte ponovno.</translation>
@@ -233,8 +244,37 @@
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">Runaway iznimka</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">Dogodila se greška. %1 ne može sigurno nastaviti te će se zatvoriti.</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">Interna greška</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Dogodila se interna greÅ¡ka. %1 će pokuÅ¡ati sigurno nastaviti. Ovo je neoÄekivani bug koji se može prijaviti kao Å¡to je objaÅ¡njeno ispod.</translation>
+ </message>
+</context>
+<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Želite li resetirati postavke na poÄetne vrijednosti ili izaći bez promjena?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Dogodila se kobna greška. Provjerite je li datoteka za postavke otvorena za promjene ili pokušajte pokrenuti s -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Greška: Zadana podatkovna mapa "%1" ne postoji.</translation>
</message>
@@ -247,6 +287,10 @@
<translation type="unfinished">Greška: %1</translation>
</message>
<message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 se nije joÅ¡ zatvorio na siguran naÄin.</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">nepoznato</translation>
</message>
@@ -259,6 +303,14 @@
<translation type="unfinished">Unesite Bitcoin adresu (npr. %1)</translation>
</message>
<message>
+ <source>Unroutable</source>
+ <translation type="unfinished">Neusmjeriv</translation>
+ </message>
+ <message>
+ <source>Internal</source>
+ <translation type="unfinished">Interni</translation>
+ </message>
+ <message>
<source>Inbound</source>
<extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
<translation type="unfinished">Dolazni</translation>
@@ -269,47 +321,72 @@
<translation type="unfinished">Izlazni</translation>
</message>
<message>
+ <source>Full Relay</source>
+ <extracomment>Peer connection type that relays all network information.</extracomment>
+ <translation type="unfinished">Potpuni prijenos</translation>
+ </message>
+ <message>
+ <source>Block Relay</source>
+ <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Blok prijenos</translation>
+ </message>
+ <message>
+ <source>Manual</source>
+ <extracomment>Peer connection type established manually through one of several methods.</extracomment>
+ <translation type="unfinished">PriruÄnik</translation>
+ </message>
+ <message>
+ <source>Feeler</source>
+ <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">IspipavaÄ</translation>
+ </message>
+ <message>
+ <source>Address Fetch</source>
+ <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
+ <translation type="unfinished">Dohvaćanje adrese</translation>
+ </message>
+ <message>
<source>None</source>
<translation type="unfinished">Ništa</translation>
</message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n second(s)</numerusform>
+ <numerusform>%n second(s)</numerusform>
+ <numerusform>%n sekundi</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n minute(s)</numerusform>
+ <numerusform>%n minute(s)</numerusform>
+ <numerusform>%n minuta</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n hour(s)</numerusform>
+ <numerusform>%n hour(s)</numerusform>
+ <numerusform>%n sati</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n day(s)</numerusform>
+ <numerusform>%n day(s)</numerusform>
+ <numerusform>%n dana</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n week(s)</numerusform>
+ <numerusform>%n week(s)</numerusform>
+ <numerusform>%n tjedana</numerusform>
</translation>
</message>
<message>
@@ -319,27 +396,47 @@
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n year(s)</numerusform>
+ <numerusform>%n year(s)</numerusform>
+ <numerusform>%n godina</numerusform>
</translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Datoteka postavke se ne može proÄitati</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Datoteka postavke se ne može mijenjati</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">Ekipa %s</translation>
</message>
<message>
+ <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
+ <translation type="unfinished">%s korumpirano. PokuÅ¡ajte koristiti bitcoin-wallet alat za novÄanike kako biste ga spasili ili pokrenuti sigurnosnu kopiju.</translation>
+ </message>
+ <message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished">-maxtxfee je postavljen preveliko. Naknade ove veliÄine će biti plaćene na individualnoj transakciji.</translation>
</message>
<message>
+ <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
+ <translation type="unfinished">Nije moguće unazaditi novÄanik s verzije %i na verziju %i. Verzija novÄanika nepromijenjena.</translation>
+ </message>
+ <message>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<translation type="unfinished">Program ne može pristupiti podatkovnoj mapi %s. %s je vjerojatno već pokrenut.</translation>
</message>
<message>
+ <source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
+ <translation type="unfinished">Nije moguće unaprijediti podijeljeni novÄanik bez HD-a s verzije %i na verziju %i bez unaprijeÄ‘enja na potporu pred-podjelnog bazena kljuÄeva. Molimo koristite verziju %i ili neku drugu.</translation>
+ </message>
+ <message>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished">Distribuirano pod MIT licencom softvera. Vidite pripadajuću datoteku %s ili %s.</translation>
</message>
@@ -348,18 +445,58 @@
<translation type="unfinished">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>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Greška: Neuspješno slušanje dolažećih veza (listen je izbacio grešku %s)</translation>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">GreÅ¡ka u Äitanju %s! Transakcijski podaci nedostaju ili su netoÄni. Ponovno skeniranje novÄanika.</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
+ <translation type="unfinished">GreÅ¡ka: Format dumpfile zapisa je netoÄan. Dobiven "%s" oÄekivani "format".</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source>
+ <translation type="unfinished">GreÅ¡ka: Identifikator dumpfile zapisa je netoÄan. Dobiven "%s", oÄekivan "%s".</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
+ <translation type="unfinished">Greška: Dumpfile verzija nije podržana. Ova bitcoin-wallet  verzija podržava samo dumpfile verziju 1. Dobiven dumpfile s verzijom %s</translation>
+ </message>
+ <message>
+ <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
+ <translation type="unfinished">GreÅ¡ka: Legacy novÄanici podržavaju samo "legacy", "p2sh-segwit", i "bech32" tipove adresa</translation>
</message>
<message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">NeuspjeÅ¡no procjenjivanje naknada. Fallbackfee je iskljuÄena. PriÄekajte nekoliko blokova ili ukljuÄite -fallbackfee.</translation>
</message>
<message>
+ <source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
+ <translation type="unfinished">Datoteka %s već postoji. Ako ste sigurni da ovo želite, prvo ju maknite, </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 type="unfinished">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>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">Nevažeći ili korumpirani peers.dat (%s). Ako mislite da je ovo bug, molimo prijavite %s. Kao alternativno rješenje, možete maknuti datoteku (%s) (preimenuj, makni ili obriši) kako bi se kreirala nova na idućem pokretanju.</translation>
+ </message>
+ <message>
+ <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
+ <translation type="unfinished">Pruženo je više od jedne onion bind adrese. Koristim %s za automatski stvorenu Tor onion uslugu.</translation>
+ </message>
+ <message>
+ <source>No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">Dump datoteka nije automatski dostupna. Kako biste koristili createfromdump, -dumpfile=&lt;filename&gt; mora biti osiguran. </translation>
+ </message>
+ <message>
+ <source>No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">Dump datoteka nije automatski dostupna. Kako biste koristili dump, -dumpfile=&lt;filename&gt; mora biti osiguran. </translation>
+ </message>
+ <message>
+ <source>No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
+ <translation type="unfinished">Format datoteke novÄanika nije dostupan. Kako biste koristili reatefromdump, -format=&lt;format&gt; mora biti osiguran.</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 type="unfinished">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>
@@ -376,18 +513,34 @@
<translation type="unfinished">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>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
+ <translation type="unfinished">SQLiteDatabase: Nepoznata sqlite shema novÄanika verzija %d. Podržana je samo verzija %d.</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 type="unfinished">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>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">Index bloka db sadrži legacy 'txindex'. Kako biste oÄistili zauzeti prostor na disku, pokrenite puni -reindex ili ignorirajte ovu greÅ¡ku. Ova greÅ¡ka neće biti ponovno prikazana.</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished">Iznos transakcije je premalen za poslati nakon naknade</translation>
</message>
<message>
+ <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source>
+ <translation type="unfinished">Ova greÅ¡ka bi se mogla dogoditi kada se ovaj novÄanik ne ugasi pravilno i ako je posljednji put bio podignut koristeći noviju verziju Berkeley DB. Ako je tako, molimo koristite softver kojim je novÄanik podignut zadnji put.</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 type="unfinished">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 maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
+ <translation type="unfinished">Ovo je najveća transakcijska naknada koju plaćate (uz normalnu naknadu) kako biste prioritizirali izbjegavanje djelomiÄne potroÅ¡nje nad uobiÄajenom selekcijom sredstava.</translation>
+ </message>
+ <message>
<source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
<translation type="unfinished">Ovo je transakcijska naknada koju možete odbaciti ako je ostatak manji od "prašine" (sićušnih iznosa) po ovoj stopi</translation>
</message>
@@ -404,6 +557,14 @@
<translation type="unfinished">Ne mogu se ponovo odigrati blokovi. Morat ćete ponovo složiti bazu koristeći -reindex-chainstate.</translation>
</message>
<message>
+ <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source>
+ <translation type="unfinished">Nepoznati formant novÄanika "%s" pružen. Molimo dostavite "bdb" ili "sqlite".</translation>
+ </message>
+ <message>
+ <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
+ <translation type="unfinished">Upozorenje: Dumpfile format novÄanika "%s" se ne poklapa sa formatom komandne linije "%s".</translation>
+ </message>
+ <message>
<source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
<translation type="unfinished">Upozorenje: Privatni kljuÄevi pronaÄ‘eni u novÄaniku {%s} s iskljuÄenim privatnim kljuÄevima</translation>
</message>
@@ -412,6 +573,10 @@
<translation type="unfinished">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>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
+ <translation type="unfinished">Podaci svjedoka za blokove poslije visine %d zahtijevaju validaciju. Molimo restartirajte sa -reindex.</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 type="unfinished">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>
@@ -424,14 +589,46 @@
<translation type="unfinished">-maxmempool mora biti barem %d MB</translation>
</message>
<message>
+ <source>A fatal internal error occurred, see debug.log for details</source>
+ <translation type="unfinished">Dogodila se kobna greška, vidi detalje u debug.log.</translation>
+ </message>
+ <message>
<source>Cannot resolve -%s address: '%s'</source>
<translation type="unfinished">Ne može se razriješiti adresa -%s: '%s'</translation>
</message>
<message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">Nije moguće postaviti -forcednsseed na true kada je postavka za -dnsseed false.</translation>
+ </message>
+ <message>
+ <source>Cannot set -peerblockfilters without -blockfilterindex.</source>
+ <translation type="unfinished">Nije moguće postaviti -peerblockfilters bez -blockfilterindex.</translation>
+ </message>
+ <message>
<source>Cannot write to data directory '%s'; check permissions.</source>
<translation type="unfinished">Nije moguće pisati u podatkovnu mapu '%s'; provjerite dozvole.</translation>
</message>
<message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">UnaprijeÄ‘enje -txindex koje za zapoÄela prijaÅ¡nja verzija nije moguće zavrÅ¡iti. Ponovno pokrenite s prethodnom verzijom ili pokrenite potpuni -reindex.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s zahtjev za slušanje na portu %u. Ovaj port se smatra "lošim" i time nije vjerojatno da će se drugi Bitcoin Core peerovi spojiti na njega. Pogledajte doc/p2p-bad-ports.md za detalje i cijeli popis.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Nije moguće ponuditi specifiÄne veze i istovremeno dati addrman da traži izlazne veze.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">PogreÅ¡ka pri uÄitavanju %s: Vanjski potpisni novÄanik se uÄitava bez kompajlirane potpore vanjskog potpisnika</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Preimenovanje nevažeće peers.dat datoteke neuspješno. Molimo premjestite ili obrišite datoteku i pokušajte ponovno.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">Konfiguriranje postavki za %s primijenjeno je samo na %s mreži u odjeljku [%s].</translation>
</message>
@@ -448,6 +645,10 @@
<translation type="unfinished">Nije moguće proÄitati asmap datoteku %s</translation>
</message>
<message>
+ <source>Disk space is too low!</source>
+ <translation type="unfinished">Nema dovoljno prostora na disku!</translation>
+ </message>
+ <message>
<source>Do you want to rebuild the block database now?</source>
<translation type="unfinished">Želite li sada obnoviti bazu blokova?</translation>
</message>
@@ -456,6 +657,14 @@
<translation type="unfinished">UÄitavanje gotovo</translation>
</message>
<message>
+ <source>Dump file %s does not exist.</source>
+ <translation type="unfinished">Dump datoteka %s ne postoji.</translation>
+ </message>
+ <message>
+ <source>Error creating %s</source>
+ <translation type="unfinished">Greška pri stvaranju %s</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
<translation type="unfinished">Greška kod inicijaliziranja baze blokova</translation>
</message>
@@ -492,14 +701,50 @@
<translation type="unfinished">GreÅ¡ka kod iÅ¡Äitanja baze. Zatvara se klijent.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Greška kod ažuriranja baze stanja lanca</translation>
+ <source>Error reading next record from wallet database</source>
+ <translation type="unfinished">GreÅ¡ka pri oÄitavanju idućeg zapisa iz baza podataka novÄanika</translation>
+ </message>
+ <message>
+ <source>Error: Couldn't create cursor into database</source>
+ <translation type="unfinished">Greška: Nije moguće kreirati cursor u batu podataka</translation>
</message>
<message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Pogreška: Malo diskovnog prostora za %s</translation>
</message>
<message>
+ <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
+ <translation type="unfinished">GreÅ¡ka: Dumpfile checksum se ne poklapa. IzraÄunao %s, oÄekivano %s</translation>
+ </message>
+ <message>
+ <source>Error: Got key that was not hex: %s</source>
+ <translation type="unfinished">GreÅ¡ka: Dobiven kljuÄ koji nije hex: %s</translation>
+ </message>
+ <message>
+ <source>Error: Got value that was not hex: %s</source>
+ <translation type="unfinished">Greška: Dobivena vrijednost koja nije hex: %s</translation>
+ </message>
+ <message>
+ <source>Error: Keypool ran out, please call keypoolrefill first</source>
+ <translation type="unfinished">GreÅ¡ka: Ispraznio se bazen kljuÄeva, molimo prvo pozovite keypoolrefill</translation>
+ </message>
+ <message>
+ <source>Error: Missing checksum</source>
+ <translation type="unfinished">Greška: Nedostaje checksum</translation>
+ </message>
+ <message>
+ <source>Error: No %s addresses available.</source>
+ <translation type="unfinished">Greška: Nema %s adresa raspoloživo.</translation>
+ </message>
+ <message>
+ <source>Error: Unable to parse version %u as a uint32_t</source>
+ <translation type="unfinished">Greška: Nije moguće parsirati verziju %u kao uint32_t</translation>
+ </message>
+ <message>
+ <source>Error: Unable to write record to new wallet</source>
+ <translation type="unfinished">GreÅ¡ka: Nije moguće unijeti zapis u novi novÄanik</translation>
+ </message>
+ <message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation type="unfinished">Neuspješno slušanje na svim portovima. Koristite -listen=0 ako to želite.</translation>
</message>
@@ -508,6 +753,22 @@
<translation type="unfinished">NeuspjeÅ¡no ponovo skeniranje novÄanika tijekom inicijalizacije</translation>
</message>
<message>
+ <source>Failed to verify database</source>
+ <translation type="unfinished">Verifikacija baze podataka neuspješna</translation>
+ </message>
+ <message>
+ <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source>
+ <translation type="unfinished">Naknada (%s) je niža od postavke minimalne visine naknade (%s)</translation>
+ </message>
+ <message>
+ <source>Ignoring duplicate -wallet %s.</source>
+ <translation type="unfinished">Zanemarujem duplicirani -wallet %s.</translation>
+ </message>
+ <message>
+ <source>Importing…</source>
+ <translation type="unfinished">Uvozim...</translation>
+ </message>
+ <message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
<translation type="unfinished">Neispravan ili nepostojeći blok geneze. Možda je kriva podatkovna mapa za mrežu?</translation>
</message>
@@ -516,10 +777,18 @@
<translation type="unfinished">Brzinska provjera inicijalizacije neuspješna. %s se zatvara.</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Input nije pronađen ili je već potrošen</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">Nedovoljna sredstva</translation>
</message>
<message>
+ <source>Invalid -i2psam address or hostname: '%s'</source>
+ <translation type="unfinished">Neispravna -i2psam adresa ili ime raÄunala: '%s'</translation>
+ </message>
+ <message>
<source>Invalid -onion address or hostname: '%s'</source>
<translation type="unfinished">Neispravna -onion adresa ili ime raÄunala: '%s'</translation>
</message>
@@ -552,10 +821,38 @@
<translation type="unfinished">Neispravna mrežna maska zadana u -whitelist: '%s'</translation>
</message>
<message>
+ <source>Loading P2P addresses…</source>
+ <translation type="unfinished">Pokreće se popis P2P adresa...</translation>
+ </message>
+ <message>
+ <source>Loading banlist…</source>
+ <translation type="unfinished">Pokreće se popis zabrana...</translation>
+ </message>
+ <message>
+ <source>Loading block index…</source>
+ <translation type="unfinished">UÄitavanje indeksa blokova...</translation>
+ </message>
+ <message>
+ <source>Loading wallet…</source>
+ <translation type="unfinished">UÄitavanje novÄanika...</translation>
+ </message>
+ <message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Iznos nedostaje</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">Nedostaju podaci za procjenu veliÄine transakcije</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">Treba zadati port pomoću -whitebind: '%s'</translation>
</message>
<message>
+ <source>No addresses available</source>
+ <translation type="unfinished">Nema dostupnih adresa</translation>
+ </message>
+ <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">Nema dovoljno dostupnih datoteÄnih opisivaÄa.</translation>
</message>
@@ -568,10 +865,38 @@
<translation type="unfinished">NaÄin obreživanja (pruning) nekompatibilan je s parametrom -txindex.</translation>
</message>
<message>
+ <source>Pruning blockstore…</source>
+ <translation type="unfinished">Pruning blockstore-a...</translation>
+ </message>
+ <message>
<source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
<translation type="unfinished">Smanjuje se -maxconnections sa %d na %d zbog sustavnih ograniÄenja.</translation>
</message>
<message>
+ <source>Replaying blocks…</source>
+ <translation type="unfinished">Premotavam blokove...</translation>
+ </message>
+ <message>
+ <source>Rescanning…</source>
+ <translation type="unfinished">Ponovno pretraživanje...</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source>
+ <translation type="unfinished">SQLiteDatabase: Neuspješno izvršenje izjave za verifikaciju baze podataka: %s</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source>
+ <translation type="unfinished">SQLiteDatabase: Neuspješno pripremanje izjave za verifikaciju baze: %s</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Failed to read database verification error: %s</source>
+ <translation type="unfinished">SQLiteDatabase: NeuspjeÅ¡no Äitanje greÅ¡ke verifikacije baze podataka %s</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source>
+ <translation type="unfinished">SQLiteDatabase: NeoÄekivani id aplikacije. OÄekvano %u, pronaÄ‘eno %u</translation>
+ </message>
+ <message>
<source>Section [%s] is not recognized.</source>
<translation type="unfinished">Odjeljak [%s] nije prepoznat.</translation>
</message>
@@ -596,10 +921,18 @@
<translation type="unfinished">Zadana mapa blokova "%s" ne postoji.</translation>
</message>
<message>
+ <source>Starting network threads…</source>
+ <translation type="unfinished">Pokreću se mrežne niti...</translation>
+ </message>
+ <message>
<source>The source code is available from %s.</source>
<translation type="unfinished">Izvorni kod je dostupan na %s.</translation>
</message>
<message>
+ <source>The specified config file %s does not exist</source>
+ <translation type="unfinished">Navedena konfiguracijska datoteka %s ne postoji</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to pay the fee</source>
<translation type="unfinished">Transakcijiski iznos je premalen da plati naknadu</translation>
</message>
@@ -628,6 +961,10 @@
<translation type="unfinished">Iznosi transakcije ne smiju biti negativni</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">Indeks change outputa transakcije je izvan dometa</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">Transakcija ima prevelik lanac memorijskog bazena</translation>
</message>
@@ -636,6 +973,10 @@
<translation type="unfinished">Transakcija mora imati barem jednog primatelja</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">Transakciji je potrebna change adresa, ali ju ne možemo generirati.</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">Transakcija prevelika</translation>
</message>
@@ -660,6 +1001,14 @@
<translation type="unfinished">Ne mogu se generirati kljuÄevi</translation>
</message>
<message>
+ <source>Unable to open %s for writing</source>
+ <translation type="unfinished">Ne mogu otvoriti %s za upisivanje</translation>
+ </message>
+ <message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">Nije moguće parsirati -maxuploadtarget: '%s'</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">Ne može se pokrenuti HTTP server. Vidite debug.log za više detalja.</translation>
</message>
@@ -680,18 +1029,26 @@
<translation type="unfinished">Nepoznata mreža zadana kod -onlynet: '%s'</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">Nepodržana kategorija zapisa %s=%s.</translation>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished"> Nepoznata nova pravila aktivirana (versionbit %i)</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Ažurira se UTXO baza</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Nepodržana kategorija zapisa %s=%s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Komentar pod "KorisniÄki agent" (%s) sadrži nesigurne znakove.</translation>
</message>
<message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">Provjervanje blokova...</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)…</source>
+ <translation type="unfinished">Provjeravanje novÄanika...</translation>
+ </message>
+ <message>
<source>Wallet needed to be rewritten: restart %s to complete</source>
<translation type="unfinished">NovÄanik je trebao prepravak: ponovo pokrenite %s</translation>
</message>
@@ -740,13 +1097,17 @@
</message>
<message>
<source>Modify configuration options for %1</source>
- <translation type="unfinished">Promijenite postavke za %1</translation>
+ <translation type="unfinished">Promijeni konfiguraciju opcija za %1</translation>
</message>
<message>
<source>Create a new wallet</source>
<translation type="unfinished">Stvorite novi novÄanik</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimiziraj</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">NovÄanik:</translation>
</message>
@@ -761,7 +1122,7 @@
</message>
<message>
<source>Send coins to a Bitcoin address</source>
- <translation type="unfinished">Pošaljite novac na Bitcoin adresu</translation>
+ <translation type="unfinished">Pošaljite sredstva na Bitcoin adresu</translation>
</message>
<message>
<source>Backup wallet to another location</source>
@@ -777,21 +1138,65 @@
</message>
<message>
<source>&amp;Receive</source>
- <translation type="unfinished">Pri&amp;mite</translation>
+ <translation type="unfinished">&amp;Primite</translation>
+ </message>
+ <message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Opcije</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;Å ifriraj novÄanik</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">Å ifrirajte privatne kljuÄeve u novÄaniku</translation>
</message>
<message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;Kreiraj sigurnosnu kopiju novÄanika</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;Promijeni lozinku</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">Potpiši &amp;poruku</translation>
+ </message>
+ <message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
<translation type="unfinished">Poruku potpišemo s Bitcoin adresom, kako bi dokazali vlasništvo nad tom adresom</translation>
</message>
<message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;Potvrdi poruku</translation>
+ </message>
+ <message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
<translation type="unfinished">Provjerite poruku da je potpisana s navedenom Bitcoin adresom</translation>
</message>
<message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;UÄitaj PSBT iz datoteke...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">Otvori &amp;URI adresu...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">Zatvori novÄanik...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">Kreiraj novÄanik...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">Zatvori sve novÄanike...</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation type="unfinished">&amp;Datoteka</translation>
</message>
@@ -808,6 +1213,30 @@
<translation type="unfinished">Traka kartica</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Sinkronizacija zaglavlja bloka (%1%)...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Sinkronizacija s mrežom...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Indeksiranje blokova na disku...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Obrađivanje blokova na disku...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Reindeksiranje blokova na disku...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Povezivanje sa peer-ovima...</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">Zatražite uplatu (stvara QR kod i bitcoin: URI adresu)</translation>
</message>
@@ -826,9 +1255,9 @@
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Processed %n block(s) of transaction history.</numerusform>
+ <numerusform>Processed %n block(s) of transaction history.</numerusform>
+ <numerusform>Obrađeno %n blokova povijesti transakcije.</numerusform>
</translation>
</message>
<message>
@@ -836,6 +1265,10 @@
<translation type="unfinished">%1 iza</translation>
</message>
<message>
+ <source>Catching up…</source>
+ <translation type="unfinished">Ažuriranje...</translation>
+ </message>
+ <message>
<source>Last received block was generated %1 ago.</source>
<translation type="unfinished">Zadnji primljeni blok je bio ustvaren prije %1.</translation>
</message>
@@ -864,6 +1297,10 @@
<translation type="unfinished">UÄitaj djelomiÄno potpisanu bitcoin transakciju</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">UÄitaj PSBT iz &amp;meÄ‘uspremnika...</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">UÄitaj djelomiÄno potpisanu bitcoin transakciju iz meÄ‘uspremnika</translation>
</message>
@@ -908,6 +1345,14 @@
<translation type="unfinished">Prikažite pomoć programa %1 kako biste ispisali moguće opcije preko terminala</translation>
</message>
<message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">&amp;Sakrij vrijednosti</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">Sakrij vrijednost u tabu Pregled </translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">uobiÄajeni novÄanik</translation>
</message>
@@ -916,6 +1361,16 @@
<translation type="unfinished">Nema dostupnih novÄanika</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Podaci novÄanika</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Ime novÄanika</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Prozor</translation>
</message>
@@ -931,16 +1386,44 @@
<source>%1 client</source>
<translation type="unfinished">%1 klijent</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Sakrij</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">&amp;Pokaži</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
+ <numerusform>%n aktivnih veza s Bitcoin mrežom.</numerusform>
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Klikni za više radnji.</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Pokaži Peers tab </translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">Onemogući mrežnu aktivnost</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">Omogući mrežnu aktivnost</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Greška: %1</translation>
</message>
@@ -963,7 +1446,8 @@
<message>
<source>Wallet: %1
</source>
- <translation type="unfinished">NovÄanik: %1</translation>
+ <translation type="unfinished">NovÄanik: %1
+</translation>
</message>
<message>
<source>Type: %1
@@ -1011,7 +1495,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation type="unfinished">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>Original message:</source>
+ <translation type="unfinished">Originalna poruka:</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1094,6 +1582,30 @@
<translation type="unfinished">Kopirajte iznos</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopiraj adresu</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiraj &amp;oznaku</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopiraj &amp;iznos</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Kopiraj &amp;ID transakcije i output index</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">&amp;ZakljuÄaj nepotroÅ¡en input</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;OtkljuÄaj nepotroÅ¡en input</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Kopirajte iznos</translation>
</message>
@@ -1158,6 +1670,11 @@
<translation type="unfinished">Stvorite novÄanik</translation>
</message>
<message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">Kreiranje novÄanika &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
<source>Create wallet failed</source>
<translation type="unfinished">NeuspjeÅ¡no stvaranje novÄanika</translation>
</message>
@@ -1165,8 +1682,25 @@
<source>Create wallet warning</source>
<translation type="unfinished">Upozorenje kod stvaranja novÄanika</translation>
</message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Nije moguće izlistati potpisnike</translation>
+ </message>
</context>
<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">UÄitaj novÄanike</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">UÄitavanje novÄanika...</translation>
+ </message>
+</context>
+<context>
<name>OpenWalletActivity</name>
<message>
<source>Open wallet failed</source>
@@ -1185,7 +1719,12 @@
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">Otvorite novÄanik</translation>
</message>
- </context>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">Otvaranje novÄanika &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
<context>
<name>WalletController</name>
<message>
@@ -1198,13 +1737,17 @@
</message>
<message>
<source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
- <translation type="unfinished">Držanje novÄanik zatvorenim predugo može rezultirati ponovnom sinkronizacijom cijelog lanca ako je obrezivanje ukljuÄeno.</translation>
+ <translation type="unfinished">Držanje novÄanik zatvorenim predugo može rezultirati ponovnom sinkronizacijom cijelog lanca ako je ukljuÄen pruning (odbacivanje dijela podataka).</translation>
</message>
<message>
<source>Close all wallets</source>
<translation type="unfinished">Zatvori sve novÄanike</translation>
</message>
- </context>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">Jeste li sigurni da želite zatvoriti sve novÄanike?</translation>
+ </message>
+</context>
<context>
<name>CreateWalletDialog</name>
<message>
@@ -1228,6 +1771,10 @@
<translation type="unfinished">Å ifrirajte novÄanik</translation>
</message>
<message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">Napredne opcije</translation>
+ </message>
+ <message>
<source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
<translation type="unfinished">IskljuÄite privatne kljuÄeve za ovaj novÄanik. NovÄanici gdje su privatni kljuÄevi iskljuÄeni neće sadržati privatne kljuÄeve te ne mogu imati HD sjeme ili uvezene privatne kljuÄeve. Ova postavka je idealna za novÄanike koje su iskljuÄivo za promatranje.</translation>
</message>
@@ -1244,10 +1791,35 @@
<translation type="unfinished">Stvorite prazni novÄanik</translation>
</message>
<message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">Koristi deskriptore za upravljanje scriptPubKey-a</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">Deskriptor novÄanik</translation>
+ </message>
+ <message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Koristi vanjski potpisni ureÄ‘aj kao Å¡to je hardverski novÄanik. Prije koriÅ¡tenja konfiguriraj vanjski potpisni skript u postavkama novÄanika.</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">Vanjski potpisnik</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">Stvorite</translation>
</message>
- </context>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished">Kompajlirano bez sqlite mogućnosti (potrebno za deskriptor novÄanike)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Kompajlirano bez mogućnosti vanjskog potpisivanje (potrebno za vanjsko potpisivanje)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -1307,7 +1879,7 @@
<name>FreespaceChecker</name>
<message>
<source>A new data directory will be created.</source>
- <translation type="unfinished">Bit će stvorena nova podatkovna mapa.</translation>
+ <translation type="unfinished">Biti će stvorena nova podatkovna mapa.</translation>
</message>
<message>
<source>name</source>
@@ -1328,6 +1900,30 @@
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(od potrebnog prostora od %n GB)</numerusform>
+ <numerusform>(od potrebnog prostora od %n GB)</numerusform>
+ <numerusform>(od potrebnog %n GB)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(potreban je %n GB za cijeli lanac)</numerusform>
+ <numerusform>(potrebna su %n GB-a za cijeli lanac)</numerusform>
+ <numerusform>(potrebno je %n GB-a za cijeli lanac)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Bit će spremljeno barem %1 GB podataka u ovoj mapi te će se povećati tijekom vremena.</translation>
@@ -1340,9 +1936,9 @@
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
+ <numerusform>(dovoljno za vraćanje sigurnosne kopije stare %n dan(a))</numerusform>
</translation>
</message>
<message>
@@ -1374,8 +1970,8 @@
<translation type="unfinished">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 type="unfinished">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>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">OgraniÄi pohranu u blockchain na:</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
@@ -1387,7 +1983,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 type="unfinished">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>
+ <translation type="unfinished">Ako odluÄite ograniÄiti spremanje lanca blokova pomoću pruninga, 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>
@@ -1416,6 +2012,10 @@
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 do zatvaranja...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation type="unfinished">Ne ugasite raÄunalo dok ovaj prozor ne nestane.</translation>
</message>
@@ -1439,6 +2039,14 @@
<translation type="unfinished">Broj preostalih blokova</translation>
</message>
<message>
+ <source>Unknown…</source>
+ <translation type="unfinished">Nepoznato...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">raÄunam...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation type="unfinished">Posljednje vrijeme bloka</translation>
</message>
@@ -1458,6 +2066,10 @@
<source>Hide</source>
<translation type="unfinished">Sakrijte</translation>
</message>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Nepoznato. Sinkroniziranje zaglavlja blokova (%1, %2%)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -1475,7 +2087,7 @@
<name>OptionsDialog</name>
<message>
<source>Options</source>
- <translation type="unfinished">Postavke</translation>
+ <translation type="unfinished">Opcije</translation>
</message>
<message>
<source>&amp;Main</source>
@@ -1490,6 +2102,10 @@
<translation type="unfinished">&amp;Pokrenite %1 kod prijave u sustav</translation>
</message>
<message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Omogućavanje pruninga smanjuje prostor na disku potreban za pohranu transakcija. Svi blokovi su još uvijek potpuno potvrđeni. Poništavanje ove postavke uzrokuje ponovno skidanje cijelog blockchaina.</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation type="unfinished">VeliÄina predmemorije baze podataka</translation>
</message>
@@ -1519,11 +2135,11 @@
</message>
<message>
<source>Reset all client options to default.</source>
- <translation type="unfinished">Nastavi sve postavke programa na poÄetne vrijednosti.</translation>
+ <translation type="unfinished">Resetiraj sve opcije programa na poÄetne vrijednosti.</translation>
</message>
<message>
<source>&amp;Reset Options</source>
- <translation type="unfinished">Po&amp;nastavi postavke</translation>
+ <translation type="unfinished">&amp;Resetiraj opcije</translation>
</message>
<message>
<source>&amp;Network</source>
@@ -1538,14 +2154,44 @@
<translation type="unfinished">Vraćanje na prijašnje stanje zahtijeva ponovo preuzimanje cijelog lanca blokova.</translation>
</message>
<message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">Maksimalna veliÄina cachea baza podataka. Veći cache može doprinijeti bržoj sinkronizaciji, nakon koje je korisnost manje izražena za većinu sluÄajeva. Smanjenje cache veliÄine će smanjiti koriÅ¡tenje memorije. NekoriÅ¡tena mempool memorija se dijeli za ovaj cache. </translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Postavi broj skript verifikacijskih niti. Negativne vrijednosti odgovaraju broju jezgri koje trebate ostaviti slobodnima za sustav.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = automatski odredite, &lt;0 = ostavite slobodno upravo toliko jezgri)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Ovo omogućava vama ili vanjskom alatu komunikaciju s Ävorom kroz command-line i JSON-RPC komande.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">UkljuÄi &amp;RPC server</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">&amp;NovÄanik</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Za postavljanje oduzimanja naknade od iznosa kao zadano ili ne.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Oduzmi &amp;naknadu od iznosa kao zadano</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">StruÄne postavke</translation>
</message>
@@ -1562,6 +2208,28 @@
<translation type="unfinished">&amp;Trošenje nepotvrđenih vraćenih iznosa</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">UkljuÄi &amp;PBST opcije za upravljanje</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Za prikazivanje PSBT opcija za upravaljanje. </translation>
+ </message>
+ <message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">Vanjski potpisnik (npr. hardverski novÄanik)</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;Put za vanjsku skriptu potpisnika</translation>
+ </message>
+ <message>
+ <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished">Cijeli put do Bitcoin Core kompatibilnog skripta (npr. C:\Downloads\hwi.exe ili /Users/you/Downloads/hwi.py). Upozerenje: malware može ukrasti vaša sredstva!</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 type="unfinished">Automatski otvori port Bitcoin klijenta na ruteru. To radi samo ako ruter podržava UPnP i ako je omogućen.</translation>
</message>
@@ -1570,6 +2238,14 @@
<translation type="unfinished">Mapiraj port koristeći &amp;UPnP</translation>
</message>
<message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
+ <translation type="unfinished">Automatski otvori port Bitcoin klijenta na ruteru. Ovo radi samo ako ruter podržava UPnP i ako je omogućen. Vanjski port može biti nasumiÄan.</translation>
+ </message>
+ <message>
+ <source>Map port using NA&amp;T-PMP</source>
+ <translation type="unfinished">Mapiraj port koristeći &amp;UPnP</translation>
+ </message>
+ <message>
<source>Accept connections from outside.</source>
<translation type="unfinished">Prihvatite veze izvana.</translation>
</message>
@@ -1614,6 +2290,14 @@
<translation type="unfinished">&amp;Prozor</translation>
</message>
<message>
+ <source>Show the icon in the system tray.</source>
+ <translation type="unfinished">Pokaži ikonu sa sustavne trake.</translation>
+ </message>
+ <message>
+ <source>&amp;Show tray icon</source>
+ <translation type="unfinished">&amp;Pokaži ikonu</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation type="unfinished">Prikaži samo ikonu u sistemskoj traci nakon minimiziranja prozora</translation>
</message>
@@ -1646,12 +2330,36 @@
<translation type="unfinished">Izaberite željeni najmanji dio bitcoina koji će biti prikazan u suÄelju i koji će se koristiti za plaćanje.</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 type="unfinished">Vanjski URL-ovi transakcije (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>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;Vanjski URL-ovi transakcije</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">Ovisi želite li prikazati mogućnosti kontroliranja inputa ili ne.</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Opcije postavljene u ovom dijalogu nadglašene su naredbenom linijom ili konfiguracijskom datotekom:</translation>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
+ <translation type="unfinished">Spojite se na Bitcoin mrežu kroz zaseban SOCKS5 proxy za povezivanje na Tor onion usluge.</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
+ <translation type="unfinished">Koristite zaseban SOCKS&amp;5 proxy kako biste dohvatili klijente preko Tora:</translation>
+ </message>
+ <message>
+ <source>Monospaced font in the Overview tab:</source>
+ <translation type="unfinished">Font fiksne Å¡irine u tabu Pregled:</translation>
+ </message>
+ <message>
+ <source>embedded "%1"</source>
+ <translation type="unfinished">ugrađen "%1"</translation>
+ </message>
+ <message>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">najbliže poklapanje "%1"</translation>
</message>
<message>
<source>&amp;OK</source>
@@ -1662,6 +2370,11 @@
<translation type="unfinished">&amp;Odustani</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Kompajlirano bez mogućnosti vanjskog potpisivanje (potrebno za vanjsko potpisivanje)</translation>
+ </message>
+ <message>
<source>default</source>
<translation type="unfinished">standardne vrijednosti</translation>
</message>
@@ -1671,20 +2384,23 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Potvrdite resetiranje opcija</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">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>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Zatvorit će se klijent. Želite li nastaviti?</translation>
</message>
<message>
<source>Configuration options</source>
<extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
- <translation type="unfinished">Konfiguracijske postavke</translation>
+ <translation type="unfinished">Konfiguracijske opcije</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>
@@ -1692,6 +2408,10 @@
<translation type="unfinished">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>Continue</source>
+ <translation type="unfinished">Nastavi</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">Odustanite</translation>
</message>
@@ -1786,7 +2506,11 @@
<source>Current total balance in watch-only addresses</source>
<translation type="unfinished">Trenutno ukupno stanje na iskljuÄivo promatranim adresama</translation>
</message>
- </context>
+ <message>
+ <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
+ <translation type="unfinished">Privatni naÄin aktiviran za tab Pregled. Za prikaz vrijednosti, odznaÄi Postavke -&gt; Sakrij vrijednosti.</translation>
+ </message>
+</context>
<context>
<name>PSBTOperationsDialog</name>
<message>
@@ -1794,6 +2518,91 @@
<translation type="unfinished">Dijalog</translation>
</message>
<message>
+ <source>Sign Tx</source>
+ <translation type="unfinished">Potpiši Tx</translation>
+ </message>
+ <message>
+ <source>Broadcast Tx</source>
+ <translation type="unfinished">Objavi Tx</translation>
+ </message>
+ <message>
+ <source>Copy to Clipboard</source>
+ <translation type="unfinished">Kopiraj u međuspremnik</translation>
+ </message>
+ <message>
+ <source>Save…</source>
+ <translation type="unfinished">Spremi...</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished">Zatvori</translation>
+ </message>
+ <message>
+ <source>Failed to load transaction: %1</source>
+ <translation type="unfinished">Neuspješno dohvaćanje transakcije: %1</translation>
+ </message>
+ <message>
+ <source>Failed to sign transaction: %1</source>
+ <translation type="unfinished">Neuspješno potpisivanje transakcije: %1</translation>
+ </message>
+ <message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">Nije moguće potpisati inpute dok je novÄanik zakljuÄan.</translation>
+ </message>
+ <message>
+ <source>Could not sign any more inputs.</source>
+ <translation type="unfinished">Nije bilo moguće potpisati više inputa. </translation>
+ </message>
+ <message>
+ <source>Signed %1 inputs, but more signatures are still required.</source>
+ <translation type="unfinished">Potpisano %1 inputa, ali potrebno je još potpisa. </translation>
+ </message>
+ <message>
+ <source>Signed transaction successfully. Transaction is ready to broadcast.</source>
+ <translation type="unfinished">Transakcija uspješno potpisana. Transakcija je spremna za objavu.</translation>
+ </message>
+ <message>
+ <source>Unknown error processing transaction.</source>
+ <translation type="unfinished">Nepoznata greška pri obradi transakcije.</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast successfully! Transaction ID: %1</source>
+ <translation type="unfinished">Uspješna objava transakcije! ID transakcije: %1</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast failed: %1</source>
+ <translation type="unfinished">Neuspješna objava transakcije: %1</translation>
+ </message>
+ <message>
+ <source>PSBT copied to clipboard.</source>
+ <translation type="unfinished">PBST kopiran u meduspremnik.</translation>
+ </message>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">Spremi podatke transakcije</translation>
+ </message>
+ <message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">DjelomiÄno potpisana transakcija (binarno)</translation>
+ </message>
+ <message>
+ <source>PSBT saved to disk.</source>
+ <translation type="unfinished">PBST spremljen na disk.</translation>
+ </message>
+ <message>
+ <source> * Sends %1 to %2</source>
+ <translation type="unfinished">* Å alje %1 %2</translation>
+ </message>
+ <message>
+ <source>Unable to calculate transaction fee or total transaction amount.</source>
+ <translation type="unfinished">Ne mogu izraÄunati naknadu za transakciju niti totalni iznos transakcije.</translation>
+ </message>
+ <message>
+ <source>Pays transaction fee: </source>
+ <translation type="unfinished">Plaća naknadu za transakciju:</translation>
+ </message>
+ <message>
<source>Total Amount</source>
<translation type="unfinished">Ukupni iznos</translation>
</message>
@@ -1801,7 +2610,39 @@
<source>or</source>
<translation type="unfinished">ili</translation>
</message>
- </context>
+ <message>
+ <source>Transaction has %1 unsigned inputs.</source>
+ <translation type="unfinished">Transakcija ima %1 nepotpisanih inputa.</translation>
+ </message>
+ <message>
+ <source>Transaction is missing some information about inputs.</source>
+ <translation type="unfinished">Transakciji nedostaje informacija o inputima.</translation>
+ </message>
+ <message>
+ <source>Transaction still needs signature(s).</source>
+ <translation type="unfinished">Transakcija još uvijek treba potpis(e).</translation>
+ </message>
+ <message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Ali nijedan novÄanik nije uÄitan.)</translation>
+ </message>
+ <message>
+ <source>(But this wallet cannot sign transactions.)</source>
+ <translation type="unfinished">(Ali ovaj novÄanik ne može potpisati transakcije.)</translation>
+ </message>
+ <message>
+ <source>(But this wallet does not have the right keys.)</source>
+ <translation type="unfinished">(Ali ovaj novÄanik nema odgovarajuće kljuÄeve.)</translation>
+ </message>
+ <message>
+ <source>Transaction is fully signed and ready for broadcast.</source>
+ <translation type="unfinished">Transakcija je cjelovito potpisana i spremna za objavu.</translation>
+ </message>
+ <message>
+ <source>Transaction status is unknown.</source>
+ <translation type="unfinished">Status transakcije je nepoznat.</translation>
+ </message>
+</context>
<context>
<name>PaymentServer</name>
<message>
@@ -1821,6 +2662,14 @@
<translation type="unfinished">'bitcoin://' nije ispravan URI. Koristite 'bitcoin:' umjesto toga.</translation>
</message>
<message>
+ <source>Cannot process payment request because BIP70 is not supported.
+Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
+If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
+ <translation type="unfinished">Nemoguće obraditi zahtjev za plaćanje zato što BIP70 nije podržan.
+S obzirom na Å¡iroko rasprostranjene sigurnosne nedostatke u BIP70, preporuÄljivo je da zanemarite preporuke trgovca u vezi promjene novÄanika.
+Ako imate ovu grešku, od trgovca zatražite URI koji je kompatibilan sa BIP21.</translation>
+ </message>
+ <message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<translation type="unfinished">Ne može se parsirati URI! Uzrok tomu može biti nevažeća Bitcoin adresa ili neispravni parametri kod URI-a.</translation>
</message>
@@ -1880,6 +2729,10 @@
<context>
<name>QRImageWidget</name>
<message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Spremi sliku...</translation>
+ </message>
+ <message>
<source>&amp;Copy Image</source>
<translation type="unfinished">&amp;Kopirajte sliku</translation>
</message>
@@ -1899,7 +2752,12 @@
<source>Save QR Code</source>
<translation type="unfinished">Spremi QR kod</translation>
</message>
- </context>
+ <message>
+ <source>PNG Image</source>
+ <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment>
+ <translation type="unfinished">PNG slika</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -2007,10 +2865,38 @@
<translation type="unfinished">Broj sinkronizranih blokova</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Zadnja transakcija</translation>
+ </message>
+ <message>
+ <source>The mapped Autonomous System used for diversifying peer selection.</source>
+ <translation type="unfinished">Mapirani Autonomni sustav koji se koristi za diverzifikaciju odabira peer-ova.</translation>
+ </message>
+ <message>
<source>Mapped AS</source>
<translation type="unfinished">Mapirano kao</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Prenosimo li adrese ovom peer-u.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Prijenos adresa</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Obrađene adrese</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Adrese ograniÄene brzinom</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">KorisniÄki agent</translation>
</message>
@@ -2019,6 +2905,10 @@
<translation type="unfinished">Konzola za Ävor</translation>
</message>
<message>
+ <source>Current block height</source>
+ <translation type="unfinished">Trenutna visina bloka</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 type="unfinished">Otvorite datoteku zapisa programa %1 iz trenutne podatkovne mape. Može potrajati nekoliko sekundi za velike datoteke zapisa.</translation>
</message>
@@ -2031,14 +2921,59 @@
<translation type="unfinished">Povećajte veliÄinu fonta</translation>
</message>
<message>
+ <source>Permissions</source>
+ <translation type="unfinished">Dopuštenja</translation>
+ </message>
+ <message>
+ <source>The direction and type of peer connection: %1</source>
+ <translation type="unfinished">Smjer i tip peer konekcije: %1</translation>
+ </message>
+ <message>
+ <source>Direction/Type</source>
+ <translation type="unfinished">Smjer/tip</translation>
+ </message>
+ <message>
+ <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
+ <translation type="unfinished">Mrežni protokoli kroz koje je spojen ovaj peer: IPv4, IPv6, Onion, I2P, ili CJDNS.</translation>
+ </message>
+ <message>
<source>Services</source>
<translation type="unfinished">Usluge</translation>
</message>
<message>
+ <source>Whether the peer requested us to relay transactions.</source>
+ <translation type="unfinished">Je li peer od nas zatražio prijenos transakcija.</translation>
+ </message>
+ <message>
+ <source>Wants Tx Relay</source>
+ <translation type="unfinished">Želi Tx prijenos</translation>
+ </message>
+ <message>
+ <source>High bandwidth BIP152 compact block relay: %1</source>
+ <translation type="unfinished">Visoka razina BIP152 kompaktnog blok prijenosa: %1</translation>
+ </message>
+ <message>
+ <source>High Bandwidth</source>
+ <translation type="unfinished">Visoka razina prijenosa podataka</translation>
+ </message>
+ <message>
<source>Connection Time</source>
<translation type="unfinished">Trajanje veze</translation>
</message>
<message>
+ <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
+ <translation type="unfinished">Vrijeme prošlo od kada je ovaj peer primio novi bloka koji je prošao osnovne provjere validnosti.</translation>
+ </message>
+ <message>
+ <source>Last Block</source>
+ <translation type="unfinished">Zadnji blok</translation>
+ </message>
+ <message>
+ <source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
+ <extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
+ <translation type="unfinished">Vrijeme prošlo od kada je ovaj peer primio novu transakciju koja je prihvaćena u naš mempool.</translation>
+ </message>
+ <message>
<source>Last Send</source>
<translation type="unfinished">Zadnja pošiljka</translation>
</message>
@@ -2103,6 +3038,53 @@
<translation type="unfinished">Izlazne:</translation>
</message>
<message>
+ <source>Inbound: initiated by peer</source>
+ <extracomment>Explanatory text for an inbound peer connection.</extracomment>
+ <translation type="unfinished">Ulazna: pokrenuo peer</translation>
+ </message>
+ <message>
+ <source>Outbound Full Relay: default</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment>
+ <translation type="unfinished">Izlazni potpuni prijenos: zadano</translation>
+ </message>
+ <message>
+ <source>Outbound Block Relay: does not relay transactions or addresses</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Izlazni blok prijenos: ne prenosi transakcije ili adrese</translation>
+ </message>
+ <message>
+ <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
+ <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment>
+ <translation type="unfinished">PriruÄnik za izlazeće (?): dodano koristeći RPC %1 ili %2/%3 konfiguracijske opcije</translation>
+ </message>
+ <message>
+ <source>Outbound Feeler: short-lived, for testing addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Izlazni ispipavaÄ: kratkotrajan, za testiranje adresa</translation>
+ </message>
+ <message>
+ <source>Outbound Address Fetch: short-lived, for soliciting addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment>
+ <translation type="unfinished">Dohvaćanje izlaznih adresa: kratkotrajno, za traženje adresa</translation>
+ </message>
+ <message>
+ <source>we selected the peer for high bandwidth relay</source>
+ <translation type="unfinished">odabrali smo peera za brzopodatkovni prijenos</translation>
+ </message>
+ <message>
+ <source>the peer selected us for high bandwidth relay</source>
+ <translation type="unfinished">peer odabran za brzopodatkovni prijenos</translation>
+ </message>
+ <message>
+ <source>no high bandwidth relay selected</source>
+ <translation type="unfinished">brzopodatkovni prijenos nije odabran</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Kopiraj adresu</translation>
+ </message>
+ <message>
<source>&amp;Disconnect</source>
<translation type="unfinished">&amp;Odspojite</translation>
</message>
@@ -2111,6 +3093,10 @@
<translation type="unfinished">1 &amp;sat</translation>
</message>
<message>
+ <source>1 d&amp;ay</source>
+ <translation type="unfinished">1 d&amp;an</translation>
+ </message>
+ <message>
<source>1 &amp;week</source>
<translation type="unfinished">1 &amp;tjedan</translation>
</message>
@@ -2119,6 +3105,11 @@
<translation type="unfinished">1 &amp;godinu</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Kopiraj IP/Netmask</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Ukinite zabranu</translation>
</message>
@@ -2135,6 +3126,28 @@
<translation type="unfinished">IzvrÅ¡ava se naredba koristeći novÄanik "%1"</translation>
</message>
<message>
+ <source>Welcome to the %1 RPC console.
+Use up and down arrows to navigate history, and %2 to clear screen.
+Use %3 and %4 to increase or decrease the font size.
+Type %5 for an overview of available commands.
+For more information on using this console, type %6.
+
+%7WARNING: 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.%8</source>
+ <extracomment>RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</extracomment>
+ <translation type="unfinished">Dobrodošli u %1 RPC konzolu.
+Koristite strelice za gore i dolje kako biste navigirali kroz povijest, i %2 za micanje svega sa zaslona.
+Koristite %3 i %4 za smanjivanje i povećavanje veliÄine fonta.
+Utipkajte %5 za pregled svih dosrupnih komandi.
+Za više informacija o korištenju ove konzile, utipkajte %6.
+
+%7UPOZORENJE: Prevaranti su uvijek aktivni te kradu sadržaj novÄanika korisnika tako Å¡to im daju upute koje komande upisati. Nemojte koristiti ovu konzolu bez potpunog razumijevanja posljedica upisivanja komande.%8</translation>
+ </message>
+ <message>
+ <source>Executing…</source>
+ <extracomment>A console message indicating an entered command is currently being executed.</extracomment>
+ <translation type="unfinished">Izvršavam...</translation>
+ </message>
+ <message>
<source>via %1</source>
<translation type="unfinished">preko %1</translation>
</message>
@@ -2159,6 +3172,10 @@
<translation type="unfinished">Zabranite za</translation>
</message>
<message>
+ <source>Never</source>
+ <translation type="unfinished">Nikada</translation>
+ </message>
+ <message>
<source>Unknown</source>
<translation type="unfinished">Nepoznato</translation>
</message>
@@ -2194,6 +3211,10 @@
<translation type="unfinished">Opcionalan iznos koji možete zahtijevati. Ostavite ovo prazno ili unesite nulu ako ne želite zahtijevati specifiÄan iznos.</translation>
</message>
<message>
+ <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
+ <translation type="unfinished">Neobvezna oznaka za oznaÄavanje nove primateljske adrese (koristi se za identifikaciju raÄuna). TakoÄ‘er je pridružena zahtjevu za plaćanje.</translation>
+ </message>
+ <message>
<source>An optional message that is attached to the payment request and may be displayed to the sender.</source>
<translation type="unfinished">Izborna poruka je priložena zahtjevu za plaćanje i može se prikazati pošiljatelju.</translation>
</message>
@@ -2234,13 +3255,41 @@
<translation type="unfinished">Kopiraj &amp;URI</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopiraj adresu</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiraj &amp;oznaku</translation>
+ </message>
+ <message>
+ <source>Copy &amp;message</source>
+ <translation type="unfinished">Kopiraj &amp;poruku</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopiraj &amp;iznos</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">Ne može se otkljuÄati novÄanik.</translation>
</message>
- </context>
+ <message>
+ <source>Could not generate new %1 address</source>
+ <translation type="unfinished">Ne mogu generirati novu %1 adresu</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>Request payment to …</source>
+ <translation type="unfinished">Zatraži plaćanje na...</translation>
+ </message>
+ <message>
+ <source>Address:</source>
+ <translation type="unfinished">Adresa:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation type="unfinished">Iznos:</translation>
</message>
@@ -2265,6 +3314,18 @@
<translation type="unfinished">Kopiraj &amp;adresu</translation>
</message>
<message>
+ <source>&amp;Verify</source>
+ <translation type="unfinished">&amp;Verificiraj</translation>
+ </message>
+ <message>
+ <source>Verify this address on e.g. a hardware wallet screen</source>
+ <translation type="unfinished">Verificiraj ovu adresu na npr. zaslonu hardverskog novÄanika</translation>
+ </message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Spremi sliku...</translation>
+ </message>
+ <message>
<source>Payment information</source>
<translation type="unfinished">Informacije o uplati</translation>
</message>
@@ -2395,15 +3456,31 @@
<translation type="unfinished">Obriši sva polja</translation>
</message>
<message>
+ <source>Inputs…</source>
+ <translation type="unfinished">Inputi...</translation>
+ </message>
+ <message>
<source>Dust:</source>
<translation type="unfinished">Prah:</translation>
</message>
<message>
+ <source>Choose…</source>
+ <translation type="unfinished">Odaberi...</translation>
+ </message>
+ <message>
<source>Hide transaction fee settings</source>
<translation type="unfinished">Sakrijte postavke za transakcijske provizije
</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 rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation type="unfinished">Zadajte prilagodenu 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>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">Kada je kapacitet transakcija manja od prostora u blokovima, rudari i Ävorovi prenositelji mogu zatražiti minimalnu naknadu. Prihvatljivo je platiti samo ovu minimalnu naknadu, ali budite svjesni da ovime može nastati transakcija koja se nikad ne potvrÄ‘uje Äim je potražnja za koriÅ¡tenjem Bitcoina veća nego Å¡to mreža može obraditi.</translation>
</message>
@@ -2412,6 +3489,10 @@
<translation type="unfinished">Preniska naknada može rezultirati transakcijom koja se nikad ne potvrÄ‘uje (vidite oblaÄić)</translation>
</message>
<message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source>
+ <translation type="unfinished">(Pametna procjena naknada joÅ¡ nije inicijalizirana. InaÄe traje nekoliko blokova...)</translation>
+ </message>
+ <message>
<source>Confirmation time target:</source>
<translation type="unfinished">Ciljno vrijeme potvrde:</translation>
</message>
@@ -2472,10 +3553,28 @@
<translation type="unfinished">%1 (%2 blokova)</translation>
</message>
<message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">Potpiši na uređaju</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">Prvo poveži svoj hardverski novÄanik.</translation>
+ </message>
+ <message>
+ <source>Set external signer script path in Options -&gt; Wallet</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Postavi put za vanjsku skriptu potpisnika u Opcije -&gt; NovÄanik</translation>
+ </message>
+ <message>
<source>Cr&amp;eate Unsigned</source>
<translation type="unfinished">Cr&amp;eate nije potpisan</translation>
</message>
<message>
+ <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <translation type="unfinished">Stvara djelomiÄno potpisanu Bitcoin transakciju (Partially Signed Bitcoin Transaction - PSBT) za upotrebu sa npr. novÄanikom %1 koji nije povezan s mrežom ili sa PSBT kompatibilnim hardverskim novÄanikom.</translation>
+ </message>
+ <message>
<source> from wallet '%1'</source>
<translation type="unfinished">iz novÄanika '%1'</translation>
</message>
@@ -2488,10 +3587,41 @@
<translation type="unfinished">%1 na %2</translation>
</message>
<message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">Kliknite "Prikažite detalje..." kako biste pregledali popis primatelja</translation>
+ </message>
+ <message>
<source>Sign failed</source>
<translation type="unfinished">Potpis nije uspio</translation>
</message>
<message>
+ <source>External signer not found</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Vanjski potpisnik nije pronađen</translation>
+ </message>
+ <message>
+ <source>External signer failure</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Neuspješno vanjsko potpisivanje</translation>
+ </message>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">Spremi podatke transakcije</translation>
+ </message>
+ <message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">DjelomiÄno potpisana transakcija (binarno)</translation>
+ </message>
+ <message>
+ <source>PSBT saved</source>
+ <translation type="unfinished">PSBT spremljen</translation>
+ </message>
+ <message>
+ <source>External balance:</source>
+ <translation type="unfinished">Vanjski balans:</translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">ili</translation>
</message>
@@ -2500,6 +3630,21 @@
<translation type="unfinished">Možete kasnije povećati naknadu (javlja Replace-By-Fee, BIP-125).</translation>
</message>
<message>
+ <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment>
+ <translation type="unfinished">Molimo pregledajte svoj prijedlog transakcije. Ovo će stvoriti djelomiÄno potpisanu Bitcoin transakciju (PBST) koju možete spremiti ili kopirati i zatim potpisati sa npr. novÄanikom %1 koji nije povezan s mrežom ili sa PSBT kompatibilnim hardverskim novÄanikom.</translation>
+ </message>
+ <message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Želite li kreirati ovu transakciju?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Molimo pregledajte svoju transakciju. Možete kreirarti i poslati ovu transakciju ili kreirati djelomiÄno potpisanu Bitcoin transakciju (PBST) koju možete spremiti ili kopirati i zatim potpisati sa npr. novÄanikom %1 koji nije povezan s mrežom ili sa PSBT kompatibilnim hardverskim novÄanikom.</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Molim vas, pregledajte svoju transakciju.</translation>
@@ -2552,16 +3697,12 @@
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Naknada veća od %1 smatra se apsurdno visokim naknadom.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Zahtjev za plaćanje istekao.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
+ <numerusform>Procijenjeno je da će potvrÄ‘ivanje poÄeti unutar %n blokova.</numerusform>
</translation>
</message>
<message>
@@ -2636,14 +3777,6 @@
<translation type="unfinished">Poruka:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Ovo je neautenticiran zahtjev za plaćanje.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">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 type="unfinished">Unesite oznaku za ovu adresu kako bi ju dodali u vaš adresar</translation>
</message>
@@ -2651,14 +3784,6 @@
<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 type="unfinished">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 type="unfinished">Primatelj plaćanja:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Zapis:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -2666,7 +3791,11 @@
<source>Send</source>
<translation type="unfinished">Pošalji</translation>
</message>
- </context>
+ <message>
+ <source>Create Unsigned</source>
+ <translation type="unfinished">Kreiraj nepotpisano</translation>
+ </message>
+</context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
@@ -2811,33 +3940,36 @@
</message>
</context>
<context>
- <name>TransactionDesc</name>
+ <name>SplashScreen</name>
<message>
- <source>conflicted with a transaction with %1 confirmations</source>
- <translation type="unfinished">subokljen s transakcijom broja potvrde %1</translation>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished">(pritisnite q kako bi ugasili i nastavili kasnije)</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/nepotvrđeno, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">u memorijskom bazenu</translation>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">pritisnite q za gašenje</translation>
</message>
+</context>
+<context>
+ <name>TransactionDesc</name>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">nije u memorijskom bazenu</translation>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
+ <translation type="unfinished">subokljen s transakcijom broja potvrde %1</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">napušteno</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/nepotvrđeno</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 potvrda</translation>
</message>
<message>
@@ -2883,9 +4015,9 @@
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>matures in %n more block(s)</numerusform>
+ <numerusform>matures in %n more block(s)</numerusform>
+ <numerusform>dozrijeva za još %n blokova</numerusform>
</translation>
</message>
<message>
@@ -3138,10 +4270,64 @@
<translation type="unfinished">Min iznos</translation>
</message>
<message>
+ <source>Range…</source>
+ <translation type="unfinished">Raspon...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopiraj adresu</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiraj &amp;oznaku</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopiraj &amp;iznos</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">Kopiraj &amp;ID transakcije</translation>
+ </message>
+ <message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">Kopiraj &amp;sirovu transakciju</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">Kopiraj sve transakcijske &amp;detalje</translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">&amp;Prikaži detalje transakcije</translation>
+ </message>
+ <message>
+ <source>Increase transaction &amp;fee</source>
+ <translation type="unfinished">Povećaj transakcijsku &amp;naknadu</translation>
+ </message>
+ <message>
+ <source>A&amp;bandon transaction</source>
+ <translation type="unfinished">&amp;Napusti transakciju</translation>
+ </message>
+ <message>
+ <source>&amp;Edit address label</source>
+ <translation type="unfinished">&amp;Izmjeni oznaku adrese</translation>
+ </message>
+ <message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Prikazi u %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Izvozite povijest transakcija</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Datoteka podataka odvojenih zarezima (*.csv)</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">Potvrđeno</translation>
</message>
@@ -3193,6 +4379,14 @@
<context>
<name>WalletFrame</name>
<message>
+ <source>No wallet has been loaded.
+Go to File &gt; Open Wallet to load a wallet.
+- OR -</source>
+ <translation type="unfinished">Nijedan novÄanik nije uÄitan.
+Idi na Datoteka &gt; Otvori novÄanik za uÄitanje novÄanika.
+- ILI -</translation>
+ </message>
+ <message>
<source>Create a new wallet</source>
<translation type="unfinished">Stvorite novi novÄanik</translation>
</message>
@@ -3200,7 +4394,27 @@
<source>Error</source>
<translation type="unfinished">Greška</translation>
</message>
- </context>
+ <message>
+ <source>Unable to decode PSBT from clipboard (invalid base64)</source>
+ <translation type="unfinished">Nije moguće dekodirati PSBT iz međuspremnika (nevažeći base64)</translation>
+ </message>
+ <message>
+ <source>Load Transaction Data</source>
+ <translation type="unfinished">UÄitaj podatke transakcije</translation>
+ </message>
+ <message>
+ <source>Partially Signed Transaction (*.psbt)</source>
+ <translation type="unfinished">DjelomiÄno potpisana transakcija (*.psbt)</translation>
+ </message>
+ <message>
+ <source>PSBT file must be smaller than 100 MiB</source>
+ <translation type="unfinished">PSBT datoteka mora biti manja od 100 MB</translation>
+ </message>
+ <message>
+ <source>Unable to decode PSBT</source>
+ <translation type="unfinished">Nije moguće dekodirati PSBT</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
<message>
@@ -3233,6 +4447,10 @@
<translation type="unfinished">Nova naknada:</translation>
</message>
<message>
+ <source>Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
+ <translation type="unfinished">Upozorenje: Ovo može platiti dodatnu naknadu smanjenjem change outputa ili dodavanjem inputa, po potrebi. Može dodati novi change output ako jedan već ne postoji. Ove promjene bi mogle smanjiti privatnost.</translation>
+ </message>
+ <message>
<source>Confirm fee bump</source>
<translation type="unfinished">Potvrdite povećanje naknade</translation>
</message>
@@ -3253,6 +4471,10 @@
<translation type="unfinished">Transakcija ne može biti izvršena.</translation>
</message>
<message>
+ <source>Can't display address</source>
+ <translation type="unfinished">Ne mogu prikazati adresu</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">uobiÄajeni novÄanik</translation>
</message>
@@ -3272,6 +4494,11 @@
<translation type="unfinished">Arhiviranje novÄanika</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Podaci novÄanika</translation>
+ </message>
+ <message>
<source>Backup Failed</source>
<translation type="unfinished">Arhiviranje nije uspjelo</translation>
</message>
diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts
index 2bcaac0552..23c44087d8 100644
--- a/src/qt/locale/bitcoin_hu.ts
+++ b/src/qt/locale/bitcoin_hu.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">A cím vagy címke szerkeszteséhez kattintson a jobb gombbal</translation>
+ <translation type="unfinished">A cím vagy címke szerkesztéséhez kattintson a jobb gombbal</translation>
</message>
<message>
<source>Create a new address</source>
@@ -47,11 +47,11 @@
</message>
<message>
<source>Choose the address to send coins to</source>
- <translation type="unfinished">Kedvezményezett címének kiválasztása</translation>
+ <translation type="unfinished">Válassza ki a küldési címet kimenő utalásokhoz</translation>
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation type="unfinished">Jóváírási cím kiválasztása</translation>
+ <translation type="unfinished">Válassza ki a fogadó címet beérkező utalásokhoz</translation>
</message>
<message>
<source>C&amp;hoose</source>
@@ -76,11 +76,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Copy Address</source>
- <translation type="unfinished">&amp;Cím másolása</translation>
+ <translation type="unfinished">Cím &amp;másolása</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation type="unfinished">Másolás és Címkézés</translation>
+ <translation type="unfinished">Másolás és &amp;címkézés</translation>
</message>
<message>
<source>&amp;Edit</source>
@@ -98,7 +98,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
- <translation type="unfinished">Hiba történt a címlista %1 mentésekor. Kérem próbálja újra.</translation>
+ <translation type="unfinished">Hiba történt a címlista %1 mentésekor. Kérem próbálja újra.</translation>
</message>
<message>
<source>Exporting Failed</source>
@@ -176,7 +176,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Enter the new passphrase for 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 type="unfinished">Ãrja be a tárca új jelszavát. &lt;br/&gt;A jelszó összetétele a következÅ‘: &lt;b&gt;tíz vagy annál több véletlenszerű karakter&lt;/b&gt;, vagy &lt;b&gt;nyolc vagy annál több szó&lt;/b&gt;. </translation>
+ <translation type="unfinished">Ãrja be a tárca új jelszavát. &lt;br/&gt;Használjon &lt;b&gt;legalább tíz véletlenszerű karakterbÅ‘l&lt;/b&gt;, vagy &lt;b&gt;legalább nyolc szóból&lt;/b&gt; álló jelszót.</translation>
</message>
<message>
<source>Enter the old passphrase and new passphrase for the wallet.</source>
@@ -245,6 +245,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">A beállítások fájl %1 sérült vagy érvénytelen.</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">Ajajj, nagy baj van: Runaway exception!</translation>
+ </message>
+ <message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
<translation type="unfinished">Végzetes hiba történt %1 nem tud biztonságban továbblépni így most kilép.</translation>
</message>
@@ -367,31 +375,31 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n másodperc</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n perc</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n óra</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n nap</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n hét</numerusform>
</translation>
</message>
<message>
@@ -401,7 +409,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n év</numerusform>
</translation>
</message>
</context>
@@ -429,11 +437,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
- <translation type="unfinished">Nem sikerült a tárcát %iverzióról %iverzióra vissza módosítani. A tárca verzió változatlan maradt.</translation>
+ <translation type="unfinished">Nem sikerült a tárcát %i verzióról %i verzióra módosítani. A tárca verziója változatlan maradt.</translation>
</message>
<message>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
- <translation type="unfinished">Az %s adatkönyvtár nem zárható. A %s valószínűleg fut már.</translation>
+ <translation type="unfinished">Az %s adatkönyvtár nem zárolható. A %s valószínűleg fut már.</translation>
</message>
<message>
<source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
@@ -468,10 +476,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Hiba: Régi típusú tárcák csak "legacy", "p2sh-segwit" és "bech32" címformátumokat támogatják</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Hiba: Figyelés a bejövő kapcsolatokra sikertelen (a listen hibaüzenete: %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Díjbecslés sikertelen. Alapértelmezett díj le van tiltva. Várjon néhány blokkot vagy engedélyezze a -fallbackfee -t.</translation>
</message>
@@ -616,6 +620,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nem lehet írni a '%s' könyvtárba; ellenőrizze a jogosultságokat.</translation>
</message>
<message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">A -txindex frissítése nem fejezhető be mivel egy korábbi verzió kezdte el. Indítsa újra az előző verziót vagy futtassa a teljes -reindex parancsot.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s kérés figyel a(z) %u porton. Ennek a portnak a megítélése "rossz" ezért valószínűtlen, hogy más Bitcoin Core partner ezen keresztül csatlakozna. Részletekért és teljes listáért lásd doc/p2p-bad-ports.md.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Nem lehetséges a megadott kapcsolatok és az addrman által felderített kapcsolatok egyidejű használata.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Hiba %s betöltése közben: Külső aláíró tárca betöltése külső aláírók támogatása nélkül</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Az érvénytelen peers.dat fájl átnevezése sikertelen. Kérjük mozgassa vagy törölje, majd próbálja újra.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">A konfigurációs beálltás %s kizárólag az %s hálózatra vonatkozik amikor a [%s] szekcióban van.</translation>
</message>
@@ -657,11 +681,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error initializing block database</source>
- <translation type="unfinished">A blokkadatbázis inicializálása nem sikerült</translation>
+ <translation type="unfinished">A blokkadatbázis előkészítése nem sikerült</translation>
</message>
<message>
<source>Error initializing wallet database environment %s!</source>
- <translation type="unfinished">A tárca-adatbázis inicializálása nem sikerült: %s!</translation>
+ <translation type="unfinished">A tárca-adatbázis előkészítése nem sikerült: %s!</translation>
</message>
<message>
<source>Error loading %s</source>
@@ -696,12 +720,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">A tárca adatbázisból a következő rekord beolvasása sikertelen.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Hiba a blokk adatbázis betöltése közben</translation>
- </message>
- <message>
<source>Error: Couldn't create cursor into database</source>
- <translation type="unfinished">Hiba: Nem tudott kurzort az adatbázisba készíteni</translation>
+ <translation type="unfinished">Hiba: Kurzor létrehozása az adatbázisba sikertelen.</translation>
</message>
<message>
<source>Error: Disk space is low for %s</source>
@@ -721,7 +741,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error: Keypool ran out, please call keypoolrefill first</source>
- <translation type="unfinished">A címraktár kiürült, kérjük előbb adja ki a keypoolrefill parancsot.</translation>
+ <translation type="unfinished">A címraktár kiürült, előbb adja ki a keypoolrefill parancsot.</translation>
</message>
<message>
<source>Error: Missing checksum</source>
@@ -732,6 +752,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Hiba: Nem áll rendelkezésre %s cím.</translation>
</message>
<message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">Hiba: Ez a pénztárca már használja az SQLite-t</translation>
+ </message>
+ <message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">Hiba: Nem lehet a %u verziót uint32_t-ként értelmezni</translation>
</message>
@@ -757,7 +781,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Ignoring duplicate -wallet %s.</source>
- <translation type="unfinished">A duplikált -wallet %s figyelmen kívül hagyva.</translation>
+ <translation type="unfinished">Az ismétlődő -wallet %s figyelmen kívül hagyva.</translation>
</message>
<message>
<source>Importing…</source>
@@ -781,15 +805,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Invalid -i2psam address or hostname: '%s'</source>
- <translation type="unfinished">Érvénytelen -i2psam cím vagy hostname: '%s'</translation>
+ <translation type="unfinished">Érvénytelen -i2psam cím vagy kiszolgáló: '%s'</translation>
</message>
<message>
<source>Invalid -onion address or hostname: '%s'</source>
- <translation type="unfinished">Érvénytelen -onion cím vagy hosztnév: '%s'</translation>
+ <translation type="unfinished">Érvénytelen -onion cím vagy kiszolgáló: '%s'</translation>
</message>
<message>
<source>Invalid -proxy address or hostname: '%s'</source>
- <translation type="unfinished">Érvénytelen -proxy cím vagy hosztnév: '%s'</translation>
+ <translation type="unfinished">Érvénytelen -proxy cím vagy kiszolgáló: '%s'</translation>
</message>
<message>
<source>Invalid P2P permission: '%s'</source>
@@ -848,10 +872,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nincsenek rendelkezésre álló címek</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Proxy szerver nincs megadva. A megadás módja: -proxy=&lt;ip&gt; vagy -proxy=&lt;ip:port&gt;</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">Nincs elég fájlleíró.</translation>
</message>
@@ -860,10 +880,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nyesett üzemmódot nem lehet negatív értékkel konfigurálni.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">A Prune mód nem kompatibilis a -coinstatsindex funkcióval.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">A -txindex nem használható nyesett üzemmódban.</translation>
</message>
@@ -921,7 +937,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Specified blocks directory "%s" does not exist.</source>
- <translation type="unfinished">A megadott blokkönyvtár "%s" nem létezik.</translation>
+ <translation type="unfinished">A megadott blokk könyvtár "%s" nem létezik.</translation>
</message>
<message>
<source>Starting network threads…</source>
@@ -964,6 +980,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tranzakció összege nem lehet negatív</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">Tartományon kivüli tranzakció visszajáró index</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">A tranzakcóihoz tartozó mempool elődlánc túl hosszú</translation>
</message>
@@ -1036,10 +1056,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nem támogatott naplózási kategória %s=%s</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">UTXO adatbázis frissítése</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">A felhasználói ügynök megjegyzés (%s) veszélyes karaktert tartalmaz.</translation>
</message>
@@ -1100,7 +1116,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Modify configuration options for %1</source>
- <translation type="unfinished">%1 beállítások módosítása</translation>
+ <translation type="unfinished">%1 beállításainak módosítása</translation>
</message>
<message>
<source>Create a new wallet</source>
@@ -1145,7 +1161,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Options…</source>
- <translation type="unfinished">&amp;Opciók…</translation>
+ <translation type="unfinished">&amp;Beállítások…</translation>
</message>
<message>
<source>&amp;Encrypt Wallet…</source>
@@ -1153,7 +1169,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
- <translation type="unfinished">A tárcához tartozó privát kulcsok titkosítása</translation>
+ <translation type="unfinished">A tárcádhoz tartozó privát kulcsok titkosítása</translation>
</message>
<message>
<source>&amp;Backup Wallet…</source>
@@ -1169,7 +1185,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation type="unfinished">Üzenetek aláírása a Bitcoin-címeivel, amivel bizonyíthatja hogy a cím az Öné</translation>
+ <translation type="unfinished">Üzenetek aláírása a Bitcoin-címmeiddel, amivel bizonyítod, hogy a cím a sajátod</translation>
</message>
<message>
<source>&amp;Verify message…</source>
@@ -1258,7 +1274,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n blokk feldolgozva a tranzakciótörténetből.</numerusform>
</translation>
</message>
<message>
@@ -1338,6 +1354,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tárca bezárása</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Tárca visszaállítása...</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Összes tárca bezárása</translation>
</message>
@@ -1362,6 +1383,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nincs elérhető tárca</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Tárca adat</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Tárca neve</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Ablak</translation>
</message>
@@ -1377,11 +1408,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 kliens</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Elrejt</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">&amp;Mutat</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n aktív kapcsolat a Bitcoin hálózathoz.</numerusform>
</translation>
</message>
<message>
@@ -1462,15 +1501,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
- <translation type="unfinished">HD kulcs generálás &lt;b&gt;tiltva&lt;/b&gt;</translation>
+ <translation type="unfinished">HD kulcs generálás &lt;b&gt;letiltva&lt;/b&gt;</translation>
</message>
<message>
<source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
- <translation type="unfinished">Privát kulcs &lt;b&gt;inaktív&lt;/b&gt;</translation>
+ <translation type="unfinished">Privát kulcs &lt;b&gt;letiltva&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 type="unfinished">A tárca &lt;b&gt;titkosítva&lt;/b&gt; és jelenleg &lt;b&gt;nyitva&lt;/b&gt;.</translation>
+ <translation type="unfinished">A tárca &lt;b&gt;titkosítva&lt;/b&gt; és jelenleg &lt;b&gt;feloldva&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>
@@ -1485,7 +1524,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>UnitDisplayStatusBarControl</name>
<message>
<source>Unit to show amounts in. Click to select another unit.</source>
- <translation type="unfinished">Egység, amelyben az összegek meg lesznek jelenítve. Kattintson ide, ha másik egységet szeretne kiválasztani.</translation>
+ <translation type="unfinished">Egység, amelyben az összegek lesznek megjelenítve. Kattintson ide másik egység kiválasztásához.</translation>
</message>
</context>
<context>
@@ -1667,7 +1706,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">Nem lehet az aláírókat listázni</translation>
</message>
-</context>
+ </context>
<context>
<name>LoadWalletsActivity</name>
<message>
@@ -1698,7 +1737,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Open Wallet</source>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
- <translation type="unfinished">Tárca megnyitása</translation>
+ <translation type="unfinished">Tárca Megnyitása</translation>
</message>
<message>
<source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
@@ -1707,6 +1746,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">A pénztárca helyreállítása nem sikerült</translation>
+ </message>
+ </context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1765,7 +1812,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
- <translation type="unfinished">Üres tárca készítése. Az üres tárcák kezdetben nem tartalmaznak privát kulcsokat vagy szkripteket. Később lehetséges a privát kulcsok vagy címek importálása avagy egy HD mag beállítása.</translation>
+ <translation type="unfinished">Üres tárca készítése. Az üres tárcák kezdetben nem tartalmaznak privát kulcsokat vagy szkripteket. Később lehetséges a privát kulcsok vagy címek importálása illetve egy HD mag beállítása.</translation>
</message>
<message>
<source>Make Blank Wallet</source>
@@ -1849,7 +1896,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Could not unlock wallet.</source>
- <translation type="unfinished">Nem sikerült a tárca felnyitása</translation>
+ <translation type="unfinished">Nem sikerült a tárca feloldása</translation>
</message>
<message>
<source>New key generation failed.</source>
@@ -1864,7 +1911,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>name</source>
- <translation type="unfinished">Név</translation>
+ <translation type="unfinished">név</translation>
</message>
<message>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
@@ -1881,13 +1928,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(a szükséges %1 GB-ból)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB szükséges a teljes lánchoz)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB szükségesnek)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB szükséges a teljes lánchoz)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1901,7 +1958,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(elegendő %n nappal ezelőtti biztonsági mentések visszaállításához)</numerusform>
</translation>
</message>
<message>
@@ -1910,7 +1967,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The wallet will also be stored in this directory.</source>
- <translation type="unfinished">A tárcát is ebben a könyvtárban tároljuk.</translation>
+ <translation type="unfinished">A tárca is ebben a könyvtárban tárolódik.</translation>
</message>
<message>
<source>Error: Specified data directory "%1" cannot be created.</source>
@@ -1933,10 +1990,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Mivel ez a program első indulása, megváltoztathatja, hogy a %1 hova mentse az adatokat.</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 type="unfinished">Ha az OK-ra kattint, %1 megkezdi a teljes %4 blokk lánc letöltését és feldolgozását (%2GB) a legkorábbi tranzakciókkal kezdve %3 -ben, amikor a %4 bevezetésre került.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">A blokklánc tárhelyének korlátozása erre:</translation>
</message>
@@ -2049,7 +2102,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Ismeretlen. Fejlécek szinkronizálása (%1, %2%)…</translation>
</message>
-</context>
+ </context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -2210,7 +2263,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">A Bitcoin-kliens portjának automatikus megnyitása a routeren. Ez csak akkor működik, ha a routered támogatja az UPnP-t és az engedélyezve is van rajta.</translation>
+ <translation type="unfinished">A Bitcoin-kliens portjának automatikus megnyitása a routeren. Ez csak akkor működik, ha a router támogatja az UPnP-t és az engedélyezve is van rajta.</translation>
</message>
<message>
<source>Map port using &amp;UPnP</source>
@@ -2262,7 +2315,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Show only a tray icon after minimizing the window.</source>
- <translation type="unfinished">Kicsinyítés után csak eszköztár-ikont mutass</translation>
+ <translation type="unfinished">Kicsinyítés után csak az eszköztár-ikont mutassa.</translation>
</message>
<message>
<source>&amp;Minimize to the tray instead of the taskbar</source>
@@ -2270,7 +2323,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>M&amp;inimize on close</source>
- <translation type="unfinished">K&amp;icsinyítés záráskor</translation>
+ <translation type="unfinished">K&amp;icsinyítés bezáráskor</translation>
</message>
<message>
<source>&amp;Display</source>
@@ -2325,10 +2378,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">legjobb találat "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Az itt beállított opciók felülbírálásra kerültek a parancssor vagy a konfigurációs fájl által:</translation>
- </message>
- <message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Mégse</translation>
</message>
@@ -2347,14 +2396,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Beállítások törlésének jóváhagyása.</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">A változtatások aktiválásahoz újra kell indítani a klienst.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">A kliens le fog állni. Szeretné folytatni?</translation>
</message>
<message>
@@ -2649,6 +2701,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">Partner</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Életkor</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Irány</translation>
@@ -2849,29 +2906,22 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Whether we relay addresses to this peer.</source>
- <extracomment>Tooltip text for the Address Relay field in the peer details area.</extracomment>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Továbbítsunk-e címeket ennek a partnernek.</translation>
</message>
<message>
<source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Cím Továbbítás</translation>
</message>
<message>
- <source>Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Processed field in the peer details area.</extracomment>
- <translation type="unfinished">Az eddig feldolgozott címek összesen, nem számolva a sebességkorlát miatt eldobott címeket.</translation>
- </message>
- <message>
<source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
<translation type="unfinished">Feldolgozott Címek</translation>
</message>
<message>
- <source>Total number of addresses dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area.</extracomment>
- <translation type="unfinished">Sebességkorlát miatt eldobott címek összesen.</translation>
- </message>
- <message>
<source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
<translation type="unfinished">Eldobott Címek</translation>
</message>
<message>
@@ -2912,7 +2962,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
- <translation type="unfinished">A hálózati protokoll amin keresztül ez a csomópont kapcsolódik: IPv4, IPv6, Onion, I2P vagy CJDNS.</translation>
+ <translation type="unfinished">A hálózati protokoll amin keresztül ez a partner kapcsolódik: IPv4, IPv6, Onion, I2P vagy CJDNS.</translation>
</message>
<message>
<source>Services</source>
@@ -2940,7 +2990,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
- <translation type="unfinished">A csomóponttól érkező új blokkokra vonatkozó érvényességet igazoló ellenőrzések óta eltelt idő.</translation>
+ <translation type="unfinished">A partnertől érkező új blokkokra vonatkozó érvényességet igazoló ellenőrzések óta eltelt idő.</translation>
</message>
<message>
<source>Last Block</source>
@@ -2949,7 +2999,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<message>
<source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
<extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
- <translation type="unfinished">Az eltelt idő, amióta egy új, a mempoolunkba elfogadott tranzakció érkezett ettől a társtulajdonostól.</translation>
+ <translation type="unfinished">Az eltelt idő, amióta egy új, a saját memóriahalomba elfogadott tranzakció érkezett ettől a partnertől.</translation>
</message>
<message>
<source>Last Send</source>
@@ -3153,7 +3203,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>&amp;Label:</source>
- <translation type="unfinished">Címke:</translation>
+ <translation type="unfinished">Cím&amp;ke:</translation>
</message>
<message>
<source>&amp;Message:</source>
@@ -3237,7 +3287,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Could not unlock wallet.</source>
- <translation type="unfinished">Nem sikerült a tárca megnyitása</translation>
+ <translation type="unfinished">Nem sikerült a tárca feloldása</translation>
</message>
<message>
<source>Could not generate new %1 address</source>
@@ -3386,7 +3436,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</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 type="unfinished">A tartalék díj (failback fee) használata egy órákig, napokig tartó, vagy akár sosem végbemenő tranzakciót eredményezhet. Fontolja meg, hogy Ön adja meg a díjat, vagy várjon amíg a teljes láncot érvényesíti.</translation>
+ <translation type="unfinished">A tartalék díj (fallback fee) használata egy órákig, napokig tartó, vagy akár sosem végbemenő tranzakciót eredményezhet. Fontolja meg, hogy Ön adja meg a díjat, vagy várjon amíg a teljes láncot érvényesíti.</translation>
</message>
<message>
<source>Warning: Fee estimation is currently not possible.</source>
@@ -3661,14 +3711,10 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">A díj magasabb, mint %1 ami abszurd magas díjnak számít.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">A fizetési kérelem lejárt.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>A megerősítésnek becsült kezdete %n blokkon belül várható.</numerusform>
</translation>
</message>
<message>
@@ -3743,14 +3789,6 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
<translation type="unfinished">Ãœzenet:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Ez egy nem hitelesített fizetési kérelem.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Ez egy hitelesített fizetési kérelem.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Adjon egy címkét ehhez a címhez, hogy bekerüljön a használt címek közé</translation>
</message>
@@ -3758,14 +3796,6 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
<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 type="unfinished">Egy üzenet a bitcoin: URI-hoz csatolva, amely a tranzakciócal együtt lesz eltárolva az Ön számára. Megjegyzés: Ez az üzenet nem kerül elküldésre a Bitcoin hálózaton keresztül.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Címzett:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Jegyzet:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3786,7 +3816,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>&amp;Sign Message</source>
- <translation type="unfinished">Üzenet aláírása...</translation>
+ <translation type="unfinished">Üzenet &amp;Aláírása</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>
@@ -3818,11 +3848,11 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>Sign the message to prove you own this Bitcoin address</source>
- <translation type="unfinished">Ãœzenet</translation>
+ <translation type="unfinished">Üzenet aláírása, ezzel bizonyítva, hogy Öné ez a Bitcoin cím</translation>
</message>
<message>
<source>Sign &amp;Message</source>
- <translation type="unfinished">Üzenet &amp;aláírása</translation>
+ <translation type="unfinished">Üzenet &amp;Aláírása</translation>
</message>
<message>
<source>Reset all sign message fields</source>
@@ -3830,7 +3860,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>Clear &amp;All</source>
- <translation type="unfinished">Mindent &amp;töröl</translation>
+ <translation type="unfinished">Mindent &amp;Töröl</translation>
</message>
<message>
<source>&amp;Verify Message</source>
@@ -3846,7 +3876,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>The signed message to verify</source>
- <translation type="unfinished">Az aláírt üzenet ellenőrzésre</translation>
+ <translation type="unfinished">Az ellenőrizni kívánt aláírt üzenet</translation>
</message>
<message>
<source>The signature given when the message was signed</source>
@@ -3858,7 +3888,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>Verify &amp;Message</source>
- <translation type="unfinished">Üzenet ellenőrzése</translation>
+ <translation type="unfinished">Üzenet &amp;Ellenőrzése</translation>
</message>
<message>
<source>Reset all verify message fields</source>
@@ -3874,7 +3904,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>Please check the address and try again.</source>
- <translation type="unfinished">Kérem ellenőrizze a címet és próbálja meg újra.</translation>
+ <translation type="unfinished">Ellenőrizze a címet és próbálja meg újra.</translation>
</message>
<message>
<source>The entered address does not refer to a key.</source>
@@ -3906,7 +3936,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>Please check the signature and try again.</source>
- <translation type="unfinished">Kérem ellenőrizze az aláírást és próbálja újra.</translation>
+ <translation type="unfinished">Ellenőrizze az aláírást és próbálja újra.</translation>
</message>
<message>
<source>The signature did not match the message digest.</source>
@@ -3936,30 +3966,22 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">ütközés egy %1 megerősítéssel rendelkező tranzakcióval</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/megerősítetlen, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">a memória halomban</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">nincs a memória halomban</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">elhagyott</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/megerősítetlen</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 megerősítés</translation>
</message>
<message>
@@ -4009,7 +4031,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>Beérik %n blokk múlva</numerusform>
</translation>
</message>
<message>
@@ -4140,7 +4162,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>Conflicted</source>
- <translation type="unfinished">Konfliktusos</translation>
+ <translation type="unfinished">Ellentmondásos</translation>
</message>
<message>
<source>Immature (%1 confirmations, will be available after %2)</source>
@@ -4168,7 +4190,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>Mined</source>
- <translation type="unfinished">Kibányászva</translation>
+ <translation type="unfinished">Bányászva</translation>
</message>
<message>
<source>watch-only</source>
@@ -4349,7 +4371,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished">Hiba az exportálás során</translation>
+ <translation type="unfinished">Sikertelen exportálás</translation>
</message>
<message>
<source>There was an error trying to save the transaction history to %1.</source>
@@ -4369,7 +4391,7 @@ Megjegyzés: Mivel a díj bájtonként van kiszámítva, egy "100 satoshi kvB-nk
</message>
<message>
<source>to</source>
- <translation type="unfinished">meddig</translation>
+ <translation type="unfinished">-</translation>
</message>
</context>
<context>
@@ -4415,7 +4437,7 @@ A "Fájl &gt; Tárca megnyitása" menüben tölthet be egyet.
<name>WalletModel</name>
<message>
<source>Send Coins</source>
- <translation type="unfinished">Érmék Küldése</translation>
+ <translation type="unfinished">Érmék küldése</translation>
</message>
<message>
<source>Fee bump error</source>
@@ -4512,7 +4534,7 @@ A "Fájl &gt; Tárca megnyitása" menüben tölthet be egyet.
</message>
<message>
<source>Cancel</source>
- <translation type="unfinished">Bezárás</translation>
+ <translation type="unfinished">Mégse</translation>
</message>
</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_id.ts b/src/qt/locale/bitcoin_id.ts
index fe5cfebb54..9eaae69602 100644
--- a/src/qt/locale/bitcoin_id.ts
+++ b/src/qt/locale/bitcoin_id.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">Klik-kanan untuk mengubah alamat atau label</translation>
+ <translation type="unfinished">Klik kanan untuk mengubah alamat atau label</translation>
</message>
<message>
<source>Create a new address</source>
@@ -23,7 +23,7 @@
</message>
<message>
<source>C&amp;lose</source>
- <translation type="unfinished">T&amp;utup</translation>
+ <translation type="unfinished">&amp;Tutup</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
@@ -50,10 +50,6 @@
<translation type="unfinished">Pilih alamat untuk mengirim koin</translation>
</message>
<message>
- <source>Choose the address to receive coins with</source>
- <translation type="unfinished">Piih alamat untuk menerima koin</translation>
- </message>
- <message>
<source>C&amp;hoose</source>
<translation type="unfinished">&amp;Pilih</translation>
</message>
@@ -237,22 +233,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">File pengaturan %1 mungkin rusak atau tidak valid.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">Pengecualian pelarian</translation>
</message>
<message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <translation type="unfinished">Kesalahan yang fatal telah terjadi. %1 tidak bisa berlanjut dengan selamat dan akan keluar.</translation>
+ <translation type="unfinished">Error yang fatal telah terjadi. %1 tidak bisa berlanjut dengan selamat dan akan keluar.</translation>
</message>
<message>
<source>Internal error</source>
<translation type="unfinished">Kesalahan internal</translation>
</message>
- <message>
- <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
- <translation type="unfinished">Terjadi kesalahan internal. %1 akan mencoba melanjutkan secara aman. Ini adalah bug yang tidak terduga yang dapat dilaporkan seperti penjelasan di bawah ini.</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -347,31 +343,31 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%ndetik</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n menit</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%njam</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n hari</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nminggu</numerusform>
</translation>
</message>
<message>
@@ -381,7 +377,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n tahun</numerusform>
</translation>
</message>
</context>
@@ -424,6 +420,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kesalahan membaca %s! Semua kunci dibaca dengan benar, tetapi data transaksi atau entri buku alamat mungkin hilang atau salah.</translation>
</message>
<message>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">Kesalahan membaca %s! Data transaksi mungkin hilang atau salah. Memindai ulang dompet.</translation>
+ </message>
+ <message>
<source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
<translation type="unfinished">Kesalahan: Rekaman pengenal dumpfile salah. Mendapat "%s", diharapkan "format". </translation>
</message>
@@ -440,10 +440,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kesalahan: Dompet lama hanya mendukung jenis alamat "warisan", "p2sh-segwit", dan "bech32"</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Kesalahan: Mendengarkan koneksi yang masuk gagal (dengarkan kesalahan yang dikembalikan %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Estimasi biaya gagal. Biaya fallback dimatikan. Tunggu beberapa blocks atau nyalakan -fallbackfee</translation>
</message>
@@ -480,6 +476,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Pemangkasan dikonfigurasikan di bawah minimum dari %d MiB. Harap gunakan angka yang lebih tinggi.</translation>
</message>
<message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">Mode pangkas tidak kompatibel dengan -reindex-chainstate. Gunakan full -reindex sebagai gantinya.</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 type="unfinished">Pemangkasan: sinkronisasi dompet terakhir melampaui data yang sudah dipangkas. Anda perlu -reindex (unduh seluruh blockchain lagi jika terjadi node pemangkasan)</translation>
</message>
@@ -528,6 +528,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Format berkas dompet tidak dikenal "%s" tersedia. Berikan salah satu dari "bdb" atau "sqlite". </translation>
</message>
<message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">Ditemukan format database chainstate yang tidak didukung. Silakan mulai ulang dengan -reindex-chainstate. Ini akan membangun kembali database chainstate.</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Dompet berhasil dibuat. Jenis dompet lama tidak digunakan lagi dan dukungan untuk membuat dan membuka dompet lama akan dihapus di masa mendatang.</translation>
+ </message>
+ <message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
<translation type="unfinished">Peringatan: Dumpfile dompet format "%s" tidak cocok dengan format baris perintah yang ditentukan "%s". </translation>
</message>
@@ -564,6 +572,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tidak bisa menyelesaikan -%s alamat: '%s'</translation>
</message>
<message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">Tidak bisa mengatur -forcednsseed ke benar ketika mengatur -dnsseed ke salah</translation>
+ </message>
+ <message>
<source>Cannot set -peerblockfilters without -blockfilterindex.</source>
<translation type="unfinished">Tidak dapat menyetel -peerblockfilters tanpa -blockfilterindex.</translation>
</message>
@@ -572,6 +584,78 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tidak dapat menulis ke direktori data '%s'; periksa izinnya.</translation>
</message>
<message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Opsi -reindex-chainstate tidak kompatibel dengan -blockfilterindex. Harap nonaktifkan blockfilterindex sementara saat menggunakan -reindex-chainstate, atau ganti -reindex-chainstate dengan -reindex untuk membangun kembali semua indeks sepenuhnya.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Opsi -reindex-chainstate tidak kompatibel dengan -coinstatsindex. Harap nonaktifkan sementara coinstatsindex saat menggunakan -reindex-chainstate, atau ganti -reindex-chainstate dengan -reindex untuk membangun kembali semua indeks sepenuhnya.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Opsi -reindex-chainstate tidak kompatibel dengan -txindex. Harap nonaktifkan sementara txindex saat menggunakan -reindex-chainstate, atau ganti -reindex-chainstate dengan -reindex untuk sepenuhnya membangun kembali semua indeks.</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">Diasumsikan-valid: sinkronisasi dompet terakhir melampaui data blok yang tersedia. Anda harus menunggu rantai validasi latar belakang untuk mengunduh lebih banyak blok.</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Kesalahan: Data buku alamat di dompet tidak dapat diidentifikasi sebagai dompet yang dimigrasikan</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">Kesalahan: Deskriptor duplikat dibuat selama migrasi. Dompet Anda mungkin rusak.</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Kesalahan: %s transaksi di dompet tidak dapat diidentifikasi sebagai dompet yang dimigrasikan</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">Kesalahan: Tidak dapat membuat deskriptor untuk dompet lawas ini. Pastikan dompet tidak terkunci terlebih dahulu</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">Opsi yang tidak kompatibel: -dnsseed=1 secara eksplisit ditentukan, tetapi -onlynet melarang koneksi ke IPv4/IPv6</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">Koneksi keluar dibatasi untuk Tor (-onlynet=onion) tetapi proxy untuk mencapai jaringan Tor secara eksplisit dilarang: -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">Koneksi keluar dibatasi untuk Tor (-onlynet=onion) tetapi proxy untuk mencapai jaringan Tor tidak disediakan: tidak ada -proxy, -onion atau -listenonion yang diberikan</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">Ditemukan deskriptor yang tidak dikenal. Memuat dompet %s
+
+Dompet mungkin telah dibuat pada versi yang lebih baru.
+Silakan coba jalankan versi perangkat lunak terbaru.
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">Level logging khusus kategori yang tidak didukung -loglevel=%s. Diharapkan -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Kategori yang valid: %s. Level log yang valid: %s.</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+Tidak dapat membersihkan migrasi yang gagal</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Tidak dapat memulihkan cadangan dompet..</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">Pengaturan konfigurasi untuk %s hanya diterapkan di jaringan %s saat berada di bagian [%s].</translation>
</message>
@@ -648,8 +732,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kesalahan membaca catatan berikutnya dari basis data dompet</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Kesalahan memutakhirkan basis data chainstate</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">Kesalahan: Tidak dapat menambahkan watchonly tx ke dompet watchonly</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">Kesalahan: Tidak dapat menghapus transaksi hanya menonton</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
@@ -664,6 +752,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kesalahan: Checksum dumpfile tidak cocok. Dihitung %s, diharapkan %s</translation>
</message>
<message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">Kesalahan: Gagal membuat dompet baru yang hanya dilihat</translation>
+ </message>
+ <message>
<source>Error: Got key that was not hex: %s</source>
<translation type="unfinished">Kesalahan: Mendapat kunci yang bukan hex: %s</translation>
</message>
@@ -684,10 +776,38 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kesalahan: Tidak ada %s alamat yang tersedia.</translation>
</message>
<message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">Kesalahan: Tidak semua txs watchonly dapat dihapus</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">Kesalahan: Dompet ini sudah menggunakan SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">Kesalahan: Dompet ini sudah menjadi dompet deskriptor</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">Kesalahan: Tidak dapat mulai membaca semua catatan dalam database</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">Kesalahan: Tidak dapat membuat cadangan dompet Anda</translation>
+ </message>
+ <message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">Kesalahan: Tidak dapat mengurai versi %u sebagai uint32_t </translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">Kesalahan: Tidak dapat membaca semua catatan dalam database</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">Kesalahan: Tidak dapat menghapus data buku alamat yang hanya dilihat</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
<translation type="unfinished">Kesalahan: Tidak dapat menulis catatan ke dompet baru</translation>
</message>
@@ -724,6 +844,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Inisialisasi pemeriksa kewarasan gagal. %s sedang dimatikan.</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Input tidak ditemukan atau sudah dibelanjakan</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">Saldo tidak mencukupi</translation>
</message>
@@ -760,6 +884,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Netmask tidak valid yang ditentukan di -whitelist: '%s'</translation>
</message>
<message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">Mendengarkan koneksi masuk gagal (mendengarkan kesalahan yang dikembalikan %s)</translation>
+ </message>
+ <message>
<source>Loading P2P addresses…</source>
<translation type="unfinished">Memuat alamat P2P....</translation>
</message>
@@ -776,12 +904,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Memuat dompet...</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Jumlah tidak ada</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">Perlu menentukan port dengan -whitebind: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Tidak ada server proxy yang ditentukan. Gunakan -proxy=&lt;ip&gt; atau -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Tidak ada alamat tersedia</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -792,10 +924,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Pemangkasan tidak dapat dikonfigurasi dengan nilai negatif.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Mode pangkas tidak kompatibel dengan -coinstatsindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">Mode prune tidak kompatibel dengan -txindex</translation>
</message>
@@ -904,10 +1032,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transaksi harus mempunyai paling tidak satu penerima</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">Transaksi memerlukan alamat perubahan, tetapi kami tidak dapat membuatnya.</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">Transaksi terlalu besar</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">Tidak dapat mengalokasikan memori untuk -maxsigcachesize: '%s' MiB</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation type="unfinished">Tidak bisa menghubungkan %s di komputer (Penghubung menghasilkan error %s)</translation>
</message>
@@ -920,6 +1056,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tidak dapat membuat berkas PID '%s': %s</translation>
</message>
<message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">Tidak dapat menemukan UTXO untuk input eksternal</translation>
+ </message>
+ <message>
<source>Unable to generate initial keys</source>
<translation type="unfinished">Tidak dapat membuat kunci awal</translation>
</message>
@@ -936,6 +1076,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tidak dapat memulai server HTTP. Lihat log debug untuk detailnya.</translation>
</message>
<message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">Tidak dapat membongkar dompet sebelum bermigrasi</translation>
+ </message>
+ <message>
<source>Unknown -blockfilterindex value %s.</source>
<translation type="unfinished">Jumlah -blockfilterindex yang tidak diketahui %s</translation>
</message>
@@ -956,12 +1100,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Aturan baru yang tidak diketahui diaktifkan (bit versi %i)</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">Kategori logging yang tidak didukung %s=%s.</translation>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">Level logging global yang tidak didukung -loglevel=%s. Nilai yang valid: %s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Memutakhirkan basis data UTXO</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Kategori logging yang tidak didukung %s=%s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
@@ -1089,7 +1233,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation type="unfinished">Tanda tangani sebuah pesan menggunakan alamat Bitcoin Anda untuk membuktikan bahwa Anda adalah pemiliknya</translation>
+ <translation type="unfinished">Tanda tangani sebuah pesan menggunakan alamat Bitcoin Anda untuk membuktikan bahwa Anda adalah pemilik alamat tersebut</translation>
</message>
<message>
<source>&amp;Verify message…</source>
@@ -1178,7 +1322,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n blok riwayat transaksi diproses.</numerusform>
</translation>
</message>
<message>
@@ -1258,6 +1402,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tutup wallet</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Pulihkan Dompet…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Pulihkan dompet dari file cadangan</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Tutup semua dompet</translation>
</message>
@@ -1282,6 +1436,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Tidak ada wallet tersedia</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Data Dompet</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Muat Pencadangan Dompet</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Pulihkan Dompet</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nama Dompet</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Jendela</translation>
</message>
@@ -1293,11 +1467,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 klien</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">Sembunyi</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">Tampilkan</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n koneksi yang aktif ke jaringan Bitcoin</numerusform>
</translation>
</message>
<message>
@@ -1321,6 +1503,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">aktifkan aktivitas jaringan</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Pra-Singkronisasi Header (%1%)...</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Kesalahan: %1</translation>
</message>
@@ -1559,6 +1745,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">Tidak dapat mencantumkan penandatangan</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Terlalu banyak penanda tangan eksternal ditemukan</translation>
+ </message>
</context>
<context>
<name>LoadWalletsActivity</name>
@@ -1599,6 +1789,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Pulihkan Dompet</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Memulihkan Dompet &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Pemulihan dompet gagal</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Peringatan pemulihan dompet</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Pesan pemulihan dompet</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1769,13 +1987,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(dari %1 GB yang dibutuhkan)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB ruang tersedia</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB dibutuhkan untuk rantai penuh)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(dari %n GB yang dibutuhkan)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB dibutuhkan untuk rantai penuh)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1789,7 +2017,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(cukup untuk memulihkan cadangan %n hari)</numerusform>
</translation>
</message>
<message>
@@ -1821,10 +2049,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Karena ini adalah pertama kalinya program dijalankan, Anda dapat memilih lokasi %1 akan menyimpan data.</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 type="unfinished">Ketika Anda mengklik OK, %1 akan mulai mengunduh dan memproses %4 block chain penuh (%2GB), dimulai dari transaksi-transaksi awal di %3 saat %4 diluncurkan pertama kali.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Batasi penyimpanan rantai blok menjadi </translation>
</message>
@@ -1841,6 +2065,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Sinkronisasi awal sangat berat dan mungkin akan menunjukkan permasalahan pada perangkat keras komputer Anda yang sebelumnya tidak tampak. Setiap kali Anda menjalankan %1, aplikasi ini akan melanjutkan pengunduhan dari posisi terakhir.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Ketika Anda mengklik OK, %1 akan mulai mengunduh dan memproses %4 block chain penuh (%2 GB) dimulai dari transaksi-transaksi awal di %3 saat %4 diluncurkan pertama kali.</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 type="unfinished">Apabila Anda memilih untuk membatasi penyimpanan block chain (pruning), data historis tetap akan diunduh dan diproses. Namun, data akan dihapus setelahnya untuk menjaga pemakaian disk agar tetap sedikit.</translation>
</message>
@@ -1933,6 +2161,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Tidak diketahui. Sinkronisasi Header (%1, %2%)...</translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Tidak diketahui. Pra-sinkronisasi Header (%1, %2%)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -1989,6 +2221,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Minimalisasi aplikasi ketika jendela ditutup. Ketika pilihan ini dipilih, aplikasi akan menutup seluruhnya jika anda memilih Keluar di menu yang tersedia.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Set opsi pengaturan pada jendela dialog ini tertutup oleh baris perintah:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Buka file konfigurasi %1 dari direktori kerja.</translation>
</message>
@@ -2027,10 +2263,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Set nomor thread script verifikasi. Nilai negatif sesuai dengan core yang tidak ingin digunakan di dalam system.</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Ini memungkinkan Anda atau alat pihak ketiga untuk berkomunikasi dengan node melalui perintah baris perintah dan JSON-RPC.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Aktifkan server R&amp;PC</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">D&amp;ompet</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Apakah akan menetapkan biaya pengurangan dari jumlah sebagai default atau tidak.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Kurangi biaya dari jumlah secara default</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">Ahli</translation>
</message>
@@ -2047,6 +2303,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Perubahan saldo untuk transaksi yang belum dikonfirmasi</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Aktifkan kontrol &amp;PSBT</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Apakah akan menampilkan kontrol PSBT.</translation>
+ </message>
+ <message>
<source>External Signer (e.g. hardware wallet)</source>
<translation type="unfinished">Penandatangan eksternal (seperti dompet perangkat keras)</translation>
</message>
@@ -2147,6 +2413,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Pilihan standar unit yang ingin ditampilkan pada layar aplikasi dan saat mengirim koin.</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 type="unfinished">URL pihak ketika (misalnya sebuah block explorer) yang mumcul dalam tab transaksi sebagai konteks menu. %s dalam URL diganti dengan kode transaksi. URL dipisahkan dengan tanda vertikal |.</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;URL transaksi Pihak Ketiga</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">Ingin menunjukkan cara pengaturan koin atau tidak.</translation>
</message>
@@ -2163,10 +2437,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Font spasi tunggal di tab Ringkasan: </translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Set opsi pengaturan pada jendela dialog ini tertutup oleh baris perintah atau dalam konfigurasi file:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">&amp;YA</translation>
</message>
@@ -2189,14 +2459,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Memastikan reset pilihan</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Restart klien diperlukan untuk mengaktifkan perubahan.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Pengaturan saat ini akan dicadangkan di "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Klien akan dimatikan, apakah anda hendak melanjutkan?</translation>
</message>
<message>
@@ -2210,6 +2488,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">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>Continue</source>
+ <translation type="unfinished">Lanjutkan</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">Batal</translation>
</message>
@@ -2231,6 +2513,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Tidak dapat membaca setelan "%1", %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2336,6 +2625,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Gagal untuk menandatangani transaksi: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">Tidak dapat menandatangani input saat dompet terkunci.</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">Tidak bisa menandatangani lagi input apapun.</translation>
</message>
@@ -2405,6 +2698,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transaksi masih membutuhkan tanda tangan(s).</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Tapi tidak ada dompet yang dimuat.)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Tetapi dompet ini tidak dapat menandatangani transaksi.)</translation>
</message>
@@ -2466,6 +2763,11 @@ Jika Anda menerima kesalahan ini, Anda harus meminta pedagang untuk memberikan U
</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Umur</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Panduan</translation>
@@ -2649,6 +2951,36 @@ Jika Anda menerima kesalahan ini, Anda harus meminta pedagang untuk memberikan U
<translation type="unfinished">AS yang Dipetakan</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Apakah kita menyampaikan alamat ke rekan ini.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Alamat Relay</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Jumlah total alamat yang diterima dari rekan ini yang diproses (tidak termasuk alamat yang dihapus karena pembatasan tarif).</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Jumlah total alamat yang diterima dari rekan ini yang dihapus (tidak diproses) karena pembatasan tarif.</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Alamat Diproses</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Tarif Alamat Terbatas</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">Agen Pengguna
@@ -2855,6 +3187,11 @@ Jika Anda menerima kesalahan ini, Anda harus meminta pedagang untuk memberikan U
<translation type="unfinished">1 &amp;tahun</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Salin IP/Netmask</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Lepas ban</translation>
</message>
@@ -3338,6 +3675,16 @@ Catatan: Karena biaya dihitung berdasarkan per byte, tarif biaya "100 satoshi pe
<translation type="unfinished">Anda dapat menambah biaya kemudian (sinyal Replace-By-Fee, BIP-125).</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Apakah Anda ingin membuat transaksi ini?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Harap untuk analisi proposal transaksi anda kembali. Anda dapat membuat dan mengirim transaksi ini atau membuat transaksi bitcoin yang ditandai tangani sebagaian (PSBT) yang bisa anda simpan atau salin dan tanda tangan dengan contoh dompet offline %1, atau dompet yang kompatibel dengan PSBT</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Mohon periksa kembali transaksi anda.</translation>
@@ -3386,14 +3733,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, tarif biaya "100 satoshi pe
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Biaya yang lebih tinggi dari %1 dianggap sebagai biaya yang sangat tinggi.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Permintaan pembayaran telah kadaluarsa.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>Diperkirakan akan memulai konfirmasi dalam %n blok.</numerusform>
</translation>
</message>
<message>
@@ -3468,14 +3811,6 @@ Catatan: Karena biaya dihitung berdasarkan per byte, tarif biaya "100 satoshi pe
<translation type="unfinished">Pesan:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Ini permintaan pembayaran yang tidak diautentikasi.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Ini permintaan pembayaran yang diautentikasi.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Masukkan label untuk alamat ini untuk dimasukan dalam daftar alamat yang pernah digunakan</translation>
</message>
@@ -3483,14 +3818,6 @@ Catatan: Karena biaya dihitung berdasarkan per byte, tarif biaya "100 satoshi pe
<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 type="unfinished">Pesan yang dilampirkan ke bitcoin: URI yang akan disimpan dengan transaksi untuk referensi Anda. Catatan: Pesan ini tidak akan dikirim melalui jaringan Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Kirim Ke:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Catatan Peringatan:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3651,33 +3978,46 @@ Catatan: Karena biaya dihitung berdasarkan per byte, tarif biaya "100 satoshi pe
</message>
</context>
<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished">(tekan q untuk mematikan dan melanjutkan nanti)</translation>
+ </message>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">tekan q untuk mematikan</translation>
+ </message>
+</context>
+<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">Konflik dengan sebuah transaksi dengan %1 konfirmasi</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/belum dikonfirmasi, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">Dalam pool memory</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/belum dikonfirmasi, di kumpulan memori</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">Tidak dalam pool memory</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/belum dikonfirmasi, tidak di kumpulan memori</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">ditinggalkan</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/belum dikonfirmasi</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 konfirmasi</translation>
</message>
<message>
@@ -3719,7 +4059,7 @@ Catatan: Karena biaya dihitung berdasarkan per byte, tarif biaya "100 satoshi pe
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>matang dalam %n blok lagi</numerusform>
</translation>
</message>
<message>
@@ -3992,6 +4332,11 @@ Catatan: Karena biaya dihitung berdasarkan per byte, tarif biaya "100 satoshi pe
<translation type="unfinished">&amp;Ubah label alamat</translation>
</message>
<message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Menunjukkan %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Ekspor Riwayat Transaksi</translation>
</message>
diff --git a/src/qt/locale/bitcoin_is.ts b/src/qt/locale/bitcoin_is.ts
index 9e5ccb88b0..30d921a07d 100644
--- a/src/qt/locale/bitcoin_is.ts
+++ b/src/qt/locale/bitcoin_is.ts
@@ -601,6 +601,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts
index e573425000..f62f7106f7 100644
--- a/src/qt/locale/bitcoin_it.ts
+++ b/src/qt/locale/bitcoin_it.ts
@@ -7,7 +7,7 @@
</message>
<message>
<source>Create a new address</source>
- <translation type="unfinished">Crea un nuovo indirizzo</translation>
+ <translation type="unfinished">Crea un indirizzo nuovo</translation>
</message>
<message>
<source>&amp;New</source>
@@ -242,6 +242,10 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Il file di impostazioni %1 potrebbe essere corrotto o invalido.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">Eccezione runaway</translation>
</message>
@@ -347,36 +351,36 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n secondo</numerusform>
+ <numerusform>%n secondi</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minuto</numerusform>
+ <numerusform>%n minuti</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n ora</numerusform>
+ <numerusform>%n ore</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n giorno</numerusform>
+ <numerusform>%n giorni</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%nsettimana</numerusform>
+ <numerusform>%nsettimane</numerusform>
</translation>
</message>
<message>
@@ -386,8 +390,8 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n anno</numerusform>
+ <numerusform>%n anni</numerusform>
</translation>
</message>
</context>
@@ -454,10 +458,6 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Errore: i portafogli elettronici obsoleti supportano solo i seguenti tipi di indirizzi: "legacy", "p2sh-segwit", e "bech32"</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Errore: attesa per connessioni in arrivo fallita (errore riportato %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Stima della commissione non riuscita. Fallbackfee è disabilitato. Attendi qualche blocco o abilita -fallbackfee.</translation>
</message>
@@ -502,6 +502,10 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">La modalità epurazione è configurata al di sotto del minimo di %d MB. Si prega di utilizzare un valore più elevato.</translation>
</message>
<message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">La modalità prune è incompatibile con -reindex-chainstate. Utilizzare invece -reindex completo.</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 type="unfinished">Epurazione: l'ultima sincronizzazione del portafoglio risulta essere precedente alla eliminazione dei dati per via della modalità epurazione. È necessario eseguire un -reindex (scaricare nuovamente la catena di blocchi in caso di nodo epurato).</translation>
</message>
@@ -554,6 +558,14 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Il formato “%s†del file portafoglio fornito non è riconosciuto. si prega di fornire uno che sia “bdb†o “sqliteâ€. </translation>
</message>
<message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">Formato del database chainstate non supportato. Riavviare con -reindex-chainstate. In questo modo si ricostruisce il database dello stato della catena.</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Portafoglio creato con successo. Il tipo di portafoglio legacy è stato deprecato e il supporto per la creazione e l'apertura di portafogli legacy sarà rimosso in futuro.</translation>
+ </message>
+ <message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
<translation type="unfinished">Attenzione: il formato “%s†del file dump di portafoglio non combacia con il formato “%s†specificato nella riga di comando.</translation>
</message>
@@ -602,6 +614,98 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Impossibile scrivere nella directory dei dati ' %s'; controlla le autorizzazioni.</translation>
</message>
<message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">L'upgrade -txindex avviato su una versione precedente non può essere completato. Riavviare con la versione precedente o eseguire un -reindex completo.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s richiede di ascoltare sulla porta %u. Questa porta è considerata "cattiva" e quindi è improbabile che qualsiasi peer Bitcoin Core si colleghi ad essa. Guardare doc/p2p-bad-ports.md per i dettagli ed un elenco completo.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">L'opzione -reindex-chainstate non è compatibile con -blockfilterindex. Disattivare temporaneamente blockfilterindex mentre si usa -reindex-chainstate, oppure sostituire -reindex-chainstate con -reindex per ricostruire completamente tutti gli indici.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">L'opzione -reindex-chainstate non è compatibile con -coinstatsindex. Si prega di disabilitare temporaneamente coinstatsindex mentre si usa -reindex-chainstate, oppure di sostituire -reindex-chainstate con -reindex per ricostruire completamente tutti gli indici.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">L'opzione -reindex-chainstate non è compatibile con -txindex. Si prega di disabilitare temporaneamente txindex mentre si usa -reindex-chainstate, oppure di sostituire -reindex-chainstate con -reindex per ricostruire completamente tutti gli indici.</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">Presunto-valido: l'ultima sincronizzazione del portafoglio va oltre i dati dei blocchi disponibili. È necessario attendere che la catena di convalida in background scarichi altri blocchi.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Non e' possibile fornire connessioni specifiche e contemporaneamente usare addrman per trovare connessioni uscenti. </translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Errore caricando %s: il wallet del dispositivo esterno di firma é stato caricato senza che il supporto del dispositivo esterno di firma sia stato compilato.</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Errore: I dati della rubrica nel portafoglio non possono essere identificati come appartenenti a portafogli migrati</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">Errore: Descrittori duplicati creati durante la migrazione. Il portafoglio potrebbe essere danneggiato.</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Errore: La transazione %s nel portafoglio non può essere identificata come appartenente ai portafogli migrati.</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">Errore: Impossibile produrre descrittori per questo portafoglio legacy. Assicurarsi che il portafoglio sia prima sbloccato</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Mancata rinominazione del file peers.dat non valido. Per favore spostarlo o eliminarlo e provare di nuovo.</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">Opzioni incompatibili: -dnsseed=1 è stato specificato esplicitamente, ma -onlynet vieta le connessioni a IPv4/IPv6</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">Connessioni in uscita limitate a Tor (-onlynet=onion) ma il proxy per raggiungere la rete Tor è esplicitamente vietato: -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">Connessioni in uscita limitate a Tor (-onlynet=onion) ma il proxy per raggiungere la rete Tor non è stato dato: nessuna tra le opzioni -proxy, -onion o -listenonion è fornita</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">Trovato descrittore non riconosciuto. Caricamento del portafoglio %s
+
+Il portafoglio potrebbe essere stato creato con una versione più recente.
+Provare a eseguire l'ultima versione del software.
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">Livello di log specifico della categoria non supportato -loglevel=%s. Atteso -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Categorie valide: %s. Livelli di log validi: %s.</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+Non in grado di pulire la migrazione fallita</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Non in grado di ripristinare il backup del portafoglio.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">La configurazione di %s si applica alla rete %s soltanto nella sezione [%s]</translation>
</message>
@@ -682,8 +786,12 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Si è verificato un errore leggendo la voce successiva dal database del portafogli elettronico</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Errore durante l'aggiornamento del database chainstate</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">Errore: Impossibile aggiungere la transazione in sola consultazione al wallet in sola consultazione</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">Errore: Non in grado di rimuovere le transazioni di sola lettura</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
@@ -698,6 +806,10 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Errore: Il Cheksum del dumpfile non corrisponde. Rilevato: %s, sarebbe dovuto essere: %s</translation>
</message>
<message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">Errore: Fallimento nella creazione di un portafoglio nuovo di sola lettura</translation>
+ </message>
+ <message>
<source>Error: Got key that was not hex: %s</source>
<translation type="unfinished">Errore: Ricevuta una key che non ha hex:%s</translation>
</message>
@@ -718,10 +830,34 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Errore: Nessun %s indirizzo disponibile</translation>
</message>
<message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">Errore: Non è stato possibile cancellare tutte le transazioni in sola consultazione</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">Errore: Questo portafoglio utilizza già SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">Errore: Questo portafoglio è già un portafoglio descrittore</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">Errore: Impossibile iniziare la lettura di tutti i record del database</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">Errore: Non in grado di creare un backup del tuo portafoglio</translation>
+ </message>
+ <message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">Errore: impossibile analizzare la versione %u come uint32_t</translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">Errore: Non in grado di leggere tutti i record nel database</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
<translation type="unfinished">Errore: non è possibile scrivere la voce nel nuovo portafogli elettronico</translation>
</message>
@@ -830,10 +966,6 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Nessun indirizzo disponibile</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Nessun server proxy specificato. Usa -proxy=&lt;ip&gt; o -proxy=&lt;ip:port&gt;.</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">Non ci sono abbastanza descrittori di file disponibili.</translation>
</message>
@@ -842,10 +974,6 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">La modalità epurazione non può essere configurata con un valore negativo.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">La modalità epurazione è incompatibile con l'opzione -coinstatsindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">La modalità epurazione è incompatibile con l'opzione -txindex.</translation>
</message>
@@ -946,6 +1074,10 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Gli importi di transazione non devono essere negativi</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">La transazione cambia l' indice dell'output fuori dal limite.</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">La transazione ha una sequenza troppo lunga nella mempool</translation>
</message>
@@ -1018,10 +1150,6 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Categoria di registrazione non supportata %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Aggiornamento del database UTXO</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Il commento del User Agent (%s) contiene caratteri non sicuri.</translation>
</message>
@@ -1131,19 +1259,19 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
</message>
<message>
<source>&amp;Encrypt Wallet…</source>
- <translation type="unfinished">&amp;Cifra il portafoglio...</translation>
+ <translation type="unfinished">&amp;Cripta il portafoglio</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
- <translation type="unfinished">Cifra le chiavi private che appartengono al tuo portafoglio</translation>
+ <translation type="unfinished">Cifra le chiavi private che appartengono al tuo portamonete</translation>
</message>
<message>
<source>&amp;Backup Wallet…</source>
- <translation type="unfinished">&amp;Backup Portafoglio...</translation>
+ <translation type="unfinished">&amp;Archivia Wallet...</translation>
</message>
<message>
<source>&amp;Change Passphrase…</source>
- <translation type="unfinished">&amp;Cambia Passphrase...</translation>
+ <translation type="unfinished">&amp;Cambia Frase di sicurezza</translation>
</message>
<message>
<source>Sign &amp;message…</source>
@@ -1236,8 +1364,8 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Processati %n blocchi di cronologia di transazioni.</numerusform>
+ <numerusform> %nblocchi di cronologia di transazioni processati.</numerusform>
</translation>
</message>
<message>
@@ -1274,7 +1402,7 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
</message>
<message>
<source>Load Partially Signed Bitcoin Transaction</source>
- <translation type="unfinished">Carica Partially Signed Bitcoin Transaction</translation>
+ <translation type="unfinished">Carica Transazione Bitcoin Parzialmente Firmata (PSBT)</translation>
</message>
<message>
<source>Load PSBT from &amp;clipboard…</source>
@@ -1317,6 +1445,16 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Chiudi portafoglio</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Ripristina Portafoglio...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Ripristina un portafoglio da un file di backup</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Chiudi tutti i portafogli</translation>
</message>
@@ -1341,6 +1479,26 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Nessun portafoglio disponibile</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Dati del Portafoglio</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Carica Backup del Portafoglio</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Ripristina Portafoglio</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nome Portafoglio</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Finestra</translation>
</message>
@@ -1348,12 +1506,20 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<source>Main Window</source>
<translation type="unfinished">Finestra principale</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Nascondi</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">S&amp;come</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%nconnessione attiva alla rete Bitcoin</numerusform>
+ <numerusform>%nconnessioni attive alla rete Bitcoin</numerusform>
</translation>
</message>
<message>
@@ -1377,6 +1543,10 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Abilita attività di rete</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Pre-sincronizzazione Headers (%1%)…</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Errore: %1</translation>
</message>
@@ -1544,7 +1714,7 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
</message>
<message>
<source>Copy &amp;amount</source>
- <translation type="unfinished">Copia &amp;importo</translation>
+ <translation type="unfinished">Copi&amp;a importo</translation>
</message>
<message>
<source>Copy transaction &amp;ID and output index</source>
@@ -1635,6 +1805,10 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<source>Can't list signers</source>
<translation type="unfinished">Impossibile elencare firmatari</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Troppi firmatari esterni trovati</translation>
+ </message>
</context>
<context>
<name>LoadWalletsActivity</name>
@@ -1675,6 +1849,34 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Ripristina Portafoglio</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Ripristinando Portafoglio &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Ripristino del portafoglio non riuscito</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Avviso di ripristino del portafoglio</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Messaggio di ripristino del portafoglio</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1849,13 +2051,26 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(di %1 GB necessari)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB di spazio disponibile</numerusform>
+ <numerusform>%n GB di spazio disponibile</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB necessari per la catena completa)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(di %n GB richiesto)</numerusform>
+ <numerusform>(di %n GB richiesti)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB richiesti per la catena completa)</numerusform>
+ <numerusform>(%n GB richiesti per la catena completa)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1869,8 +2084,8 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(sufficiente per ripristinare i backup di %n giorno fa)</numerusform>
+ <numerusform>(sufficiente per ripristinare i backup di %n giorni fa)</numerusform>
</translation>
</message>
<message>
@@ -1902,10 +2117,6 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Dato che questa è la prima volta che il programma viene lanciato, puoi scegliere dove %1 salverà i suoi dati.</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 type="unfinished">Quando fai click su OK, %1 comincerà a scaricare e processare l'intera %4 catena di blocchi (%2GB) a partire dalla prime transazioni del %3 quando %4 venne inaugurato.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Limita l'archiviazione della catena di blocchi a</translation>
</message>
@@ -1918,6 +2129,10 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">La sincronizzazione iniziale è molto dispendiosa e potrebbe mettere in luce problemi harware del tuo computer che passavano prima inosservati. Ogni volta che lanci %1 continuerà a scaricare da dove si era interrotto.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Facendo clic su OK, %1 inizierà a scaricare ed elaborare l'intera catena di blocchi di %4 (%2 GB) partendo dalle prime transazioni del %3quando %4 è stato inizialmente lanciato.</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 type="unfinished">Se hai scelto di limitare lo spazio della catena di blocchi (epurazione), i dati storici devono comunque essere scaricati e processati, ma verranno cancellati in seguito per mantenere basso l'utilizzo del tuo disco.</translation>
</message>
@@ -2014,6 +2229,10 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Sconosciuto. Sincronizzazione Intestazioni in corso (%1,%2%)…</translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Sconosciuto. Pre-sincronizzazione delle intestazioni (%1, %2%)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -2070,6 +2289,10 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">Riduci ad icona invece di uscire dall'applicazione quando la finestra viene chiusa. Attivando questa opzione l'applicazione terminerà solo dopo aver selezionato Esci dal menu File.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Le azioni da riga di comando hanno precedenza su quelle impostate da questo pannello:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Apri il %1 file di configurazione dalla cartella attiva.</translation>
</message>
@@ -2091,7 +2314,7 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
</message>
<message>
<source>Prune &amp;block storage to</source>
- <translation type="unfinished">Eliminare e bloccare l'archiviazione su</translation>
+ <translation type="unfinished">Modalità "prune": elimina i blocchi dal disco dopo</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain.</source>
@@ -2294,17 +2517,13 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
<translation type="unfinished">corrispondenza più vicina "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Le impostazioni sulla riga di comando o nell'archivio di configurazione hanno precedenza su quelle impostate in questo pannello:</translation>
- </message>
- <message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Cancella</translation>
</message>
<message>
<source>Compiled without external signing support (required for external signing)</source>
<extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
- <translation type="unfinished">Compilato senza supporto per firmatario esterno (richiesto per firmare con periferiche)</translation>
+ <translation type="unfinished">Compilato senza supporto per firma esterna (richiesto per firma esterna)</translation>
</message>
<message>
<source>default</source>
@@ -2316,14 +2535,22 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Conferma ripristino opzioni</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">È necessario un riavvio del client per applicare le modifiche.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Le impostazioni attuali saranno copiate al "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Il client sarà arrestato. Si desidera procedere?</translation>
</message>
<message>
@@ -2362,6 +2589,13 @@ E' possibile firmare solo con indirizzi di tipo "legacy".</translation>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Non posso leggere l'impostazione "%1", %2,</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2615,6 +2849,11 @@ Se ricevi questo errore, dovresti richiedere al commerciante di fornire un URI c
<translation type="unfinished">Nodo</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Età</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Direzione</translation>
@@ -2803,29 +3042,32 @@ Se ricevi questo errore, dovresti richiedere al commerciante di fornire un URI c
</message>
<message>
<source>Whether we relay addresses to this peer.</source>
- <extracomment>Tooltip text for the Address Relay field in the peer details area.</extracomment>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Se gli indirizzi vengono ritrasmessi o meno a questo peer.</translation>
</message>
<message>
<source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Trasmissione dell'Indirizzo</translation>
</message>
<message>
- <source>Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Processed field in the peer details area.</extracomment>
- <translation type="unfinished">Numero totale di indirizzi elaborati, esclusi quelli scartati a causa delle limitazioni nella quota.</translation>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Totale di indirizzi ricevuti ed elaborati da questo peer (Sono esclusi gli indirizzi che sono stati eliminati a causa della limitazione di velocità).</translation>
</message>
<message>
- <source>Addresses Processed</source>
- <translation type="unfinished">Indirizzi Processati</translation>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Il numero totale di indirizzi ricevuti da questo peer che sono stati abbandonati (non elaborati) a causa della limitazione della velocità.</translation>
</message>
<message>
- <source>Total number of addresses dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area.</extracomment>
- <translation type="unfinished">Numero totale di indirizzi scartati a causa delle limitazioni della quota.</translation>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Indirizzi Processati</translation>
</message>
<message>
<source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
<translation type="unfinished">Limite di Quota per gli Indirizzi</translation>
</message>
<message>
@@ -3042,6 +3284,10 @@ Se ricevi questo errore, dovresti richiedere al commerciante di fornire un URI c
<translation type="unfinished">Esecuzione del comando senza alcun portafoglio</translation>
</message>
<message>
+ <source>Ctrl+I</source>
+ <translation type="unfinished">Ctrl+W</translation>
+ </message>
+ <message>
<source>Executing command using "%1" wallet</source>
<translation type="unfinished">Esecuzione del comando usando il portafoglio "%1"</translation>
</message>
@@ -3361,7 +3607,7 @@ Per ulteriori informazioni su come usare la console, premi %6.
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation type="unfinished">Cancellare tutti i campi del modulo.</translation>
+ <translation type="unfinished">Cancella tutti i campi del modulo.</translation>
</message>
<message>
<source>Inputs…</source>
@@ -3600,15 +3846,11 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di "
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Una commissione maggiore di %1 è considerata irragionevolmente elevata.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Richiesta di pagamento scaduta.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Si stima che la conferma inizi entro %nblocco</numerusform>
+ <numerusform>Si stima che la conferma inizi entro %n blocchi</numerusform>
</translation>
</message>
<message>
@@ -3683,14 +3925,6 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di "
<translation type="unfinished">Messaggio:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Questa è una richiesta di pagamento non autenticata.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Questa è una richiesta di pagamento autenticata.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Inserisci un'etichetta per questo indirizzo per aggiungerlo alla lista degli indirizzi utilizzati</translation>
</message>
@@ -3698,11 +3932,7 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di "
<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 type="unfinished">Messaggio incluso nel bitcoin URI e che sarà memorizzato con la transazione per tuo riferimento. Nota: Questo messaggio non sarà inviato attraverso la rete Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Pagare a:</translation>
- </message>
- </context>
+</context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -3766,7 +3996,7 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di "
</message>
<message>
<source>Clear &amp;All</source>
- <translation type="unfinished">Cancella &amp;Tutto</translation>
+ <translation type="unfinished">Cancell&amp;a Tutto</translation>
</message>
<message>
<source>&amp;Verify Message</source>
@@ -3872,30 +4102,32 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di "
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">in conflitto con una transazione con %1 conferme</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/non confermati, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">nella riserva di memoria</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/non confermata, nel pool di memoria</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">non nella riserva di memoria</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/non confermata, non nel pool di memoria</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">abbandonato</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/non confermato</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 conferme</translation>
</message>
<message>
@@ -3945,8 +4177,8 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di "
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>matura fra %n blocco di più</numerusform>
+ <numerusform>matura fra %n blocchi di più</numerusform>
</translation>
</message>
<message>
@@ -4212,7 +4444,7 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di "
</message>
<message>
<source>Copy &amp;amount</source>
- <translation type="unfinished">Copia &amp;amount</translation>
+ <translation type="unfinished">Copi&amp;a importo</translation>
</message>
<message>
<source>Copy transaction &amp;ID</source>
@@ -4348,7 +4580,7 @@ Vai su File &gt; Apri Portafoglio per caricare un portafoglio.
<name>WalletModel</name>
<message>
<source>Send Coins</source>
- <translation type="unfinished">Invia Bitcoin</translation>
+ <translation type="unfinished">Invia Monete</translation>
</message>
<message>
<source>Fee bump error</source>
@@ -4405,7 +4637,7 @@ Vai su File &gt; Apri Portafoglio per caricare un portafoglio.
</message>
<message>
<source>default wallet</source>
- <translation type="unfinished">Portafoglio predefinito:</translation>
+ <translation type="unfinished">portafoglio predefinito</translation>
</message>
</context>
<context>
@@ -4416,7 +4648,7 @@ Vai su File &gt; Apri Portafoglio per caricare un portafoglio.
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation type="unfinished">Esporta i dati della tabella corrente in un file</translation>
+ <translation type="unfinished">Esporta su file i dati contenuti nella tabella corrente</translation>
</message>
<message>
<source>Backup Wallet</source>
diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts
index 3e3e7d4329..166014baad 100644
--- a/src/qt/locale/bitcoin_ja.ts
+++ b/src/qt/locale/bitcoin_ja.ts
@@ -247,6 +247,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">設定ファイル %1 ãŒå£Šã‚Œã¦ã„ã‚‹ã‹ç„¡åŠ¹ã§ã‚ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">暴走例外ãŒç™ºç”Ÿ</translation>
</message>
@@ -379,7 +383,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform>%n 分</numerusform>
+ <numerusform>%n 記録</numerusform>
</translation>
</message>
<message numerus="yes">
@@ -391,7 +395,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform>%n æ—¥</numerusform>
+ <numerusform>%n 日々</numerusform>
</translation>
</message>
<message numerus="yes">
@@ -478,10 +482,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">エラー: レガシーウォレットã¯ã€ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚¿ã‚¤ãƒ—「legacyã€ãŠã‚ˆã³ã€Œp2sh-segwitã€ã€ã€Œbech32ã€ã®ã¿ã‚’サãƒãƒ¼ãƒˆã—ã¾ã™</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">エラー: 内å‘ãã®æŽ¥ç¶šã‚’リッスンã™ã‚‹ã®ã«å¤±æ•—ã—ã¾ã—ãŸï¼ˆ%s エラーãŒè¿”å´ã•ã‚Œã¾ã—ãŸï¼‰</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">手数料推定ã«å¤±æ•—ã—ã¾ã—ãŸã€‚代替手数料ãŒç„¡åŠ¹ã§ã™ã€‚数ブロック待ã¤ã‹ã€-fallbackfee オプションを有効ã«ã—ã¦ãã ã•ã„。</translation>
</message>
@@ -526,6 +526,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">剪定設定ãŒã€è¨­å®šå¯èƒ½æœ€å°å€¤ã® %d MiBより低ã設定ã•ã‚Œã¦ã„ã¾ã™ã€‚より大ãã„値を使用ã—ã¦ãã ã•ã„。</translation>
</message>
<message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">プルーン モード㯠-reindex-chainstate ã¨äº’æ›æ€§ãŒã‚ã‚Šã¾ã›ã‚“。代ã‚ã‚Šã«å®Œå…¨å†ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚’使用ã—ã¦ãã ã•ã„。</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 type="unfinished">剪定: 最後ã®ã‚¦ã‚©ãƒ¬ãƒƒãƒˆåŒæœŸãƒã‚¤ãƒ³ãƒˆãŒã€å‰ªå®šã•ã‚ŒãŸãƒ‡ãƒ¼ã‚¿ã‚’越ãˆã¦ã„ã¾ã™ã€‚-reindex を実行ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ (剪定ã•ã‚ŒãŸãƒŽãƒ¼ãƒ‰ã®å ´åˆã€ãƒ–ロックãƒã‚§ãƒ¼ãƒ³å…¨ä½“ã‚’å†ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ã¾ã™)</translation>
</message>
@@ -578,6 +582,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">未知ã®ã‚¦ã‚©ãƒ¬ãƒƒãƒˆãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆ"%s"ãŒæŒ‡å®šã•ã‚Œã¾ã—ãŸã€‚"bdb"ã‚‚ã—ãã¯"sqlite"ã®ã©ã¡ã‚‰ã‹ã‚’指定ã—ã¦ãã ã•ã„。</translation>
</message>
<message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ãƒã‚§ãƒ¼ãƒ³ã‚¹ãƒ†ãƒ¼ãƒˆ データベース形å¼ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸã€‚ -reindex-chainstate ã§å†èµ·å‹•ã—ã¦ãã ã•ã„。ã“ã‚Œã«ã‚ˆã‚Šã€ãƒã‚§ãƒ¼ãƒ³ã‚¹ãƒ†ãƒ¼ãƒˆ データベースãŒå†æ§‹ç¯‰ã•ã‚Œã¾ã™ã€‚</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">ウォレットãŒæ­£å¸¸ã«ä½œæˆã•ã‚Œã¾ã—ãŸã€‚レガシー ウォレット タイプã¯éžæŽ¨å¥¨ã«ãªã‚Šã€ãƒ¬ã‚¬ã‚·ãƒ¼ ウォレットã®ä½œæˆã¨ã‚ªãƒ¼ãƒ—ンã®ã‚µãƒãƒ¼ãƒˆã¯å°†æ¥çš„ã«å‰Šé™¤ã•ã‚Œã‚‹äºˆå®šã§ã™ã€‚</translation>
+ </message>
+ <message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
<translation type="unfinished">警告: ダンプファイルウォレットフォーマット"%s"ã¯ã€ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³ã§æŒ‡å®šã•ã‚ŒãŸãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆ"%s"ã¨åˆè‡´ã—ã¦ã„ã¾ã›ã‚“。</translation>
</message>
@@ -630,6 +642,94 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">以å‰ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§é–‹å§‹ã•ã‚ŒãŸ -txindex アップグレードを完了ã§ãã¾ã›ã‚“。 以å‰ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§å†èµ·å‹•ã™ã‚‹ã‹ã€ -reindex を実行ã—ã¦ãã ã•ã„。</translation>
</message>
<message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s ãƒãƒ¼ãƒˆ %u ã§ãƒªãƒƒã‚¹ãƒ³ã™ã‚‹ã‚ˆã†ã«è¦æ±‚ã—ã¾ã™ã€‚ã“ã®ãƒãƒ¼ãƒˆã¯ã€Œä¸è‰¯ã€ã¨è¦‹ãªã•ã‚Œã‚‹ãŸã‚ã€Bitcoin Core ピアãŒæŽ¥ç¶šã™ã‚‹å¯èƒ½æ€§ã¯ã»ã¨ã‚“ã©ã‚ã‚Šã¾ã›ã‚“。詳細ã¨å®Œå…¨ãªãƒªã‚¹ãƒˆã«ã¤ã„ã¦ã¯ã€doc/p2p-bad-ports.md ã‚’å‚ç…§ã—ã¦ãã ã•ã„。</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">-reindex-chainstate オプション㯠-blockfilterindex ã¨äº’æ›æ€§ãŒã‚ã‚Šã¾ã›ã‚“。 -reindex-chainstate ã®ä½¿ç”¨ä¸­ã¯ blockfilterindex を一時的ã«ç„¡åŠ¹ã«ã™ã‚‹ã‹ã€-reindex-chainstate ã‚’ -reindex ã«ç½®ãæ›ãˆã¦ã™ã¹ã¦ã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚’完全ã«å†æ§‹ç¯‰ã—ã¦ãã ã•ã„。</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">-reindex-chainstate オプション㯠-coinstatsindex ã¨äº’æ›æ€§ãŒã‚ã‚Šã¾ã›ã‚“。 -reindex-chainstate ã®ä½¿ç”¨ä¸­ã¯ä¸€æ™‚çš„ã« coinstatsindex を無効ã«ã™ã‚‹ã‹ã€-reindex-chainstate ã‚’ -reindex ã«ç½®ãæ›ãˆã¦ã™ã¹ã¦ã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚’完全ã«å†æ§‹ç¯‰ã—ã¦ãã ã•ã„。</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">-reindex-chainstate オプション㯠-txindex ã¨äº’æ›æ€§ãŒã‚ã‚Šã¾ã›ã‚“。 -reindex-chainstate ã®ä½¿ç”¨ä¸­ã¯ä¸€æ™‚çš„ã« txindex を無効ã«ã™ã‚‹ã‹ã€-reindex-chainstate ã‚’ -reindex ã«ç½®ãæ›ãˆã¦ã™ã¹ã¦ã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚’完全ã«å†æ§‹ç¯‰ã—ã¦ãã ã•ã„。</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">有効ã¨ã¿ãªã•ã‚Œã‚‹: 最後ã®ã‚¦ã‚©ãƒ¬ãƒƒãƒˆåŒæœŸã¯ã€åˆ©ç”¨å¯èƒ½ãªãƒ–ロック データを超ãˆã¦ã„ã¾ã™ã€‚ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰æ¤œè¨¼ãƒã‚§ãƒ¼ãƒ³ãŒã•ã‚‰ã«ãƒ–ロックをダウンロードã™ã‚‹ã¾ã§å¾…ã¤å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">特定ã®æŽ¥ç¶šã‚’æä¾›ã™ã‚‹ã“ã¨ã¯ã§ããšã€åŒæ™‚ã« addrman ã«ç™ºä¿¡æŽ¥ç¶šã‚’見ã¤ã‘ã•ã›ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">%s ã®ãƒ­ãƒ¼ãƒ‰ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸï¼šå¤–​​部署å者ウォレットãŒãƒ­ãƒ¼ãƒ‰ã•ã‚Œã¦ã„ã¾ã™</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">エラー: ウォレット内ã®ã‚¢ãƒ‰ãƒ¬ã‚¹å¸³ãƒ‡ãƒ¼ã‚¿ãŒã€ç§»è¡Œã•ã‚ŒãŸã‚¦ã‚©ãƒ¬ãƒƒãƒˆã«å±žã—ã¦ã„ã‚‹ã¨è­˜åˆ¥ã§ãã¾ã›ã‚“</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">エラー: 移行中ã«ä½œæˆã•ã‚ŒãŸé‡è¤‡ã—ãŸè¨˜è¿°å­ã€‚ウォレットãŒç ´æã—ã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">エラー: ウォレット内ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ %s ã¯ã€ç§»è¡Œã•ã‚ŒãŸã‚¦ã‚©ãƒ¬ãƒƒãƒˆã«å±žã—ã¦ã„ã‚‹ã¨è­˜åˆ¥ã§ãã¾ã›ã‚“</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">エラー: ã“ã®ãƒ¬ã‚¬ã‚·ãƒ¼ ウォレットã®è¨˜è¿°å­ã‚’生æˆã§ãã¾ã›ã‚“。最åˆã«ã‚¦ã‚©ãƒ¬ãƒƒãƒˆã®ãƒ­ãƒƒã‚¯ãŒè§£é™¤ã•ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">無効㪠peers.dat ファイルã®åå‰ã‚’変更ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚移動ã¾ãŸã¯å‰Šé™¤ã—ã¦ã‹ã‚‰ã€ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">互æ›æ€§ã®ãªã„オプション: -dnsseed=1 ãŒæ˜Žç¤ºçš„ã«æŒ‡å®šã•ã‚Œã¾ã—ãŸãŒã€-onlynet 㯠IPv4/IPv6 ã¸ã®æŽ¥ç¶šã‚’ç¦æ­¢ã—ã¾ã™</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">アウトãƒã‚¦ãƒ³ãƒ‰æŽ¥ç¶šã¯ Tor (-onlynet=onion) ã«åˆ¶é™ã•ã‚Œã¦ã„ã¾ã™ãŒã€Tor ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã«åˆ°é”ã™ã‚‹ãŸã‚ã®ãƒ—ロキシã¯æ˜Žç¤ºçš„ã«ç¦æ­¢ã•ã‚Œã¦ã„ã¾ã™: -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">アウトãƒã‚¦ãƒ³ãƒ‰æŽ¥ç¶šã¯ Tor (-onlynet=onion) ã«åˆ¶é™ã•ã‚Œã¦ã„ã¾ã™ãŒã€Tor ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã«åˆ°é”ã™ã‚‹ãŸã‚ã®ãƒ—ロキシã¯æä¾›ã•ã‚Œã¦ã„ã¾ã›ã‚“: -proxyã€-onionã€ã¾ãŸã¯ -listenonion ã®ã„ãšã‚Œã‚‚指定ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">èªè­˜ã§ããªã„記述å­ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸã€‚ウォレットをロードã—ã¦ã„ã¾ã™ %s
+
+ウォレットãŒæ–°ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ä½œæˆã•ã‚ŒãŸå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚
+最新ã®ã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’実行ã—ã¦ã¿ã¦ãã ã•ã„。
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„カテゴリ固有ã®ãƒ­ã‚° レベル -loglevel=%s。 -loglevel=&lt;category&gt;:&lt;loglevel&gt;. ãŒå¿…è¦ã§ã™ã€‚有効ãªã‚«ãƒ†ã‚´ãƒª:%s 。有効ãªãƒ­ã‚°ãƒ¬ãƒ™ãƒ«:%s .</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+失敗ã—ãŸç§»è¡Œã‚’クリーンアップã§ãã¾ã›ã‚“</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+ウォレットã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を復元ã§ãã¾ã›ã‚“。</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">%s ã®è¨­å®šã¯ã€ [%s] セクションã«æ›¸ã‹ã‚ŒãŸå ´åˆã®ã¿ %s ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã¸é©ç”¨ã•ã‚Œã¾ã™ã€‚</translation>
</message>
@@ -706,8 +806,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ウォレットデータベースã‹ã‚‰æ¬¡ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã®èª­ã¿å–ã‚Šã§ã‚¨ãƒ©ãƒ¼</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">chainstate データベースã®æ›´æ–°æ™‚ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">¡エラー: watchonly tx ã‚’ watchonly ウォレットã«è¿½åŠ ã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">エラー: watchonly トランザクションを削除ã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
@@ -722,6 +826,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">エラー: ダンプファイルã®ãƒã‚§ãƒƒã‚¯ã‚µãƒ ãŒåˆè‡´ã—ã¾ã›ã‚“。計算ã•ã‚ŒãŸå€¤%sã€æœŸå¾…ã•ã‚Œã‚‹å€¤%s</translation>
</message>
<message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">エラー: æ–°ã—ã„ watchonly ウォレットを作æˆã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
+ </message>
+ <message>
<source>Error: Got key that was not hex: %s</source>
<translation type="unfinished">エラー: hexã§ã¯ãªã„éµã‚’å–å¾—ã—ã¾ã—ãŸ: %s</translation>
</message>
@@ -742,10 +850,38 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">エラー: %sアドレスã¯ã‚ã‚Šã¾ã›ã‚“。</translation>
</message>
<message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">エラー: 一部㮠watchonly tx を削除ã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">エラー: ã“ã®ã‚¦ã‚©ãƒ¬ãƒƒãƒˆã¯ã™ã§ã« SQLite を使用ã—ã¦ã„ã¾ã™</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">エラー: ã“ã®ã‚¦ã‚©ãƒ¬ãƒƒãƒˆã¯ã™ã§ã«è¨˜è¿°å­ã‚¦ã‚©ãƒ¬ãƒƒãƒˆã§ã™</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">エラー: データベース内ã®ã™ã¹ã¦ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã®èª­ã¿å–りを開始ã§ãã¾ã›ã‚“</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">エラー: ウォレットã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を作æˆã§ãã¾ã›ã‚“</translation>
+ </message>
+ <message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">エラー: ãƒãƒ¼ã‚¸ãƒ§ãƒ³%uã‚’uint32_tã¨ã—ã¦ãƒ‘ースã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">エラー: データベース内ã®ã™ã¹ã¦ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’読ã¿å–ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">エラー: watchonly アドレス帳データを削除ã§ãã¾ã›ã‚“</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
<translation type="unfinished">エラー: æ–°ã—ã„ウォレットã«ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’書ãè¾¼ã‚ã¾ã›ã‚“</translation>
</message>
@@ -826,6 +962,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">-whitelist オプションã«å¯¾ã™ã‚‹ä¸æ­£ãªãƒãƒƒãƒˆãƒžã‚¹ã‚¯: '%s'</translation>
</message>
<message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">ç€ä¿¡æŽ¥ç¶šã®ãƒªãƒƒã‚¹ãƒ³ã«å¤±æ•—ã—ã¾ã—㟠(listen ㌠error ã‚’è¿”ã—ã¾ã—㟠%s)</translation>
+ </message>
+ <message>
<source>Loading P2P addresses…</source>
<translation type="unfinished">P2Pアドレスã®èª­ã¿è¾¼ã¿ä¸­â€¦</translation>
</message>
@@ -858,10 +998,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">アドレスãŒä½¿ãˆã¾ã›ã‚“</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">プロキシサーãƒãƒ¼ãŒæŒ‡å®šã•ã‚Œã¦ã¾ã›ã‚“. -proxy=&lt;ip&gt; ã‹ -proxy=&lt;ip:port&gt; を使用ã—ã¦ãã ã•ã„.</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">使用å¯èƒ½ãªãƒ•ã‚¡ã‚¤ãƒ«ãƒ‡ã‚£ã‚¹ã‚¯ãƒªãƒ—ã‚¿ãŒä¸è¶³ã—ã¦ã„ã¾ã™ã€‚</translation>
</message>
@@ -870,10 +1006,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">剪定モードã®è¨­å®šå€¤ã¯è² ã®å€¤ã«ã¯ã§ãã¾ã›ã‚“。</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">剪定モード㯠-txindex オプションã¨äº’æ›æ€§ãŒã‚ã‚Šã¾ã›ã‚“。</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">剪定モード㯠-txindex オプションã¨äº’æ›æ€§ãŒã‚ã‚Šã¾ã›ã‚“。</translation>
</message>
@@ -994,6 +1126,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">トランザクションãŒå¤§ãã™ãŽã¾ã™</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">-maxsigcachesize ã«ãƒ¡ãƒ¢ãƒªã‚’割り当ã¦ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“: '%s' MiB</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation type="unfinished">ã“ã®ã‚³ãƒ³ãƒ”ュータ㮠%s ã«ãƒã‚¤ãƒ³ãƒ‰ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“(%s エラーãŒè¿”å´ã•ã‚Œã¾ã—ãŸï¼‰</translation>
</message>
@@ -1006,6 +1142,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">PIDファイルã®ä½œæˆã«å¤±æ•—ã—ã¾ã—㟠('%s': %s)</translation>
</message>
<message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">外部入力用ã®UTXOãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“</translation>
+ </message>
+ <message>
<source>Unable to generate initial keys</source>
<translation type="unfinished">イニシャルéµã‚’生æˆã§ãã¾ã›ã‚“</translation>
</message>
@@ -1026,6 +1166,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">HTTPサーãƒã‚’開始ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚詳細㯠debug.log ã‚’å‚ç…§ã—ã¦ãã ã•ã„。</translation>
</message>
<message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">移行å‰ã«ã‚¦ã‚©ãƒ¬ãƒƒãƒˆã‚’アンロードã§ãã¾ã›ã‚“</translation>
+ </message>
+ <message>
<source>Unknown -blockfilterindex value %s.</source>
<translation type="unfinished">ä¸æ˜Žãª -blockfilterindex ã®å€¤ %s。</translation>
</message>
@@ -1046,12 +1190,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ä¸æ˜Žãªæ–°ãƒ«ãƒ¼ãƒ«ãŒã‚¢ã‚¯ãƒ†ã‚£ãƒ™ãƒ¼ãƒˆã•ã‚Œã¾ã—㟠(versionbit %i)</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ログカテゴリ %s=%s 。</translation>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„グローãƒãƒ« ログ レベル -loglevel=%s。有効ãªå€¤: %s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">UTXOデータベースã®æ›´æ–°ä¸­</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ログカテゴリ %s=%s 。</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
@@ -1272,7 +1416,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform>%n ブロックã®å–引履歴を処ç†ã—ã¾ã—ãŸã€‚</numerusform>
+ <numerusform>トランザクション履歴㮠%n ブロックを処ç†ã—ã¾ã—ãŸã€‚</numerusform>
</translation>
</message>
<message>
@@ -1352,6 +1496,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ウォレットを閉ã˜ã‚‹</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">ウォレットを復元…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ— ファイルã‹ã‚‰ã‚¦ã‚©ãƒ¬ãƒƒãƒˆã‚’復元ã™ã‚‹</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">å…¨ã¦ã®ã‚¦ã‚©ãƒ¬ãƒƒãƒˆã‚’é–‰ã˜ã‚‹</translation>
</message>
@@ -1376,6 +1530,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ウォレットã¯åˆ©ç”¨ã§ãã¾ã›ã‚“</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">ウォレットデータ</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">ウォレットã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—をロード</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">ウォレットを復</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">ウォレットå</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">ウィンドウ (&amp;W)</translation>
</message>
@@ -1403,7 +1577,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform>Bitcoin Networkã¸ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªæŽ¥ç¶šæ•°: %n</numerusform>
+ <numerusform>%n ビットコイン ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã¸ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªæŽ¥ç¶šã€‚</numerusform>
</translation>
</message>
<message>
@@ -1427,6 +1601,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯æ´»å‹•ã‚’有効化ã™ã‚‹</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">事å‰åŒæœŸãƒ˜ãƒƒãƒ€ãƒ¼ (%1%)…</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">エラー: %1</translation>
</message>
@@ -1689,6 +1867,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">ç½²å者をリストã§ãã¾ã›ã‚“</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">見ã¤ã‹ã£ãŸå¤–部署å者ãŒå¤šã™ãŽã¾ã™</translation>
+ </message>
</context>
<context>
<name>LoadWalletsActivity</name>
@@ -1729,6 +1911,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">ウォレットを復</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">ウォレットã®å¾©å…ƒ &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">ウォレットã®å¾©å…ƒã«å¤±æ•—ã—ã¾ã—ãŸ</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">ウォレットã®å¾©å…ƒã«é–¢ã™ã‚‹è­¦å‘Š</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">ウォレット メッセージã®å¾©å…ƒ</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1903,17 +2113,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
- <message>
- <source>%1 GB of space available</source>
- <translation type="unfinished">%1 GBã®ç©ºã容é‡ãŒåˆ©ç”¨å¯èƒ½</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB ã®ç©ºã容é‡</numerusform>
+ </translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(内 %1 GB ãŒå¿…è¦)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(å¿…è¦ãª %n GB ã®ã†ã¡)</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(フルãƒã‚§ãƒ¼ãƒ³ã«ã¯ %1 GB ãŒå¿…è¦)</translation>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(完全ãªãƒã‚§ãƒ¼ãƒ³ã«ã¯ %n GB ãŒå¿…è¦)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1927,7 +2143,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform>(%n æ—¥å‰ã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を復元ã™ã‚‹ã®ã«å……分ã§ã™)</numerusform>
+ <numerusform>(%n 日経éŽã—ãŸãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を復元ã™ã‚‹ã®ã«å分ã§ã™)</numerusform>
</translation>
</message>
<message>
@@ -1959,10 +2175,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ã“ã‚Œã¯ãƒ—ログラムã®æœ€åˆã®èµ·å‹•ã§ã™ã€‚%1 ãŒãƒ‡ãƒ¼ã‚¿ã‚’ä¿å­˜ã™ã‚‹å ´æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</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 type="unfinished">OKをクリックã™ã‚‹ã¨ã€%1 㯠%4 ãŒãƒªãƒªãƒ¼ã‚¹ã•ã‚ŒãŸ%3å¹´ã«ãŠã‘る最åˆã®å–引ã‹ã‚‰ã®å®Œå…¨ãª %4 ブロックãƒã‚§ãƒ¼ãƒ³ï¼ˆ%2GB)ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ãŠã‚ˆã³å‡¦ç†ã‚’開始ã—ã¾ã™ã€‚</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">ブロックãƒã‚§ãƒ¼ãƒ³ã®ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã‚’次ã«é™å®šã™ã‚‹: </translation>
</message>
@@ -2067,6 +2279,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">ä¸æ˜Žã€‚ヘッダ (%1, %2%) ã®åŒæœŸä¸­â€¦</translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">ã‚ã‹ã‚‰ãªã„。ヘッダーを事å‰åŒæœŸã—ã¦ã„ã¾ã™ (%1, %2%)…</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -2123,6 +2339,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ウィンドウãŒé–‰ã˜ã‚‰ã‚ŒãŸã¨ãã€ã‚¢ãƒ—リケーションを終了ã™ã‚‹ã®ã§ã¯ãªã最å°åŒ–ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションãŒæœ‰åŠ¹ã®å ´åˆã€ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‹ã‚‰çµ‚了ãŒé¸æŠžã•ã‚ŒãŸã¨ãã®ã¿ã‚¢ãƒ—リケーションãŒçµ‚了ã—ã¾ã™ã€‚</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§è¨­å®šã•ã‚ŒãŸã‚ªãƒ—ションã¯ã€ã‚³ãƒžãƒ³ãƒ‰ ラインã«ã‚ˆã£ã¦ä¸Šæ›¸ãã•ã‚Œã¾ã™ã€‚</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">作業ディレクトリ内㮠%1 ã®è¨­å®šãƒ•ã‚¡ã‚¤ãƒ«ã‚’é–‹ã。</translation>
</message>
@@ -2351,10 +2571,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">最もマッãƒã™ã‚‹ "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§æŒ‡å®šã—ãŸã‚ªãƒ—ションã¯ã€ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³ã‚„設定ファイルã®å†…容ã§ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰ã•ã‚Œã¾ã™:</translation>
- </message>
- <message>
<source>&amp;Cancel</source>
<translation type="unfinished">キャンセル(&amp;C)</translation>
</message>
@@ -2373,14 +2589,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">設定リセットã®ç¢ºèª</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">変更を有効化ã™ã‚‹ã«ã¯ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã‚’å†èµ·å‹•ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">ç¾åœ¨ã®è¨­å®šã¯ã€Œ%1ã€ã«ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã•ã‚Œã¾ã™ã€‚</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">クライアントを終了ã—ã¾ã™ã€‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ</translation>
</message>
<message>
@@ -2419,6 +2643,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">設定 "%1", %2 を読ã¿å–ã‚Œã¾ã›ã‚“ã§ã—ãŸã€‚</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2677,6 +2908,11 @@ BIP70ã«ã¯åºƒç¯„ãªã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ¼ä¸Šã®å•é¡ŒãŒã‚ã‚‹ã®ã§ã€ã‚¦ã‚©ãƒ¬
<translation type="unfinished">ピア</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">å¹´</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">æ–¹å‘</translation>
@@ -2873,29 +3109,32 @@ BIP70ã«ã¯åºƒç¯„ãªã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ¼ä¸Šã®å•é¡ŒãŒã‚ã‚‹ã®ã§ã€ã‚¦ã‚©ãƒ¬
</message>
<message>
<source>Whether we relay addresses to this peer.</source>
- <extracomment>Tooltip text for the Address Relay field in the peer details area.</extracomment>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">ã“ã®ãƒ”ã‚¢ã«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’中継ã™ã‚‹ã‹å¦ã‹ã€‚</translation>
</message>
<message>
<source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">アドレスã®ä¸­ç¶™</translation>
</message>
<message>
- <source>Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Processed field in the peer details area.</extracomment>
- <translation type="unfinished">レート制é™ã®ãŸã‚ã«é™¤å¤–ã•ã‚ŒãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’除ãã€å‡¦ç†ã•ã‚ŒãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã®ç·æ•°ã€‚</translation>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">ã“ã®ãƒ”ã‚¢ã‹ã‚‰å—ä¿¡ã•ã‚Œã€å‡¦ç†ã•ã‚ŒãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã®ç·æ•° (レート制é™ã®ãŸã‚ã«ãƒ‰ãƒ­ãƒƒãƒ—ã•ã‚ŒãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’除ã)。</translation>
</message>
<message>
- <source>Addresses Processed</source>
- <translation type="unfinished">処ç†ã•ã‚ŒãŸã‚¢ãƒ‰ãƒ¬ã‚¹</translation>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">レート制é™ãŒåŽŸå› ã§ãƒ‰ãƒ­ãƒƒãƒ—ã•ã‚ŒãŸ (処ç†ã•ã‚Œãªã‹ã£ãŸ) ã“ã®ãƒ”ã‚¢ã‹ã‚‰å—ä¿¡ã—ãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã®ç·æ•°ã€‚</translation>
</message>
<message>
- <source>Total number of addresses dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area.</extracomment>
- <translation type="unfinished">レート制é™ã®ãŸã‚ã«é™¤å¤–ã•ã‚ŒãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã®ç·æ•°ã€‚</translation>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">処ç†ã•ã‚ŒãŸã‚¢ãƒ‰ãƒ¬ã‚¹</translation>
</message>
<message>
<source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
<translation type="unfinished">レート制é™å¯¾è±¡ã®ã‚¢ãƒ‰ãƒ¬ã‚¹</translation>
</message>
<message>
@@ -3702,14 +3941,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">%1 よりも高ã„手数料ã¯ã€ç•°å¸¸ã«é«˜ã™ãŽã§ã™ã€‚</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">支払ã„リクエストãŒæœŸé™åˆ‡ã‚Œã§ã™ã€‚</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform>%n ブロック以内ã«æ‰¿èªãŒé–‹å§‹ã•ã‚Œã‚‹è¦‹è¾¼ã¿ã§ã™ã€‚</numerusform>
+ <numerusform>%n ブロック以内ã«ç¢ºèªã‚’開始ã™ã‚‹ã¨æŽ¨å®šã•ã‚Œã¾ã™ã€‚</numerusform>
</translation>
</message>
<message>
@@ -3784,14 +4019,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">メッセージ:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">ã“ã‚Œã¯æœªèªè¨¼ã®æ”¯æ‰•ã„リクエストã§ã™ã€‚</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">ã“ã‚Œã¯èªè¨¼æ¸ˆã¿ã®æ”¯æ‰•ã„リクエストã§ã™ã€‚</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">ã“ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã«å¯¾ã™ã‚‹ãƒ©ãƒ™ãƒ«ã‚’入力ã™ã‚‹ã“ã¨ã§ã€é€é‡‘ã—ãŸã“ã¨ãŒã‚るアドレスã®ä¸€è¦§ã«è¿½åŠ ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™</translation>
</message>
@@ -3799,14 +4026,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<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 type="unfinished">bitcoin URIã«æ·»ä»˜ã•ã‚Œã¦ã„ãŸãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™ã€‚ã“ã‚Œã¯å‚照用ã¨ã—ã¦å–引ã¨ã¨ã‚‚ã«ä¿å­˜ã•ã‚Œã¾ã™ã€‚注æ„: メッセージ㯠Bitcoin ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ä¸Šã¸é€ä¿¡ã•ã‚Œã¾ã›ã‚“。</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">é€é‡‘å…ˆ:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">メモ:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3984,30 +4203,32 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">%1 承èªã®å–引ã¨è¡çª</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/未承èª, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">メモリプール内</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/未確èªã€ãƒ¡ãƒ¢ãƒªãƒ¼ãƒ—ール内</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">メモリプール外</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/未確èªã€ãƒ¡ãƒ¢ãƒª プールã«ãªã„</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">é€ä¿¡ä¸­æ­¢</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/未承èª</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 承èª</translation>
</message>
<message>
@@ -4057,7 +4278,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform>ã‚㨠%n ブロックã§ç†Ÿæˆã—ã¾ã™</numerusform>
+ <numerusform>%n 個以上ã®ãƒ–ロックã§æˆç†Ÿã™ã‚‹</numerusform>
</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts
index c0820471b9..22b83a58ba 100644
--- a/src/qt/locale/bitcoin_ka.ts
+++ b/src/qt/locale/bitcoin_ka.ts
@@ -70,6 +70,12 @@
<translation type="unfinished">ეს áƒáƒ áƒ˜áƒ¡ თქვენი ბიტკáƒáƒ˜áƒœ-მისáƒáƒ›áƒáƒ áƒ—ები, რáƒáƒ›áƒ”ლთáƒáƒ’áƒáƒœáƒáƒª შეგიძლიáƒáƒ— გáƒáƒ“áƒáƒ®áƒ“áƒ. áƒáƒ£áƒªáƒ˜áƒšáƒ”ბლáƒáƒ“ შეáƒáƒ›áƒáƒ¬áƒ›áƒ”თ თáƒáƒœáƒ®áƒ დრმიმღები მისáƒáƒ›áƒáƒ áƒ—ი გáƒáƒ’ზáƒáƒ•áƒœáƒáƒ›áƒ“ე.</translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">ეს თქვენი ბიტკáƒáƒ˜áƒœáƒ˜áƒ¡ მიმღები მიმსáƒáƒ›áƒáƒ áƒ—ებიáƒ. ისáƒáƒ áƒ’ებლეთ ღილáƒáƒ™áƒ˜áƒ— "შექმენით áƒáƒ®áƒáƒšáƒ˜ მიმღები მისáƒáƒ›áƒáƒ áƒ—ები", რáƒáƒ”მლიც მáƒáƒªáƒ”მულირმიმღების ჩáƒáƒœáƒáƒ áƒ—ში áƒáƒ®áƒáƒšáƒ˜ მისáƒáƒ›áƒáƒ áƒ—ების შესáƒáƒ¥áƒ›áƒœáƒ”ლáƒáƒ“.
+ხელმáƒáƒ¬áƒ”რრმხáƒáƒšáƒáƒ“ "მემკვიდრეáƒáƒ‘ის" ტიპის მისáƒáƒ›áƒáƒ áƒ—ებთáƒáƒœáƒáƒ შესáƒáƒ«áƒšáƒ”ბელიáƒ</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">მისáƒáƒ›áƒáƒ áƒ—ის კáƒáƒžáƒ˜áƒ áƒ”ბáƒ</translation>
</message>
@@ -86,6 +92,11 @@
<translation type="unfinished">მისáƒáƒ›áƒáƒ áƒ—ების სიის ექსპáƒáƒ áƒ¢áƒ˜</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">CSV (სპეციáƒáƒšáƒ£áƒ áƒ˜ ტექსტური ფáƒáƒ˜áƒšáƒ˜)</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">მისáƒáƒ›áƒáƒ áƒ—ების სიის %1 შენáƒáƒ®áƒ•áƒ ვერ მáƒáƒ®áƒ”რხდáƒ. გáƒáƒ˜áƒ›áƒ”áƒáƒ áƒ”თ მცდელáƒáƒ‘áƒ.</translation>
@@ -239,6 +250,14 @@
<translation type="unfinished">შეცდáƒáƒ›áƒ: მითითებული მáƒáƒœáƒáƒªáƒ”მთრკáƒáƒ¢áƒáƒšáƒáƒ’ი "%1" áƒáƒ  áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">შეცდáƒáƒ›áƒ: შეუძლებელირკáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ¡ ფáƒáƒ˜áƒšáƒ˜áƒ¡ წáƒáƒ™áƒ˜áƒ—ხვáƒ: %1</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">შეცდუმáƒ: %1</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">უცნáƒáƒ‘იáƒ</translation>
</message>
@@ -356,6 +375,10 @@
<translation type="unfinished">áƒáƒ  áƒáƒ áƒ˜áƒ¡ სáƒáƒ™áƒ›áƒáƒ áƒ˜áƒ¡áƒ˜ თáƒáƒœáƒ®áƒ</translation>
</message>
<message>
+ <source>No addresses available</source>
+ <translation type="unfinished">áƒáƒ áƒªáƒ”რთი მისáƒáƒ›áƒáƒ áƒ—ი áƒáƒ  áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს</translation>
+ </message>
+ <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">áƒáƒ  áƒáƒ áƒ˜áƒ¡ სáƒáƒ™áƒ›áƒáƒ áƒ˜áƒ¡áƒ˜ ფáƒáƒ˜áƒš-დესკრიპტáƒáƒ áƒ”ბი.</translation>
</message>
@@ -427,6 +450,10 @@
<translation type="unfinished">შექმენით áƒáƒ®áƒáƒšáƒ˜ სáƒáƒ¤áƒ£áƒšáƒ”</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;ჩáƒáƒ®áƒ£áƒ áƒ•áƒ</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ”:</translation>
</message>
@@ -563,6 +590,14 @@
<translation type="unfinished">გáƒáƒ®áƒ¡áƒ”ნით სáƒáƒ¤áƒ£áƒšáƒ”</translation>
</message>
<message>
+ <source>Close wallet</source>
+ <translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ˜áƒ¡ დáƒáƒ®áƒ£áƒ áƒ•áƒ</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">ყველრსáƒáƒ¤áƒ£áƒšáƒ˜áƒ¡ დáƒáƒ®áƒ£áƒ áƒ•áƒ</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">ნáƒáƒ’ულისხმევი სáƒáƒ¤áƒ£áƒšáƒ”</translation>
</message>
@@ -571,6 +606,11 @@
<translation type="unfinished">áƒáƒ  áƒáƒ áƒ˜áƒ¡ ჩáƒáƒ¢áƒ•áƒ˜áƒ áƒ—ული სáƒáƒ¤áƒ£áƒšáƒ”.</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ˜áƒ¡ სáƒáƒ®áƒ”ლი</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;ფáƒáƒœáƒ¯áƒáƒ áƒ</translation>
</message>
@@ -591,6 +631,15 @@
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">მეტი...</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">შეცდუმáƒ: %1</translation>
+ </message>
+ <message>
<source>Date: %1
</source>
<translation type="unfinished">თáƒáƒ áƒ˜áƒ¦áƒ˜: %1
@@ -646,6 +695,10 @@
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Coin Selection</source>
+ <translation type="unfinished">Coin-ები</translation>
+ </message>
+ <message>
<source>Quantity:</source>
<translation type="unfinished">რáƒáƒáƒ“ენáƒáƒ‘áƒ:</translation>
</message>
@@ -755,6 +808,31 @@
</message>
</context>
<context>
+ <name>CreateWalletActivity</name>
+ <message>
+ <source>Create Wallet</source>
+ <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
+ <translation type="unfinished">áƒáƒ®áƒáƒšáƒ˜ სáƒáƒ¤áƒ£áƒšáƒ”</translation>
+ </message>
+ <message>
+ <source>Create wallet failed</source>
+ <translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ” ვერ შეიქმნáƒ</translation>
+ </message>
+ </context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ”ების ჩáƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒ</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">იტვირთებრსáƒáƒ¤áƒ£áƒšáƒ”ები...</translation>
+ </message>
+</context>
+<context>
<name>OpenWalletActivity</name>
<message>
<source>default wallet</source>
@@ -767,11 +845,46 @@
</message>
</context>
<context>
+ <name>WalletController</name>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ˜áƒ¡ დáƒáƒ®áƒ£áƒ áƒ•áƒ</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">დáƒáƒ˜áƒ®áƒ£áƒ áƒáƒ¡ სáƒáƒ¤áƒ£áƒšáƒ”&lt;i&gt;%1&lt;/i&gt; ?</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">ყველრსáƒáƒ¤áƒ£áƒšáƒ˜áƒ¡ დáƒáƒ®áƒ£áƒ áƒ•áƒ</translation>
+ </message>
+ </context>
+<context>
<name>CreateWalletDialog</name>
<message>
+ <source>Create Wallet</source>
+ <translation type="unfinished">áƒáƒ®áƒáƒšáƒ˜ სáƒáƒ¤áƒ£áƒšáƒ”</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ˜áƒ¡ სáƒáƒ®áƒ”ლი</translation>
+ </message>
+ <message>
<source>Wallet</source>
<translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ”</translation>
</message>
+ <message>
+ <source>Encrypt Wallet</source>
+ <translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ˜áƒ¡ დáƒáƒªáƒ•áƒ [Encrypt Wallet]</translation>
+ </message>
+ <message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">დáƒáƒ›áƒáƒ¢áƒ”ბითი ფუნქციები</translation>
+ </message>
+ <message>
+ <source>Create</source>
+ <translation type="unfinished">áƒáƒ®áƒáƒšáƒ˜</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -846,6 +959,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -866,6 +1000,10 @@
<translation type="unfinished">კეთილი იყáƒáƒ¡ თქვენი მáƒáƒ‘რძáƒáƒœáƒ”ბრ%1-ში.</translation>
</message>
<message>
+ <source> GB</source>
+ <translation type="unfinished">GB</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation type="unfinished">ნáƒáƒ’ულისხმევი კáƒáƒ¢áƒáƒšáƒáƒ’ის გáƒáƒ›áƒáƒ§áƒ”ნებáƒ</translation>
</message>
@@ -892,6 +1030,10 @@
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished"> დáƒáƒ®áƒ£áƒ áƒ£áƒšáƒ˜áƒ %1...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation type="unfinished">áƒáƒ  გáƒáƒ›áƒáƒ áƒ—áƒáƒ— კáƒáƒ›áƒžáƒ˜áƒ£áƒ¢áƒ”რი áƒáƒ› ფáƒáƒœáƒ¯áƒ áƒ˜áƒ¡ გáƒáƒ¥áƒ áƒáƒ‘áƒáƒ›áƒ“ე.</translation>
</message>
@@ -903,6 +1045,18 @@
<translation type="unfinished">ფáƒáƒ áƒ›áƒ</translation>
</message>
<message>
+ <source>Number of blocks left</source>
+ <translation type="unfinished">დáƒáƒ áƒ©áƒ”ნილი ბლáƒáƒ™áƒ”ბის რáƒáƒáƒ“ენáƒáƒ‘áƒ</translation>
+ </message>
+ <message>
+ <source>Unknown…</source>
+ <translation type="unfinished">უცნáƒáƒ‘ი...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">გáƒáƒ›áƒáƒ—ვლáƒ...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation type="unfinished">ბáƒáƒšáƒ ბლáƒáƒ™áƒ˜áƒ¡ დრáƒ</translation>
</message>
@@ -911,6 +1065,10 @@
<translation type="unfinished">პრáƒáƒ’რესი</translation>
</message>
<message>
+ <source>Estimated time left until synced</source>
+ <translation type="unfinished">სინქრáƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ˜áƒ¡ დáƒáƒ¡áƒ áƒ£áƒšáƒ”ბáƒáƒ›áƒ“ე დáƒáƒ áƒ©áƒ”ნილი დრáƒ</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation type="unfinished">დáƒáƒ›áƒáƒšáƒ•áƒ</translation>
</message>
@@ -1039,13 +1197,28 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">დáƒáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”თ პáƒáƒ áƒáƒ›áƒ”ტრების დáƒáƒ‘რუნებრნáƒáƒ’ულისხმევზე</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">ცვლილებები ძáƒáƒšáƒáƒ¨áƒ˜ შევრკლიენტის ხელáƒáƒ®áƒáƒšáƒ˜ გáƒáƒ¨áƒ•áƒ”ბის შემდეგ.</translation>
</message>
<message>
+ <source>Configuration options</source>
+ <extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
+ <translation type="unfinished">კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ¡ პáƒáƒ áƒáƒ›áƒ”ტრები</translation>
+ </message>
+ <message>
+ <source>Continue</source>
+ <translation type="unfinished">გáƒáƒ’რძელებáƒ</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">შეცდáƒáƒ›áƒ</translation>
</message>
@@ -1207,6 +1380,22 @@
<translation type="unfinished">კვáƒáƒœáƒ«áƒ˜áƒ¡ ფáƒáƒœáƒ¯áƒáƒ áƒ</translation>
</message>
<message>
+ <source>Connection Time</source>
+ <translation type="unfinished">დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბის დრáƒ</translation>
+ </message>
+ <message>
+ <source>Last Block</source>
+ <translation type="unfinished">ბáƒáƒšáƒ "ბლáƒáƒ™áƒ˜"</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation type="unfinished">ბáƒáƒšáƒ გáƒáƒ’ზáƒáƒ•áƒœáƒ˜áƒšáƒ˜</translation>
+ </message>
+ <message>
+ <source>Ping Time</source>
+ <translation type="unfinished">"Ping"-ის ხáƒáƒœáƒ’რძლივáƒáƒ‘áƒ</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation type="unfinished">ბáƒáƒšáƒ ბლáƒáƒ™áƒ˜áƒ¡ დრáƒ</translation>
</message>
@@ -1250,7 +1439,15 @@
<source>From</source>
<translation type="unfinished">გáƒáƒ›áƒ’ზáƒáƒ•áƒœáƒ˜</translation>
</message>
- </context>
+ <message>
+ <source>Never</source>
+ <translation type="unfinished">áƒáƒ áƒáƒ¡áƒáƒ“ეს</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation type="unfinished">უცნáƒáƒ‘ი</translation>
+ </message>
+</context>
<context>
<name>ReceiveCoinsDialog</name>
<message>
@@ -1431,6 +1628,10 @@
<translation type="unfinished">დáƒáƒ›áƒáƒšáƒ•áƒ</translation>
</message>
<message>
+ <source>Recommended:</source>
+ <translation type="unfinished">სáƒáƒ¡áƒ£áƒ áƒ•áƒ”ლიáƒ:</translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation type="unfinished">გáƒáƒ’ზáƒáƒ•áƒœáƒ რáƒáƒ›áƒ“ენიმე რეციპიენტთáƒáƒœ ერთდრáƒáƒ£áƒšáƒáƒ“</translation>
</message>
@@ -1491,10 +1692,19 @@
<translation type="unfinished">%1-დáƒáƒœ %2-ში</translation>
</message>
<message>
+ <source>PSBT saved</source>
+ <translation type="unfinished">PSBT შენáƒáƒ®áƒ£áƒšáƒ˜áƒ</translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">áƒáƒœ</translation>
</message>
<message>
+ <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
+ <translation type="unfinished">სáƒáƒ™áƒáƒ›áƒ˜áƒ¡áƒ˜áƒ [fee] შეგიძლიáƒáƒ— შცვáƒáƒšáƒáƒ— მáƒáƒ’ვიáƒáƒœáƒ”ბით (სიგნáƒáƒšáƒ”ბი Replace-By-Fee, BIP-125}.
+ </translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation type="unfinished">ტრáƒáƒœáƒ¡áƒáƒ¥áƒªáƒ˜áƒ˜áƒ¡ სáƒáƒ¤áƒáƒ¡áƒ£áƒ áƒ˜ - სáƒáƒ™áƒáƒ›áƒ˜áƒ¡áƒ˜áƒ</translation>
</message>
@@ -1576,14 +1786,6 @@
<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 type="unfinished">მესიჯი, რáƒáƒ›áƒ”ლიც თáƒáƒœ ერთვის მáƒáƒœáƒ”ტებს: URI, რáƒáƒ›áƒ”ლიც შეინáƒáƒ®áƒ”ბრტრáƒáƒœáƒ¡áƒáƒ¥áƒªáƒ˜áƒáƒ¡áƒ—áƒáƒœ ერთáƒáƒ“ თქვენთვის. შენიშვნáƒ: მესიჯი áƒáƒ  გáƒáƒ§áƒ•áƒ”ბრგáƒáƒ“áƒáƒ®áƒ“áƒáƒ¡ ბითქáƒáƒ˜áƒœáƒ˜áƒ¡ ქსელში.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">áƒáƒ“რესáƒáƒ¢áƒ˜:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">შენიშვნáƒ:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -1701,13 +1903,26 @@
</message>
</context>
<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished">'q' - დáƒáƒ®áƒ£áƒ áƒ•áƒ დრმáƒáƒ’ვიáƒáƒœáƒ”ბით გáƒáƒ’რძელებáƒ</translation>
+ </message>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">დáƒáƒ®áƒ£áƒ áƒ•áƒ 'q'</translation>
+ </message>
+</context>
+<context>
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/დáƒáƒ£áƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბელიáƒ</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 დáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბულიáƒ</translation>
</message>
<message>
@@ -1963,6 +2178,11 @@
<translation type="unfinished">ტრáƒáƒœáƒ¡áƒáƒ¥áƒªáƒ˜áƒ”ბის ისტáƒáƒ áƒ˜áƒ˜áƒ¡ ექსპáƒáƒ áƒ¢áƒ˜</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">CSV (სპეციáƒáƒšáƒ£áƒ áƒ˜ ტექსტური ფáƒáƒ˜áƒšáƒ˜)</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">დáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბულიáƒ</translation>
</message>
@@ -2059,5 +2279,9 @@
<source>The wallet data was successfully saved to %1.</source>
<translation type="unfinished">სáƒáƒ¤áƒ£áƒšáƒ˜áƒ¡ მáƒáƒœáƒáƒªáƒ”მები შენáƒáƒ®áƒ£áƒšáƒ˜áƒ %1-ში.</translation>
</message>
- </context>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_kk.ts b/src/qt/locale/bitcoin_kk.ts
index 5461e6dbab..c9e9387b1a 100644
--- a/src/qt/locale/bitcoin_kk.ts
+++ b/src/qt/locale/bitcoin_kk.ts
@@ -606,6 +606,10 @@
<translation type="unfinished">РаÑÑ‚Ñ‹Ò›</translation>
</message>
<message>
+ <source>yes</source>
+ <translation type="unfinished">Иа</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(белгі жоқ)</translation>
</message>
@@ -646,6 +650,27 @@
<translation type="unfinished">Биткоин</translation>
</message>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -659,7 +684,7 @@
</message>
<message>
<source>Error</source>
- <translation type="unfinished">Қате</translation>
+ <translation type="unfinished">қате</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>
@@ -690,7 +715,7 @@
</message>
<message>
<source>Error</source>
- <translation type="unfinished">Қате</translation>
+ <translation type="unfinished">қате</translation>
</message>
</context>
<context>
@@ -815,10 +840,6 @@
<context>
<name>TransactionDesc</name>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/раÑталмаған, %1</translation>
- </message>
- <message>
<source>Date</source>
<translation type="unfinished">Күні</translation>
</message>
@@ -889,7 +910,7 @@
</message>
<message>
<source>Error</source>
- <translation type="unfinished">Қате</translation>
+ <translation type="unfinished">қате</translation>
</message>
</context>
<context>
diff --git a/src/qt/locale/bitcoin_kl.ts b/src/qt/locale/bitcoin_kl.ts
index facce35f99..14f7391759 100644
--- a/src/qt/locale/bitcoin_kl.ts
+++ b/src/qt/locale/bitcoin_kl.ts
@@ -206,6 +206,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_km.ts b/src/qt/locale/bitcoin_km.ts
index e8c469c133..e25764b8f7 100644
--- a/src/qt/locale/bitcoin_km.ts
+++ b/src/qt/locale/bitcoin_km.ts
@@ -86,6 +86,11 @@
<translation type="unfinished">នាំចáŸáž‰áž“ូវបញ្ជីអាសយដ្ឋាន</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Comma បំបែកឯកសារ</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation type="unfinished">ការនាំចáŸáž‰áž”ានបរាជáŸáž™</translation>
</message>
@@ -216,8 +221,37 @@
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">ករណីលើកលែងដែលរážáŸ‹áž‚áŸáž…ážáŸ’លួន</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">ážáž¶áž„ក្នុងបញ្ហា</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">កំហុសážáž¶áž„ក្នុងបានកើážáž¡áž¾áž„។ %1នឹងព្យាយាមបន្ážážŠáŸ„យសុវážáŸ’ážáž·áž—ាព។ áž“áŸáŸ‡â€‹áž‡áž¶â€‹áž€áŸ†áž áž»ážŸâ€‹ážŠáŸ‚ល​មិន​នឹក​ស្មាន​ដល់ ដែល​អាច​ážáŸ’រូវ​បាន​រាយការណáŸâ€‹ážŠáž¼áž…​បាន​ពណ៌នា​ážáž¶áž„​ក្រោម។</translation>
+ </message>
+</context>
+<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">ážáž¾â€‹áž¢áŸ’នក​ចង់​កំណážáŸ‹â€‹áž€áž¶ážšâ€‹áž€áŸ†ážŽážáŸ‹â€‹áž¡áž¾áž„​វិញ​ទៅ​ជា​ážáž˜áŸ’លៃ​លំនាំដើម ឬ​បោះបង់​ដោយ​មិន​ធ្វើ​ការ​ផ្លាស់ប្ដូរ?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">កំហុសធ្ងន់ធ្ងរបានកើážáž¡áž¾áž„។ áž–áž·áž“áž·ážáŸ’យមើលážáž¶áž¯áž€ážŸáž¶ážšáž€áž¶ážšáž€áŸ†ážŽážáŸ‹áž¢áž¶áž…សរសáŸážšáž”ាន ឬព្យាយាមដំណើរការជាមួយ -nosettings។</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1មិនទាន់ចáŸáž‰ážŠáŸ„យសុវážáŸ’ážáž·áž—ាពទáŸâ€¦</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">មិនស្គាល់</translation>
</message>
@@ -275,6 +309,14 @@
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">ការកំណážáŸ‹áž¯áž€ážŸáž¶ážšáž˜áž·áž“អាចអានបានទáŸáŸ”</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">ការកំណážáŸ‹áž¯áž€ážŸáž¶ážšáž˜áž·áž“អាចសរសáŸážšáž”ានទáŸáŸ”</translation>
+ </message>
+ <message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished">-maxtxfee មានážáŸ†áž˜áŸ’លៃážáŸ’ពស់ពáŸáž€áŸ”​ ážáŸ†áž˜áŸ’លៃនáŸáŸ‡ អាចគួរážáŸ’រូវបានបង់សម្រាប់មួយប្រážáŸ’ážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáŸ”</translation>
</message>
@@ -430,6 +472,10 @@
<translation type="unfinished">បង្កើážáž€áž¶áž”ូបចលáŸážážáŸ’មីមួយ</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;បង្រួមអប្បបរមា</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">កាបូបចលáŸážáŸ–</translation>
</message>
@@ -463,18 +509,62 @@
<translation type="unfinished">&amp;ទទួល</translation>
</message>
<message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;ជម្រើស…</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;អ៊ិនគ្រីបកាបូប</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">បំលែងលáŸážážŸáŸ†áž˜áŸ’ងាážáŸ‹ážŸáž˜áŸ’រាប់កាបូបអáŸáž¡áž·áž…ážáŸ’រូនិច របស់អ្នកឲ្យទៅជាភាសាកុំព្យូទáŸážš </translation>
</message>
<message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;ការបម្រុងទុកកាបូប...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;ការផ្លាស់ប្ážáž¼ážšážƒáŸ’លាសម្ងាážáŸ‹</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">ចុះហážáŸ’ážáž›áŸážáž¶&amp;សារ…</translation>
+ </message>
+ <message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
<translation type="unfinished">ចុះហážáŸ’ážáž›áŸážáž¶áž›áž¾ážŸáž¶ážš អាសយដ្ឋានប៊ីážážáž‰ážšáž”ស់អ្នក ដើម្បីបញ្ចាក់ážáž¶áž¢áŸ’នកជាម្ចាស់</translation>
</message>
<message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;ផ្ទៀងផ្ទាážáŸ‹ážŸáž¶ážš...</translation>
+ </message>
+ <message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
<translation type="unfinished">ធ្វើការបញ្ចាក់សារ ដើម្បីធានាážáž¶ážŸáž¶ážšáž‘ាំំងនោះបានចុះហážáŸ’ážáž›áŸážáž¶ ជាមួយអាសយដ្ážáž¶áž“ប៊ីážážáž‰</translation>
</message>
<message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;ផ្ទុក PSBT ពីឯកសារ...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">បើក &amp;URI…</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">បិទកាបូប…</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">បង្កើážáž€áž¶áž”ូប...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">បិទកាបូបអáŸáž¡áž·áž…ážáŸ’រូនិចទាំងអស់...</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation type="unfinished">ឯកសារ</translation>
</message>
@@ -491,6 +581,30 @@
<translation type="unfinished">ធូបារážáŸáž”</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">កំពុងសមកាល បឋមកážáž¶ (%1%)...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">កំពុងធ្វើសមកាលកម្មជាមួយបណ្ដាញ...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">កំពុងធ្វើលិបិក្រមប្លុកនៅលើážáž¶ážŸ...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">កំពុងដំណើរការប្លុកនៅលើážáž¶ážŸ...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">កំពុងដំណើរការប្លុកនៅលើážáž¶ážŸ...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">កំពុងភ្ជាប់ទៅមិážáŸ’ážáž—ក្ដិ...</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">សំណើរទូរទាážáŸ‹â€‹(បង្កើážáž€áž¼ážŠ QR áž“áž·áž„ ប៊ីážážáž‰: URLs)</translation>
</message>
@@ -509,11 +623,15 @@
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>បានដំណើរការ %n ប្លុកនៃប្រវážáŸ’ážáž·áž”្រážáŸ’ážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáŸ”</numerusform>
<numerusform />
</translation>
</message>
<message>
+ <source>Catching up…</source>
+ <translation type="unfinished">កំពុងចាប់...</translation>
+ </message>
+ <message>
<source>Transactions after this will not yet be visible.</source>
<translation type="unfinished">ប្រážáŸ’ážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáž”ន្ទាប់ពីនáŸáŸ‡ នឹងមិនអាចទាន់មើលឃើញនៅឡើយទáŸáŸ”</translation>
</message>
@@ -538,6 +656,10 @@
<translation type="unfinished">បង្ហាញប្រážáŸ’ážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáž”៊ីážážáž‰ážŠáŸ‚លបានចុះហážáŸ’ážáž›áŸážáž¶ážŠáŸ„យផ្នែក</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">ផ្ទុក PSBT ពី &amp;clipboard...</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">បង្ហាញប្រážáŸ’ážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáž”៊ីážážáž‰ážŠáŸ‚លបានចុះហážáŸ’ážáž›áŸážáž¶ážŠáŸ„យផ្នែកពីក្ដារážáž˜áŸ’រៀប</translation>
</message>
@@ -570,18 +692,51 @@
<translation type="unfinished">មិនមានកាបូបអáŸáž¡áž·áž…ážáŸ’រូនិច</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">ឈ្មោះកាបូប</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;វិនដូ</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;លាក់</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">S&amp;របៀប</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n ការážáž—្ជាប់សកម្មទៅបណ្ážáž¶áž‰ Bitcoin ។</numerusform>
<numerusform />
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">ចុចសម្រាប់សកម្មភាពបន្ážáŸ‚ម។</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">បង្ហាញផ្ទាំង Peers</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">បិទសកម្មភាពបណ្ážáž¶áž‰</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">បើកសកម្មភាពបណ្ážáž¶áž‰</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation type="unfinished">បានបញ្ចូនប្រážáŸ’ážáž·áž”ážáŸ’ážáž·áž€áž¶ážš</translation>
</message>
@@ -649,6 +804,30 @@
<translation type="unfinished">បានបញ្ចាក់រួចរាល់</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;ចម្លងអាសយដ្ឋាន</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">ចម្លង &amp; ស្លាក</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">ចម្លង &amp; ចំនួន</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">ចម្លងប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš &amp; áž›áŸážážŸáž˜áŸ’គាល់ និងសន្ទស្សនáŸáž‘ិន្នផល</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">L&amp;ock មិនបានចំណាយ</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;ដោះសោដោយមិនបានចំណាយ</translation>
+ </message>
+ <message>
<source>yes</source>
<translation type="unfinished">បាទ ឬ ចាស</translation>
</message>
@@ -677,11 +856,33 @@
<translation type="unfinished">បង្កើážáž€áž¶áž”ូប</translation>
</message>
<message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">ការបង្កើážáž€áž¶áž”ូប&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
<source>Create wallet failed</source>
<translation type="unfinished">បង្កើážáž€áž¶áž”ូបអáŸáž¡áž·áž…ážáŸ’រូនិច មិនជោគជáŸáž™</translation>
</message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">មិនអាចចុះបញ្ជីអ្នកចុះហážáŸ’ážáž›áŸážáž¶áž”ានទáŸáŸ”</translation>
+ </message>
</context>
<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">ផ្ទុកកាបូប</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">កំពុងផ្ទុកកាបូប...</translation>
+ </message>
+</context>
+<context>
<name>OpenWalletActivity</name>
<message>
<source>Open wallet failed</source>
@@ -696,7 +897,12 @@
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">បើកកាបូបអáŸáž¡áž·áž…ážáŸ’រូនិច</translation>
</message>
- </context>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">កាបូបការបើកកាបូប&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
<context>
<name>WalletController</name>
<message>
@@ -743,10 +949,23 @@
<translation type="unfinished">ធ្វើឲ្យកាបូបអáŸáž¡áž·áž…ážáŸ’រូនិចទទáŸ</translation>
</message>
<message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">ប្រើឧបករណáŸáž…ុះហážáŸ’ážáž›áŸážáž¶ážáž¶áž„ក្រៅ ដូចជាកាបូបផ្នែករឹង។ កំណážáŸ‹ážšáž…នាសម្ពáŸáž“្ធស្គ្រីបអ្នកចុះហážáŸ’ážáž›áŸážáž¶ážáž¶áž„ក្រៅនៅក្នុងចំណូលចិážáŸ’ážáž€áž¶áž”ូបជាមុនសិន។</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">អ្នកចុះហážáŸ’ážáž›áŸážáž¶ážáž¶áž„ក្រៅ</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">បង្កើáž</translation>
</message>
- </context>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">ចងក្រងដោយមិនមានការគាំទ្រការចុះហážáŸ’ážáž›áŸážáž¶ážáž¶áž„ក្រៅ (ទាមទារសម្រាប់ការចុះហážáŸ’ážáž›áŸážáž¶ážáž¶áž„ក្រៅ)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -812,6 +1031,27 @@
<translation type="unfinished">ប៊ីážážáž‰</translation>
</message>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(នៃ%n ជីហ្គាប៊ៃ ដែលážáŸ’រូវការ)</numerusform>
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -960,11 +1200,18 @@
<translation type="unfinished">&amp;បង្ហាញ</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">ចងក្រងដោយមិនមានការគាំទ្រការចុះហážáŸ’ážáž›áŸážáž¶ážáž¶áž„ក្រៅ (ទាមទារសម្រាប់ការចុះហážáŸ’ážáž›áŸážáž¶ážáž¶áž„ក្រៅ)</translation>
+ </message>
+ <message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">បញ្ចាក់ជម្រើសការកែសម្រួលឡើងវិញ</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">ផ្ទាំងអážáž·ážáž·áž‡áž“áž“áž·áž„ážáŸ’រូវបិទ។ ážáž¾áž¢áŸ’នកចង់បន្ážáž‘ៀážáž«áž‘áŸ?</translation>
</message>
<message>
@@ -1314,6 +1561,11 @@
<translation type="unfinished">áž…áŸáž‰áŸˆ</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;ចម្លងអាសយដ្ឋាន</translation>
+ </message>
+ <message>
<source>Network activity disabled</source>
<translation type="unfinished">សកម្មភាពបណ្ážáž¶áž‰ ážáŸ’រូវបានដាក់អោយប្រើការលែងបាន។</translation>
</message>
@@ -1405,6 +1657,18 @@
<translation type="unfinished">ážážáž…ម្លង &amp;RUl</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;ចម្លងអាសយដ្ឋាន</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">ចម្លង &amp; ស្លាក</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">ចម្លង &amp; ចំនួន</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">មិនអាចបើកសោរ កាបូបអáŸáž¡áž·áž…ážáŸ’រូនិចបាន។</translation>
</message>
@@ -1594,10 +1858,6 @@
<source>Transaction creation failed!</source>
<translation type="unfinished">បង្កើážáž”្រážáŸ’ážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáž˜áž·áž“ជោគជáŸáž™!</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">សំណើរទូរទាážáŸ‹áž”្រាក់បានផុážáž€áŸ†ážŽážáŸ‹áŸ”</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -1649,26 +1909,10 @@
<translation type="unfinished">សារៈ</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">áž“áŸáŸ‡áž‡áž¶ážŸáŸ†ážŽáž¾ážšáž‘ូរទាážáŸ‹áž”្រាក់មិនទាន់បានបញ្ចាក់ážáž¶áž˜áž…្បាប់ážáŸ’រឹមážáŸ’រូវ។</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">áž“áŸáŸ‡áž‡áž¶ážŸáŸ†ážŽáž¾ážšáž‘ូរទាážáŸ‹áž”្រាក់ដែលបានបញ្ចាក់ážáž¶áž˜áž…្បាប់ážáŸ’រឹមážáŸ’រូវ។</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">បញ្ចូលស្លាក​សញ្ញាមួយ សម្រាប់អាសយដ្ឋាននáŸáŸ‡ ដើម្បីបញ្ចូលវាទៅក្នងបញ្ចីរអាសយដ្ឋានដែលបានប្រើប្រាស់</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">បង់ទៅកាន់</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">អនុស្សរណៈ</translation>
- </message>
-</context>
+ </context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -1803,6 +2047,7 @@
<name>TransactionDesc</name>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">បានបោះបង់ចោល</translation>
</message>
<message>
@@ -2031,10 +2276,27 @@
<translation type="unfinished">ចំនួនážáž·áž…បំផុáž</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;ចម្លងអាសយដ្ឋាន</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">ចម្លង &amp; ស្លាក</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">ចម្លង &amp; ចំនួន</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">ប្រវážáŸ’ážáž·áž“ៃការនាំចáŸáž‰áž”្រážáŸ’ážáž·áž”ážáŸ’ážáž·áž€áž¶ážš</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Comma បំបែកឯកសារ</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">បានបញ្ចាក់រួចរាល់</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ko.ts b/src/qt/locale/bitcoin_ko.ts
index f335deb009..94f0a2e030 100644
--- a/src/qt/locale/bitcoin_ko.ts
+++ b/src/qt/locale/bitcoin_ko.ts
@@ -3,11 +3,11 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">지갑 주소나 ë¼ë²¨ì„ 수정하려면 ìš°í´ë¦­ì„ 하십시오.</translation>
+ <translation type="unfinished">ìš°í´ë¦­í•˜ì—¬ 주소나 ìƒí‘œ 수정하기</translation>
</message>
<message>
<source>Create a new address</source>
- <translation type="unfinished">새로운 지갑 주소 ìƒì„±</translation>
+ <translation type="unfinished">새로운 주소 ìƒì„± </translation>
</message>
<message>
<source>&amp;New</source>
@@ -51,7 +51,7 @@
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation type="unfinished">ì½”ì¸ì„ ë°›ì„ ì£¼ì†Œë¥¼ ì„ íƒí•˜ì‹­ì‹œì˜¤.</translation>
+ <translation type="unfinished">ì½”ì¸ì„ ë°›ì„ ì£¼ì†Œë¥¼ ì„ íƒí•˜ì‹­ì‹œì˜¤</translation>
</message>
<message>
<source>C&amp;hoose</source>
@@ -153,7 +153,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unlock wallet</source>
- <translation type="unfinished">지갑 ìž ê¸ˆì„ í•´ì œ</translation>
+ <translation type="unfinished">지갑 잠금 해제</translation>
</message>
<message>
<source>Change passphrase</source>
@@ -169,7 +169,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Are you sure you wish to encrypt your wallet?</source>
- <translation type="unfinished">지갑 암호화를 허용하시겠습니까?</translation>
+ <translation type="unfinished">ì •ë§ë¡œ ì§€ê°‘ì„ ì•”í˜¸í™”í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
</message>
<message>
<source>Wallet encrypted</source>
@@ -246,6 +246,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">%1íŒŒì¼ ì„¸íŒ…ì´ ìž˜ëª»ë˜ì—ˆê±°ë‚˜ 유효하지 않습니다.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">ëŸ°ì–´ì›¨ì´ ì˜ˆì™¸</translation>
</message>
@@ -265,6 +269,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">초기값으로 리셋하거나 ë³€ë™ì‚¬í•­ì—†ì´ 진행하시겠습니까?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">심ê°í•œ 문제가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤. 세팅 파ì¼ì´ 작성가능한지 확ì¸í•˜ê±°ë‚˜ ì„¸íŒ…ì—†ì´ ì‹¤í–‰ì„ ì‹œë„해보세요.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">오류: 지정한 ë°ì´í„° í´ë” "%1"ì€ ì¡´ìž¬í•˜ì§€ 않습니다.</translation>
</message>
@@ -358,31 +372,31 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nì´ˆ</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n분</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n시간</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nì¼</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n주</numerusform>
</translation>
</message>
<message>
@@ -392,7 +406,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%në…„</numerusform>
</translation>
</message>
<message>
@@ -431,10 +445,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">-maxtxfee ê°’ì´ ë„ˆë¬´ í½ë‹ˆë‹¤! í•˜ë‚˜ì˜ ê±°ëž˜ì— ë„ˆë¬´ í° ìˆ˜ìˆ˜ë£Œê°€ 지불 ë©ë‹ˆë‹¤.</translation>
</message>
<message>
+ <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
+ <translation type="unfinished">%i버젼ì—ì„œ %i버젼으로 다운그레ì´ë“œ í•  수 없습니다. 월렛 ë²„ì ¼ì€ ë³€ê²½ë˜ì§€ 않았습니다.</translation>
+ </message>
+ <message>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<translation type="unfinished">ë°ì´í„° 디렉토리 %s ì— ë½ì„ 걸 수 없었습니다. %sê°€ ì´ë¯¸ 실행 ì¤‘ì¸ ê²ƒìœ¼ë¡œ 보입니다.</translation>
</message>
<message>
+ <source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
+ <translation type="unfinished">사전분리 키풀를 지ì›í•˜ê¸° 위해서 업그레ì´ë“œ 하지 않고는 Non HD split ì§€ê°‘ì˜ %ië²„ì ¼ì„ %i버젼으로 업그레ì´ë“œ í•  수 없습니다. %ië²„ì ¼ì„ í™œìš©í•˜ê±°ë‚˜ 구체화ë˜ì§€ ì•Šì€ ë²„ì ¼ì„ í™œìš©í•˜ì„¸ìš”.</translation>
+ </message>
+ <message>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished">MIT 소프트웨어 ë¼ì´ì„¼ìŠ¤ì— ë”°ë¼ ë°°í¬ë˜ì—ˆìŠµë‹ˆë‹¤. 첨부 íŒŒì¼ %s ë˜ëŠ” %sì„ ì°¸ì¡°í•˜ì‹­ì‹œì˜¤.</translation>
</message>
@@ -443,22 +465,58 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%s 불러오기 오류! 주소 키는 ëª¨ë‘ ì •í™•í•˜ê²Œ 로드ë˜ì—ˆìœ¼ë‚˜ 거래 ë°ì´í„°ì™€ ì£¼ì†Œë¡ í•„ë“œì—ì„œ 누ë½ì´ë‚˜ 오류가 존재할 수 있습니다.</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">오류: 들어오는 ì—°ê²°ì„ í—ˆìš©í•˜ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤ (리슨 오류: %s)</translation>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">%s를 ì½ëŠ”ë° ì—러가 ìƒê²¼ìŠµë‹ˆë‹¤. 트랜잭션 ë°ì´í„°ê°€ 잘못ë˜ì—ˆê±°ë‚˜ 누ë½ë˜ì—ˆìŠµë‹ˆë‹¤. ì§€ê°‘ì„ ë‹¤ì‹œ 스ìºë‹í•©ë‹ˆë‹¤.</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
+ <translation type="unfinished">오류 : ë¤í”„íŒŒì¼ í¬ë§· 기ë¡ì´ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤. "í¬ë§·"ì´ ì•„ë‹ˆë¼ "%s"를 얻었습니다.</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source>
+ <translation type="unfinished">오류 : ë¤í”„íŒŒì¼ ì‹ë³„ìž ê¸°ë¡ì´ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤. "%s"ì´ ì•„ë‹Œ "%s"를 얻었습니다.</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
+ <translation type="unfinished">오류 : ë¤í”„íŒŒì¼ ë²„ì ¼ì´ ì§€ì›ë˜ì§€ 않습니다. ì´ ë¹„íŠ¸ì½”ì¸ ì§€ê°‘ ë²„ì ¼ì€ ì˜¤ì§ ë²„ì ¼1ì˜ ë¤í”„파ì¼ì„ 지ì›í•©ë‹ˆë‹¤. %së²„ì ¼ì˜ ë¤í”„파ì¼ì„ 얻었습니다.</translation>
+ </message>
+ <message>
+ <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
+ <translation type="unfinished">오류 : 레거시 지갑주소는 "레거시", "p2sh-segwit", "bech32" 지갑 ì£¼ì†Œì˜ íƒ€ìž…ë§Œ 지ì›í•©ë‹ˆë‹¤.</translation>
</message>
<message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">수수료 ì¶”ì •ì´ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤. 고장 대체 수수료가 비활성화 ìƒíƒœìž…니다. 몇 블ë¡ì„ 기다리거나 -fallbackfee를 활성화 하십시오.</translation>
</message>
<message>
+ <source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
+ <translation type="unfinished">%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 type="unfinished">유효하지 ì•Šì€ ê¸ˆì•¡ -maxtxfee=&lt;amount&gt;: '%s' (거래가 막히는 ìƒí™©ì„ 방지하게 위해 ì ì–´ë„ %s ì˜ ì¤‘ê³„ 수수료를 지정해야 합니다)</translation>
</message>
<message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">유효하지 않거나 ì†ìƒëœ peers.dat(%s). 만약 ì´ê²Œ ë²„ê·¸ì¸ ê²½ìš°ì—, %sì´ìª½ìœ¼ë¡œ 리í¬íŠ¸í•´ì£¼ì„¸ìš”. 새로 만들어서 시작하기 위한 해결방법으로 %s파ì¼ì„ 옮길 수 있습니다. (ì´ë¦„ 재설정, íŒŒì¼ ì˜®ê¸°ê¸° í˜¹ì€ ì‚­ì œ).</translation>
+ </message>
+ <message>
<source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
<translation type="unfinished">하나 ì´ìƒì˜ 양파 ë°”ì¸ë”© 주소가 제공ë©ë‹ˆë‹¤. ìžë™ìœ¼ë¡œ ìƒì„± ëœ Tor onion ì„œë¹„ìŠ¤ì— %s 사용.</translation>
</message>
<message>
+ <source>No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">ë¤í”„파ì¼ì´ ìž…ë ¥ë˜ì§€ 않았습니다. ë¤í”„파ì¼ì„ 사용하기 위해서는 -dumpfile=&lt;filename&gt;ì´ ë°˜ë“œì‹œ ìž…ë ¥ë˜ì–´ì•¼ 합니다. </translation>
+ </message>
+ <message>
+ <source>No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">ë¤í”„파ì¼ì´ ìž…ë ¥ë˜ì§€ 않았습니다. ë¤í”„를 사용하기 위해서는 -dumpfile=&lt;filename&gt;ì´ ë°˜ë“œì‹œ ìž…ë ¥ë˜ì–´ì•¼ 합니다.</translation>
+ </message>
+ <message>
+ <source>No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
+ <translation type="unfinished">shshhdchb bdfjj fb rciivfjb doffbfbdjdj</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 type="unfinished">ì»´í“¨í„°ì˜ ë‚ ì§œì™€ ì‹œê°„ì´ ì˜¬ë°”ë¥¸ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤! ì‹œê°„ì´ ìž˜ëª»ë˜ë©´ %sì€ ì œëŒ€ë¡œ ë™ìž‘하지 않습니다.</translation>
</message>
@@ -483,6 +541,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ë¸”ë¡ ë°ì´í„°ë² ì´ìŠ¤ì— ë¯¸ëž˜ì˜ ë¸”ë¡ì´ í¬í•¨ë˜ì–´ 있습니다. ì´ê²ƒì€ 사용ìžì˜ ì»´í“¨í„°ì˜ ë‚ ì§œì™€ ì‹œê°„ì´ ì˜¬ë°”ë¥´ê²Œ 설정ë˜ì–´ 있지 ì•Šì„ë•Œ 나타날 수 있습니다. ë¸”ë¡ ë°ì´í„° ë² ì´ìŠ¤ì˜ ìž¬êµ¬ì„±ì€ ì‚¬ìš©ìžì˜ ì»´í“¨í„°ì˜ ë‚ ì§œì™€ ì‹œê°„ì´ ì˜¬ë°”ë¥´ë‹¤ê³  확신할 ë•Œì—만 하십시오.</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">udhdbfjfjdnbdjfjf hdhdbjcn2owkd. jjwbdbdof dkdbdnck wdkdj </translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished">ê±°ëž˜ì•¡ì´ ìˆ˜ìˆ˜ë£Œë¥¼ 지불하기엔 너무 작습니다</translation>
</message>
@@ -543,6 +605,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%s 주소를 확ì¸í•  수 없습니다: '%s'</translation>
</message>
<message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">naravfbj. dufb jdncnlfs. jx dhcji djc d jcbc jdnbfbicb </translation>
+ </message>
+ <message>
<source>Cannot set -peerblockfilters without -blockfilterindex.</source>
<translation type="unfinished">-blockfilterindex는 -peerblockfilters ì—†ì´ ì‚¬ìš©í•  수 없습니다.</translation>
</message>
@@ -576,7 +642,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Done loading</source>
- <translation type="unfinished">로딩 완료</translation>
+ <translation type="unfinished">불러오기 완료</translation>
+ </message>
+ <message>
+ <source>Dump file %s does not exist.</source>
+ <translation type="unfinished">íŒŒì¼ ë²„ë¦¬ê¸° 1%s 존재 안함
+</translation>
+ </message>
+ <message>
+ <source>Error creating %s</source>
+ <translation type="unfinished">만들기 오류 1%s
+</translation>
</message>
<message>
<source>Error initializing block database</source>
@@ -592,7 +668,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error loading %s: Private keys can only be disabled during creation</source>
- <translation type="unfinished">%s 로딩 실패: ê°œì¸í‚¤ëŠ” ìƒì„±í• ë•Œë§Œ 비활성화 í•  수 있습니다</translation>
+ <translation type="unfinished">%s 불러오기 오류: ê°œì¸í‚¤ëŠ” ìƒì„±í• ë•Œë§Œ 비활성화 í•  수 있습니다</translation>
</message>
<message>
<source>Error loading %s: Wallet corrupted</source>
@@ -612,11 +688,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error reading from database, shutting down.</source>
- <translation type="unfinished">ë¸”ë¡ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ë¶ˆëŸ¬ì˜¤ëŠ”ë° ì˜¤ë¥˜ê°€ ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤, 곧 종료ë©ë‹ˆë‹¤.</translation>
+ <translation type="unfinished">ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ë¶ˆëŸ¬ì˜¤ëŠ”ë° ì˜¤ë¥˜ê°€ ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤, 곧 종료ë©ë‹ˆë‹¤.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">ì²´ì¸ ìƒíƒœ ë°ì´í„°ë² ì´ìŠ¤ 업그레ì´ë“œ 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤.</translation>
+ <source>Error reading next record from wallet database</source>
+ <translation type="unfinished">지갑 ë°ì´í„°ë² ì´ìŠ¤ì—ì„œ ë‹¤ìŒ ê¸°ë¡ì„ ë¶ˆëŸ¬ì˜¤ëŠ”ë° ì˜¤ë¥˜ê°€ ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤.</translation>
</message>
<message>
<source>Error: Disk space is low for %s</source>
@@ -627,6 +703,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">오류: í‚¤í’€ì´ ë°”ë‹¥ë‚¨, 키풀 ë¦¬í•„ì„ ë¨¼ì € 호출할 하십시오</translation>
</message>
<message>
+ <source>Error: Missing checksum</source>
+ <translation type="unfinished">오류: ì²´í¬ì„¬ 누ë½</translation>
+ </message>
+ <message>
+ <source>Error: Unable to write record to new wallet</source>
+ <translation type="unfinished">오류: 새로운 ì§€ê°‘ì— ê¸°ë¡í•˜ì§€ 못했습니다.</translation>
+ </message>
+ <message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation type="unfinished">í¬íŠ¸ ì—°ê²°ì— ì‹¤íŒ¨í•˜ì˜€ìŠµë‹ˆë‹¤. 필요하다면 -리슨=0 ì˜µì…˜ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤.</translation>
</message>
@@ -711,10 +795,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">-whitebind: '%s' 를 ì´ìš©í•˜ì—¬ í¬íŠ¸ë¥¼ 지정해야 합니다</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">프ë¡ì‹œ 서버가 지정ë˜ì§€ 않았습니다. -proxy =&lt;ip&gt; ë˜ëŠ” -proxy =&lt;ip:port&gt;를 사용하십시오.</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">íŒŒì¼ ë””ìŠ¤í¬ë¦½í„°ê°€ 부족합니다.</translation>
</message>
@@ -723,10 +803,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ë¸”ë¡ ì¶•ì†ŒëŠ” ìŒìˆ˜ë¡œ 설정할 수 없습니다.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">ë¸”ë¡ ì¶•ì†Œ 모드는 -coinstatsindex와 호환ë˜ì§€ 않습니다.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">ë¸”ë¡ ì¶•ì†Œ 모드는 -txindex와 호환ë˜ì§€ 않습니다.</translation>
</message>
@@ -851,6 +927,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">키 ìƒì„± 불가</translation>
</message>
<message>
+ <source>Unable to open %s for writing</source>
+ <translation type="unfinished">%sì„ ì“°ê¸° 위하여 ì—´ 수 없습니다.</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">HTTP 서버를 시작할 수 없습니다. ìžì„¸í•œ ì‚¬í•­ì€ ë””ë²„ê·¸ 로그를 í™•ì¸ í•˜ì„¸ìš”.</translation>
</message>
@@ -867,12 +947,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">-onlynet: '%s' ì— ì•Œìˆ˜ì—†ëŠ” 네트워í¬ê°€ 지정ë˜ì—ˆìŠµë‹ˆë‹¤</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">지ì›ë˜ì§€ 않는 로깅 카테고리 %s = %s.</translation>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished">ì•Œ 수 없는 새로운 ê·œì¹™ì´ í™œì„±í™” ë˜ì—ˆìŠµë‹ˆë‹¤. (versionbit %i)</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">UTXO ë°ì´í„°ë² ì´ìŠ¤ 업그레ì´ë“œ</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">지ì›ë˜ì§€ 않는 로깅 카테고리 %s = %s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
@@ -1093,7 +1173,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n블ë¡ì˜ 트랜잭션 ë‚´ì—­ì´ ì²˜ë¦¬ë˜ì—ˆìŠµë‹ˆë‹¤.</numerusform>
</translation>
</message>
<message>
@@ -1129,10 +1209,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">최신 정보</translation>
</message>
<message>
+ <source>Ctrl+Q</source>
+ <translation type="unfinished">Crtl + Q</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction</source>
<translation type="unfinished">부분ì ìœ¼ë¡œ ì„œëª…ëœ ë¹„íŠ¸ì½”ì¸ íŠ¸ëžœìž­ì…˜ 불러오기</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">PSBT í˜¹ì€ í´ë¦½ë³´ë“œì—ì„œ 불러오기</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">í´ë¦½ë³´ë“œë¡œë¶€í„° 부분ì ìœ¼ë¡œ ì„œëª…ëœ ë¹„íŠ¸ì½”ì¸ íŠ¸ëžœìž­ì…˜ 불러오기</translation>
</message>
@@ -1169,6 +1257,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">지갑 닫기</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">지갑 복구</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">백업파ì¼ì—ì„œ 지갑 복구하기</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">모든 지갑 닫기</translation>
</message>
@@ -1193,6 +1291,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">사용 가능한 블ë¡ì´ 없습니다.</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">지갑 정보</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">지갑 ì´ë¦„</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">ì°½(&amp;W)</translation>
</message>
@@ -1212,11 +1320,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>&amp;Hide</source>
<translation type="unfinished">&amp;숨기기</translation>
</message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">보여주기</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>ë¹„íŠ¸ì½”ì¸ ë„¤íŠ¸ì›Œí¬ì— í™œì„±í™”ëœ %nì—°ê²°</numerusform>
</translation>
</message>
<message>
@@ -1410,6 +1522,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">복사 &amp; 금액</translation>
</message>
<message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">거래 &amp; ê²°ê³¼ ì¸ë±ìŠ¤ê°’ í˜¹ì€ ID 복사</translation>
+ </message>
+ <message>
<source>L&amp;ock unspent</source>
<translation type="unfinished">L&amp;ock 미사용</translation>
</message>
@@ -1498,6 +1614,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">서명ìžë¥¼ 나열할 수 없습니다.</translation>
</message>
+ </context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">지갑 불러오기</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">지갑 불러오는 중...</translation>
+ </message>
</context>
<context>
<name>OpenWalletActivity</name>
@@ -1703,13 +1832,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Bitcoin</source>
<translation type="unfinished">비트코ì¸</translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(필요한 %1GB 중)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(ì „ì²´ ì²´ì¸ì— 필요한 %1GB)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB가 필요합니다.)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(Full ì²´ì¸ì´ ë˜ë ¤ë©´ %n GB ê°€ 필요합니다.)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1723,7 +1862,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nì¼ì°¨ ë°±ì—…ì„ ë³µêµ¬í•˜ê¸°ì— ì¶©ë¶„í•©ë‹ˆë‹¤.</numerusform>
</translation>
</message>
<message>
@@ -1755,10 +1894,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">í”„ë¡œê·¸ëž¨ì´ ì²˜ìŒìœ¼ë¡œ 실행ë˜ê³  있습니다. %1ê°€ ì–´ë””ì— ë°ì´í„°ë¥¼ 저장할지 ì„ íƒí•  수 있습니다.</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 type="unfinished">'확ì¸'ì„ í´ë¦­í•˜ë©´, %1ì€ ëª¨ë“  %4 ë¸”ë¡ ì²´ì¸ (%2GB) 장부를 가장 최근 거래 부터 %3 ì•ˆì— ë‹¤ìš´ë¡œë“œí•˜ê³  처리하는ë°, ì´ê²ƒì€ %4ê°€ 활성화 ë ë•Œ 시작ë©ë‹ˆë‹¤. </translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">블ë¡ì²´ì¸ 스토리지를 다ìŒìœ¼ë¡œ 제한하기 </translation>
</message>
@@ -1867,7 +2002,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">ì•Œ 수 ì—†ìŒ. í—¤ë” ë™ê¸°í™” 중(%1, %2)...</translation>
</message>
-</context>
+ </context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -1951,14 +2086,44 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ì´ ì„¤ì •ì„ ë˜ëŒë¦¬ë ¤ë©´ 처ìŒë¶€í„° 블ë¡ì²´ì¸ì„ 다시 다운로드 받아야 합니다.</translation>
</message>
<message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">최대 ë°ì´í„°ë² ì´ìŠ¤ ìºì‹œ 사ì´ì¦ˆì— ë„달했습니다. ë” í° ìš©ëŸ‰ì˜ ìºì‹œëŠ” ë” ë¹ ë¥´ê²Œ 싱í¬ë¥¼ 맞출 수 있으며 ëŒ€ë¶€ë¶„ì˜ ìœ ì € ê²½ìš°ì— ìœ ë¦¬í•©ë‹ˆë‹¤. ìºì‹œ 사ì´ì¦ˆë¥¼ 작게 만드는 ê²ƒì€ ë©”ëª¨ë¦¬ ì‚¬ìš©ì„ ì¤„ìž…ë‹ˆë‹¤. 미사용 ë©¤í’€ì˜ ë©”ëª¨ë¦¬ëŠ” ì´ ìºì‹œë¥¼ 위해 공유ë©ë‹ˆë‹¤.</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">스í¬ë¦½íŠ¸ ê²€ì¦ ìˆ˜ëª…ì˜ ìˆ«ìžë¥¼ 설정하세요. ìŒìˆ˜ëŠ” ì‹œìŠ¤í…œì— ë¬¶ì´ì§€ 않는 ìžìœ ë¡œìš´ ì½”ì–´ì˜ ìˆ˜ë¥¼ 뜻합니다.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = ìžë™, &lt;0 = ì§€ì •ëœ ì½”ì–´ ê°œìˆ˜ë§Œí¼ ì‚¬ìš© 안함)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">당신 í˜¹ì€ 3ìžì˜ ê°œë°œíˆ´ì´ JSON-RPC 명령과 커맨드ë¼ì¸ì„ 통해 노드와 소통하는 ê²ƒì„ í—ˆë½í•©ë‹ˆë‹¤.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">R&amp;PC 서버를 가능하게 합니다.</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">지갑(&amp;A)</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">수수료 ê°ë©´ì„ 초기값으로 할지 í˜¹ì€ ì„¤ì •í•˜ì§€ ì•Šì„지를 결정합니다.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">초기 설정값으로 수수료를 ëºë‹ˆë‹¤.</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">전문가</translation>
</message>
@@ -1975,10 +2140,25 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ê²€ì¦ë˜ì§€ ì•Šì€ ìž”ëˆ ì“°ê¸° (&amp;S)</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">PSBT ì»¨íŠ¸ë¡¤ì„ ê°€ëŠ¥í•˜ê²Œ 합니다.</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">PSBT ì»¨íŠ¸ë¡¤ì„ ë³´ì—¬ì¤„ì§€ë¥¼ 결정합니다.</translation>
+ </message>
+ <message>
<source>External Signer (e.g. hardware wallet)</source>
<translation type="unfinished">외부 ì„œëª…ìž (예: 하드웨어 지갑)</translation>
</message>
<message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">외부 ì„œëª…ìž ìŠ¤í¬ë¦½íŠ¸ 경로
+ </translation>
+ </message>
+ <message>
<source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
<translation type="unfinished">ë¹„íŠ¸ì½”ì¸ ì½”ì–´ 호환 스í¬ë¦½íŠ¸ì˜ ì „ì²´ 경로 (예: C:\Downloads\whi.exe ë˜ëŠ” /Users/you/Downloads/hwi.py). 주ì˜: 악성 í”„ë¡œê·¸ëž¨ì´ ì½”ì¸ì„ 훔칠 수 있습니다!</translation>
</message>
@@ -2075,6 +2255,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ì¸í„°íŽ˜ì´ìŠ¤ì— 표시하고 ì½”ì¸ì„ 보낼때 사용할 기본 최소화 단위를 ì„ íƒí•˜ì‹­ì‹œì˜¤.</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 type="unfinished">ë‚´ìš© 메뉴 ì•„ì´í…œìœ¼ë¡œ 거래내역 íƒ­ì´ ë³´ì´ëŠ” ì œ3ìž URL (블ë¡ìµìŠ¤í”„로러). URLì— %s는 트랜잭션 해시값으로 대체ë©ë‹ˆë‹¤. ë³µìˆ˜ì˜ URLì€ ìˆ˜ì§í•­ëª©ìœ¼ë¡œë¶€í„° 분리ë©ë‹ˆë‹¤. </translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">ì œ3ìž íŠ¸ëžœìž­ì…˜ URL</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">ì½”ì¸ ìƒì„¸ ì œì–´ê¸°ëŠ¥ì— ëŒ€í•œ 표시 여부를 ì„ íƒí•  수 있습니다.</translation>
</message>
@@ -2095,8 +2283,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1 í¬í•¨ë¨</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">ì´ ë‹¤ì´ì–¼ë¡œê·¸ì—ì„œ 설정한 ì˜µì…˜ì€ ì»¤ë§¨ë“œë¼ì¸ì´ë‚˜ 설정파ì¼ì— ì˜í•´ 바뀔 수 있습니다:</translation>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">가장 가까운 ì˜ë¯¸ "1%1"</translation>
</message>
<message>
<source>&amp;OK</source>
@@ -2121,14 +2309,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">옵션 초기화를 확실화하기</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">변경 ì‚¬í•­ì„ ì ìš©í•˜ê¸° 위해서는 í”„ë¡œê·¸ëž¨ì´ ì¢…ë£Œ 후 재시작ë˜ì–´ì•¼ 합니다.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">í´ë¼ì´ì–¸íŠ¸ê°€ 종료ë©ë‹ˆë‹¤, ê³„ì† ì§„í–‰í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
</message>
<message>
@@ -2280,8 +2471,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">거래 서명 실패: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">ì§€ê°‘ì´ ìž ê²¨ìžˆëŠ” ë™ì•ˆ ìž…ë ¥ì„ ì„œëª…í•  수 없습니다.</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
- <translation type="unfinished">ë” ì´ìƒ 추가ì ì¸ ì¸í’‹ì— 대해 서명할 수 ì—†ìŒ</translation>
+ <translation type="unfinished">ë” ì´ìƒ 추가ì ì¸ ìž…ë ¥ì— ëŒ€í•´ 서명할 수 없습니다.</translation>
</message>
<message>
<source>Signed transaction successfully. Transaction is ready to broadcast.</source>
@@ -2349,6 +2544,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">거래가 ì•„ì§ ì„œëª…(들)ì„ í•„ìš”ë¡œ 합니다.</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">하지만 지갑 ë¡œë”©ì´ ë˜ì§€ 않았습니다.</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(그러나 ì´ ì§€ê°‘ì€ ê±°ëž˜ì— ì„œëª…ì´ ë¶ˆê°€ëŠ¥í•©ë‹ˆë‹¤.)</translation>
</message>
@@ -2609,6 +2808,26 @@ BIP70ì˜ ê´‘ë²”ìœ„í•œ 보안 결함으로 ì¸í•´ 모든 가맹ì ì—서는 지ê°
<translation type="unfinished">ë§¤í•‘ëœ AS</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">ì´ í”¼ì–´ì—게 지갑주소를 릴레ì´í• ì§€ë¥¼ 결정합니다.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">지갑주소를 릴레ì´í•©ë‹ˆë‹¤.</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">ì²˜ë¦¬ëœ ì§€ê°‘</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">ì§€ê°‘ì˜ Rate제한</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">유저 ì—ì´ì „트</translation>
</message>
@@ -2746,6 +2965,37 @@ BIP70ì˜ ê´‘ë²”ìœ„í•œ 보안 결함으로 ì¸í•´ 모든 가맹ì ì—서는 지ê°
<translation type="unfinished">출력:</translation>
</message>
<message>
+ <source>Inbound: initiated by peer</source>
+ <extracomment>Explanatory text for an inbound peer connection.</extracomment>
+ <translation type="unfinished">ì‹œìž‘ì  : ë™ê¸°ì— ì˜í•´ 시작ë¨</translation>
+ </message>
+ <message>
+ <source>Outbound Full Relay: default</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment>
+ <translation type="unfinished">아웃바운드 ì „ì²´ 릴레ì´: 기본값</translation>
+ </message>
+ <message>
+ <source>Outbound Block Relay: does not relay transactions or addresses</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">아웃바운드 ë¸”ë¡ ë¦´ë ˆì´: 트랜잭션 ë˜ëŠ” 주소를 릴레ì´í•˜ì§€ ì•ŠìŒ</translation>
+ </message>
+ <message>
+ <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
+ <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment>
+ <translation type="unfinished">아웃바운드 매뉴얼 : RPC 1%1 ì´ë‚˜ 2%2/3%3 ì„ ì‚¬ìš©í•´ì„œ 환경설정 ì˜µì…˜ì„ ì¶”ê°€</translation>
+ </message>
+ <message>
+ <source>Outbound Feeler: short-lived, for testing addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Outbound Feeler: ì§§ì€ ìš©ë„, 주소 테스트용</translation>
+ </message>
+ <message>
+ <source>Outbound Address Fetch: short-lived, for soliciting addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment>
+ <translation type="unfinished">아웃바운드 주소 가져오기: 단기, 주소 요청용
+ </translation>
+ </message>
+ <message>
<source>we selected the peer for high bandwidth relay</source>
<translation type="unfinished">ì €í¬ëŠ” 가장 빠른 대역í­ì„ 가지고 있는 피어를 ì„ íƒí•©ë‹ˆë‹¤.</translation>
</message>
@@ -2754,6 +3004,10 @@ BIP70ì˜ ê´‘ë²”ìœ„í•œ 보안 결함으로 ì¸í•´ 모든 가맹ì ì—서는 지ê°
<translation type="unfinished">피어는 ë†’ì€ ëŒ€ì—­í­ì„ 위해 우리를 ì„ íƒí•©ë‹ˆë‹¤</translation>
</message>
<message>
+ <source>no high bandwidth relay selected</source>
+ <translation type="unfinished">ê³ ëŒ€ì—­í­ ë¦´ë ˆì´ê°€ ì„ íƒë˜ì§€ ì•ŠìŒ</translation>
+ </message>
+ <message>
<source>&amp;Copy address</source>
<extracomment>Context menu action to copy the address of a peer.</extracomment>
<translation type="unfinished">&amp; 주소 복사</translation>
@@ -2779,6 +3033,11 @@ BIP70ì˜ ê´‘ë²”ìœ„í•œ 보안 결함으로 ì¸í•´ 모든 가맹ì ì—서는 지ê°
<translation type="unfinished">1ë…„(&amp;Y)</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">IP/Netmask 복사하기</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">노드 차단 취소(&amp;U)</translation>
</message>
@@ -2795,6 +3054,23 @@ BIP70ì˜ ê´‘ë²”ìœ„í•œ 보안 결함으로 ì¸í•´ 모든 가맹ì ì—서는 지ê°
<translation type="unfinished">"%1" ì§€ê°‘ì„ ì‚¬ìš©í•˜ì—¬ 명령 실행</translation>
</message>
<message>
+ <source>Welcome to the %1 RPC console.
+Use up and down arrows to navigate history, and %2 to clear screen.
+Use %3 and %4 to increase or decrease the font size.
+Type %5 for an overview of available commands.
+For more information on using this console, type %6.
+
+%7WARNING: 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.%8</source>
+ <extracomment>RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</extracomment>
+ <translation type="unfinished">1%1 RPC ì½˜ì†”ì— ì˜¤ì‹  ê²ƒì„ í™˜ì˜í•©ë‹ˆë‹¤.
+위쪽 ë° ì•„ëž˜ìª½ 화살표를 사용하여 ê¸°ë¡ íƒìƒ‰ì„하고 2%2를 사용하여 í™”ë©´ì„ ì§€ìš°ì„¸ìš”.
+3%3ê³¼ 4%4ì„ ì‚¬ìš©í•˜ì—¬ 글꼴 í¬ê¸° ì¦ê°€ ë˜ëŠ” ê°ì†Œí•˜ì„¸ìš”
+사용 가능한 ëª…ë ¹ì˜ ê°œìš”ë¥¼ 보려면 5%5를 입력하십시오.
+ì´ ì½˜ì†” ì‚¬ìš©ì— ëŒ€í•œ ìžì„¸í•œ ë‚´ìš©ì„ ë³´ë ¤ë©´ 6%6ì„ ìž…ë ¥í•˜ì‹­ì‹œì˜¤.
+7%7 경고: ì‚¬ê¸°ê¾¼ë“¤ì€ ì‚¬ìš©ìžë“¤ì—게 ì—¬ê¸°ì— ëª…ë ¹ì„ ìž…ë ¥í•˜ë¼ê³  ë§í•˜ê³  활발히 ê¸ˆí’ˆì„ í›”ì¹©ë‹ˆë‹¤. 완전히 ì´í•´í•˜ì§€ ì•Šê³  ì´ ì½˜ì†”ì„ ì‚¬ìš©í•˜ì§€ 마십시오. 8%8
+</translation>
+ </message>
+ <message>
<source>Executing…</source>
<extracomment>A console message indicating an entered command is currently being executed.</extracomment>
<translation type="unfinished">실행 중...</translation>
@@ -3242,6 +3518,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">%1ì„ %2ë¡œ</translation>
</message>
<message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">ìˆ˜ì‹ ìž ëª©ë¡ì„ 검토하기 위해 "ìžì„¸ížˆ 보기"를 í´ë¦­í•˜ì„¸ìš”</translation>
+ </message>
+ <message>
+ <source>Sign failed</source>
+ <translation type="unfinished">서명 실패</translation>
+ </message>
+ <message>
<source>External signer not found</source>
<extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
<translation type="unfinished">외부 서명ìžë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ</translation>
@@ -3265,6 +3549,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">PSBT 저장ë¨</translation>
</message>
<message>
+ <source>External balance:</source>
+ <translation type="unfinished">ì™¸ë¶€ì˜ ìž”ê³ </translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">ë˜ëŠ”</translation>
</message>
@@ -3278,6 +3566,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">거래 ì œì•ˆì„ ê²€í† í•´ 주십시오. ì´ê²ƒì€ ë‹¹ì‹ ì´ ì €ìž¥í•˜ê±°ë‚˜ 복사한 ë’¤ e.g. 오프ë¼ì¸ %1 지갑 ë˜ëŠ” PSBT 호환 하드웨어 지갑으로 서명할 수 있는 PSBT (부분ì ìœ¼ë¡œ ì„œëª…ëœ ë¹„íŠ¸ì½”ì¸ íŠ¸ëžœìž­ì…˜)를 ìƒì„±í•  것입니다.</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">ì´ íŠ¸ëžœìž­ì…˜ì„ ìƒì„±í•˜ê² ìŠµë‹ˆê¹Œ?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">ë‹¹ì‹ ì˜ íŠ¸ëžœìž­ì…˜ì„ ê²€í† í•˜ì„¸ìš”. ë‹¹ì‹ ì€ íŠ¸ëžœìž­ì…˜ì„ ìƒì„±í•˜ê³  보낼 수 있습니다. í˜¹ì€ ë¶€ë¶„ì ìœ¼ë¡œ ì„œëª…ëœ ë¹„íŠ¸ì½”ì¸ íŠ¸ëžœìž­ì…˜ (PSBT, Partially Signed Bitcoin Transaction)ì„ ìƒì„±í•˜ê³ , 저장하거나 복사하여 오프ë¼ì¸ %1지갑으로 ì„œëª…í• ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. PSBTê°€ ì ìš©ë˜ëŠ” 하드월렛으로 서명할 ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. </translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">거래를 재검토 하십시오</translation>
@@ -3330,14 +3628,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">%1 보다 í° ìˆ˜ìˆ˜ë£ŒëŠ” 지나치게 ë†’ì€ ìˆ˜ìˆ˜ë£Œ 입니다.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">지불 ìš”ì²­ì´ ë§Œë£Œë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n블ë¡ë‚´ë¡œ ì»¨íŽŒì´ ì‹œìž‘ë  ê²ƒìœ¼ë¡œ 예ìƒë©ë‹ˆë‹¤.</numerusform>
</translation>
</message>
<message>
@@ -3412,14 +3706,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">메시지:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">ì¸ì¦ ë˜ì§€ ì•Šì€ ì§€ë¶ˆ 요청입니다.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">ì¸ì¦ ëœ ì§€ë¶ˆ 요청 입니다.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">ì´ ì£¼ì†Œì— ë¼ë²¨ì„ 입력하면 ì‚¬ìš©ëœ ì£¼ì†Œ 목ë¡ì— ë¼ë²¨ì´ 표시ë©ë‹ˆë‹¤</translation>
</message>
@@ -3427,14 +3713,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<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 type="unfinished">bitcoin: URIì— ì¶”ê°€ëœ ë©”ì‹œì§€ëŠ” 참고를 위해 거래내역과 함께 ì €ìž¥ë  ê²ƒìž…ë‹ˆë‹¤. Note: ì´ ë©”ì‹œì§€ëŠ” ë¹„íŠ¸ì½”ì¸ ë„¤íŠ¸ì›Œí¬ë¡œ 전송ë˜ì§€ 않습니다.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">보낼 주소:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">메모:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3591,33 +3869,36 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
</context>
<context>
- <name>TransactionDesc</name>
- <message>
- <source>conflicted with a transaction with %1 confirmations</source>
- <translation type="unfinished">%1 승ì¸ì´ 있는 거래와 충ëŒí•¨</translation>
- </message>
+ <name>SplashScreen</name>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/미승ì¸, %1</translation>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished">q 를 눌러 종료하거나 ë‚˜ì¤‘ì— ê³„ì†í•˜ì„¸ìš”.</translation>
</message>
<message>
- <source>in memory pool</source>
- <translation type="unfinished">메모리 í’€ ì•ˆì— ìžˆìŒ</translation>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">q를 눌러 종료하세요</translation>
</message>
+</context>
+<context>
+ <name>TransactionDesc</name>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">메모리 í’€ ì•ˆì— ì—†ìŒ</translation>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
+ <translation type="unfinished">%1 승ì¸ì´ 있는 거래와 충ëŒí•¨</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">버려진</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/미확ì¸</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 í™•ì¸ ì™„ë£Œ</translation>
</message>
<message>
@@ -3667,7 +3948,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nê°œ ì´ìƒ ë¸”ë¡ ì´ë‚´ì— 완료ë©ë‹ˆë‹¤.</numerusform>
</translation>
</message>
<message>
@@ -3940,10 +4221,35 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">복사 트랜잭션 &amp; ì•„ì´ë””</translation>
</message>
<message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">처리ë˜ì§€ ì•Šì€ íŠ¸ëžœìž­ì…˜ 복사</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">트랜잭션 전체와 ìƒì„¸ë‚´ì—­ 복사</translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">트랜잭션 ìƒì„¸ë‚´ì—­ 보여주기</translation>
+ </message>
+ <message>
+ <source>Increase transaction &amp;fee</source>
+ <translation type="unfinished">트랜잭션 수수료 올리기</translation>
+ </message>
+ <message>
+ <source>A&amp;bandon transaction</source>
+ <translation type="unfinished">트랜잭션 í기하기</translation>
+ </message>
+ <message>
<source>&amp;Edit address label</source>
<translation type="unfinished">&amp;주소 ë¼ë²¨ 수정하기</translation>
</message>
<message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">%1내로 보여주기</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">거래 ê¸°ë¡ ë‚´ë³´ë‚´ê¸°</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ku.ts b/src/qt/locale/bitcoin_ku.ts
new file mode 100644
index 0000000000..b41ab41d6a
--- /dev/null
+++ b/src/qt/locale/bitcoin_ku.ts
@@ -0,0 +1,357 @@
+<TS version="2.1" language="ku">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>&amp;New</source>
+ <translation type="unfinished">&amp;Nû</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation type="unfinished">&amp;Kopi bike</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation type="unfinished">Bigire</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">Navnîşana hilbijartî ji lîsteyê rake</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">Ji bo lêgerînê navnîşan an jî etîketê têkeve</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Daneya di hilpekîna niha de bi rêya dosyayekê derxîne</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">Derxîne</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation type="unfinished">Jê bibe</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">Navnîşana ku ew ê koîn were şandin, hilbijêre</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">Navnîşana ku ew ê koînan bistîne, hilbijêre</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation type="unfinished">H&amp;ilbijêre</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation type="unfinished">Navnîşanên şandinê</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation type="unfinished">Navnîşanên stendinê</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished">&amp;Navnîşanê kopî bike</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">Etîketê &amp;kopî bike</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;Serrast bike</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">Lîsteya navnîşanan derxîne</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Etîket</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">Navnîşan</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(etîket tune)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Enter passphrase</source>
+ <translation type="unfinished">Pêborîna xwe têkevê</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation type="unfinished">Pêborîna nû</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation type="unfinished">Pêborîna xwe ya nû dubare bike</translation>
+ </message>
+ <message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">Pêborînê nîşan bide</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">Şîfrekirina cizdên</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation type="unfinished">Kilîda cizdên veke</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation type="unfinished">Pêborînê biguherîne</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation type="unfinished">Şîfrekirina cizdên bipejirîne</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished">Tu bi rastî jî dixwazî cizdanê xwe şîfre bikî?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished">Cizdan hate şîfrekirin</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject</name>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Cizdan:</translation>
+ </message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation type="unfinished">Agahî</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Tarîx</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(etîket tune)</translation>
+ </message>
+ </context>
+<context>
+ <name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(sufficient to restore backups %n day(s) old)</source>
+ <extracomment>Explanatory text on the capability of the current prune target.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ <message>
+ <source>Address</source>
+ <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
+ <translation type="unfinished">Navnîşan</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment>
+ <translation type="unfinished">Cure</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Cizdan:</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Tarîx</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Etîket</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(etîket tune)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(etîket tune)</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Tarîx</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Tarîx</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation type="unfinished">Cure</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Etîket</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(etîket tune)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Tarîx</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation type="unfinished">Cure</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Etîket</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">Navnîşan</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">Derxîne</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Daneya di hilpekîna niha de bi rêya dosyayekê derxîne</translation>
+ </message>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_ku_IQ.ts b/src/qt/locale/bitcoin_ku_IQ.ts
index f78a465fbe..aebd62b774 100644
--- a/src/qt/locale/bitcoin_ku_IQ.ts
+++ b/src/qt/locale/bitcoin_ku_IQ.ts
@@ -137,6 +137,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">دووبارەکردنەوەی دەستەواژەی تێپەڕی نوێ</translation>
</message>
<message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">نیشان دانا ناوه چونه</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">کی٠خو یه پاره رمزه دانینه بر</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation type="unfinished">او شوله بو ور کرنا کی٠پاره گرکه رمزا Ú©ÛŒÙÙ‡ وؤ یه پاره بزانی</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished">به راستی اون هشیارن کا دخازن بو کی٠خو یه پاره رمزه دانین</translation>
+ </message>
+ <message>
<source>Enter the new passphrase for 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 type="unfinished">دەستەواژەی تێپەڕەوی نوێ تێبنووسە بۆ جزدان.1 تکایە دەستەواژەی تێپەڕێک بەکاربێنە لە 2ten یان زیاتر لە هێما هەڕەمەکیەکان2، یان 38 یان زیاتر ووشەکان3.</translation>
</message>
@@ -240,6 +256,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinGUI</name>
<message>
+ <source>&amp;About %1</source>
+ <translation type="unfinished">&amp;دەربارەی %1</translation>
+ </message>
+ <message>
<source>&amp;Send</source>
<translation type="unfinished">&amp;ناردن</translation>
</message>
@@ -348,6 +368,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -368,10 +409,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">بەخێربێن</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 type="unfinished">کاتێک کرتە لە پەسەندە دەکەیت، %1 دەست دەکات بە داگرتن و پرۆسەی زنجیرەبلۆکی %4 (%2GB) بە سەرەتاییترین مامەڵەکان لە %3 دەست پێدەکات کاتێک %4 لە سەرەتادا دەستی پێکرد.</translation>
- </message>
- <message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">دووبارە کردنەوەی ئەم ڕێکخستنە پێویستی بە دووبارە داگرتنی تەواوی بەربەستەکە هەیە. خێراترە بۆ داگرتنی زنجیرەی تەواو سەرەتا و داگرتنی دواتر. هەندێک تایبەتمەندی پێشکەوتوو لە کار دەهێنێت.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ky.ts b/src/qt/locale/bitcoin_ky.ts
index db2ee8975c..80320eccb0 100644
--- a/src/qt/locale/bitcoin_ky.ts
+++ b/src/qt/locale/bitcoin_ky.ts
@@ -144,6 +144,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts
index b595e3e706..49b7d4c1e2 100644
--- a/src/qt/locale/bitcoin_la.ts
+++ b/src/qt/locale/bitcoin_la.ts
@@ -521,6 +521,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -647,6 +668,7 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirma optionum reconstituere</translation>
</message>
<message>
@@ -933,10 +955,6 @@
<source>Message:</source>
<translation type="unfinished">Nuntius:</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Pensa Ad:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -1053,10 +1071,12 @@
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/non confirmata</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 confirmationes</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts
index 6d1d346a38..255a84f2b6 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 type="unfinished">Spustelėkite dešinįjį klavišą norint keisti adresą arba etiketę</translation>
+ <translation type="unfinished">Spustelėkite dešinįjį pelės klavišą norint keisti adresą arba etiketę </translation>
</message>
<message>
<source>Create a new address</source>
@@ -70,6 +70,12 @@
<translation type="unfinished">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. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Tai jūsų Bitcoin mokėjimų gavimo adresai. Naudokite 'Sukurti naują gavimo adresą' mygtuką gavimų skirtuke kad sukurtumėte naujus adresus.
+Pasirašymas galimas tik su 'legacy' tipo adresais.</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">&amp;Kopijuoti adresÄ…</translation>
</message>
@@ -86,6 +92,11 @@
<translation type="unfinished">Eksportuoti adresų sąrašą</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Kableliais atskirtas failas</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">Bandant išsaugoti adresų sąrašą - įvyko klaida keliant į %1. Prašome bandyti dar kartą.</translation>
@@ -190,7 +201,7 @@
</message>
<message>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
- <translation type="unfinished">Dėl vidinės klaidos nepavyko užšifruoti piniginę.Piniginė neužšifruota.</translation>
+ <translation type="unfinished">Dėl vidinės klaidos nepavyko užšifruoti piniginę. Piniginė neužšifruota.</translation>
</message>
<message>
<source>The supplied passphrases do not match.</source>
@@ -227,6 +238,10 @@
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Nustatymų failas %1 galimai sugadintas arba klaidingas</translation>
+ </message>
+ <message>
<source>Internal error</source>
<translation type="unfinished">VidinÄ— klaida</translation>
</message>
@@ -246,6 +261,10 @@
<translation type="unfinished">Klaida: %1</translation>
</message>
<message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 dar saugiai neužbaigė darbo...</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">nežinomas</translation>
</message>
@@ -340,6 +359,14 @@
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Nustatymų failas negalėjo būti perskaitytas</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Nustatymų failas negalėjo būti parašytas</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">%s kūrėjai</translation>
</message>
@@ -476,10 +503,6 @@
<translation type="unfinished">Nežinomas adreso tipas '%s'</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">UTXO duomenų bazės atnaujinimas</translation>
- </message>
- <message>
<source>Verifying blocks…</source>
<translation type="unfinished">Tikrinami blokai...</translation>
</message>
@@ -539,6 +562,10 @@
<translation type="unfinished">Sukurti naujÄ… piniginÄ™</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Sumažinti</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">PiniginÄ—</translation>
</message>
@@ -572,6 +599,10 @@
<translation type="unfinished">&amp;Gauti</translation>
</message>
<message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Nustatymai</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">Užšifruoti privaÄius raktus, kurie priklauso jÅ«sų piniginei</translation>
</message>
@@ -700,6 +731,11 @@
<translation type="unfinished">Piniginių nėra</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">PiniginÄ—s Pavadinimas</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Langas</translation>
</message>
@@ -1129,6 +1165,30 @@
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(reikalinga %n GB)</numerusform>
+ <numerusform>(reikalinga %n GB)</numerusform>
+ <numerusform>(reikalinga %n GB)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Šiame kataloge bus saugomi bent %1 GB duomenų, kurie laikui bėgant didės.</translation>
@@ -1175,10 +1235,6 @@
<translation type="unfinished">Kadangi tai yra pirmas kartas, kai programa paleidžiama, galite pasirinkti, kur %1 išsaugos savo duomenis.</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 type="unfinished">Spustelėjus Gerai, %1 pradės atsisiųsti ir apdoroti visą %4 blokų grandinę (%2GB), pradedant nuo ankstesnių operacijų %3, kai iš pradžių buvo paleista %4.</translation>
- </message>
- <message>
<source> GB</source>
<translation type="unfinished">GB</translation>
</message>
@@ -1447,10 +1503,6 @@
<translation type="unfinished">Rodyti monetų valdymo funkcijas, ar ne.</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Šiame dialogo lange nustatytos parinktys yra panaikintos komandų eilutėje arba konfigūracijos faile:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">&amp;Gerai</translation>
</message>
@@ -1468,14 +1520,17 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Patvirtinti nustatymų atstatymą</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Kliento perkrovimas reikalingas nustatymų aktyvavimui</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Klientas bus uždarytas. Ar norite testi?</translation>
</message>
<message>
@@ -2333,10 +2388,6 @@
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Mokestis, didesnis nei %1, laikomas absurdiÅ¡kai aukÅ¡tu mokesÄiu.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Mokėjimo prašymas pasibaigė</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2413,14 +2464,6 @@
<translation type="unfinished">Žinutė:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Tai yra nepatvirtinta mokėjimo užklausos suma</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Tai yra patvirtintas mokėjimo prašymas.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Įveskite šio adreso etiketę, kad ją pridėtumėte prie naudojamų adresų sąrašo</translation>
</message>
@@ -2428,14 +2471,6 @@
<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 type="unfinished">Pranešimas, kuris buvo pridėtas prie bitcoin: URI, kuris bus saugomas kartu su sandoriu jūsų nuoroda. Pastaba: šis pranešimas nebus išsiųstas per „Bitcoin“ tinklą.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">MokÄ—ti gavÄ—jui:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">AtmintinÄ—:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -2571,30 +2606,22 @@
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">prieštaravo sandoriui su %1 patvirtinimais</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/nepatvirtintas, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">atminties talpykloje</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">ne atminties talpykloje</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">paliktas</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/nepatvirtintas</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 patvirtinimų</translation>
</message>
<message>
@@ -2883,6 +2910,11 @@
<translation type="unfinished">Eksportuoti sandorių istoriją</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Kableliais atskirtas failas</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">Patvirtinta</translation>
</message>
diff --git a/src/qt/locale/bitcoin_lv.ts b/src/qt/locale/bitcoin_lv.ts
index 972fa659f8..9497005299 100644
--- a/src/qt/locale/bitcoin_lv.ts
+++ b/src/qt/locale/bitcoin_lv.ts
@@ -88,7 +88,7 @@
<message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
- <translation type="unfinished">MÄ“Ä£inot saglabÄt adreÅ¡u sarakstu %1 radÄs kļūda. MÄ“Ä£iniet vÄ“lreiz.</translation>
+ <translation type="unfinished">MÄ“Ä£inot saglabÄt adreÅ¡u sarakstu %1 radÄs kļūda. LÅ«dzu mÄ“Ä£iniet vÄ“lreiz.</translation>
</message>
<message>
<source>Exporting Failed</source>
@@ -126,7 +126,7 @@
</message>
<message>
<source>Repeat new passphrase</source>
- <translation type="unfinished">JaunÄ parole vÄ“lreiz</translation>
+ <translation type="unfinished">Ievadiet jauno paroli vēlreiz</translation>
</message>
<message>
<source>Show passphrase</source>
@@ -185,10 +185,18 @@
<translation type="unfinished">Maciņa Å¡ifrÄ“Å¡ana neizdevÄs</translation>
</message>
<message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">IevadÄ«tÄs paroles nav vienÄdas.</translation>
+ </message>
+ <message>
<source>Wallet unlock failed</source>
<translation type="unfinished">Maciņa atslÄ“gÅ¡ana neizdevÄs</translation>
</message>
- </context>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished">Uzmanību! Caps Lock uz klavietūras ir ieslēgts!</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -318,6 +326,10 @@
<translation type="unfinished">&amp;Par %1</translation>
</message>
<message>
+ <source>Show information about %1</source>
+ <translation type="unfinished">RÄdÄ«t informÄciju par %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation type="unfinished">Par &amp;Qt</translation>
</message>
@@ -326,6 +338,10 @@
<translation type="unfinished">ParÄdÄ«t informÄciju par Qt</translation>
</message>
<message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Izveidot jaunu maciņu</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Maciņš:</translation>
</message>
@@ -350,6 +366,10 @@
<translation type="unfinished">&amp;Saņemt</translation>
</message>
<message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Opcijas...</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">Å ifrÄ“t privÄtÄs atslÄ“gas kuras pieder tavam maciņam</translation>
</message>
@@ -378,6 +398,10 @@
<translation type="unfinished">Ciļņu rīkjosla</translation>
</message>
<message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Sinhronizē ar tīklu</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">PieprasÄ«t maksÄjumus (izveido QR kodu un bitcoin: URIs)</translation>
</message>
@@ -550,6 +574,30 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -740,9 +788,15 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">ApstiprinÄt iestatÄ«jumu atiestatÄ«Å¡anu</translation>
</message>
<message>
+ <source>Configuration options</source>
+ <extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
+ <translation type="unfinished">KonfigurÄciju Opcijas</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">Kļūda</translation>
</message>
@@ -789,6 +843,33 @@
<source>Your current total balance</source>
<translation type="unfinished">JÅ«su kopÄ“jÄ tekoÅ¡Ä bilance</translation>
</message>
+ <message>
+ <source>Spendable:</source>
+ <translation type="unfinished">Iztērējams:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation type="unfinished">NesenÄs transakcijas</translation>
+ </message>
+ </context>
+<context>
+ <name>PSBTOperationsDialog</name>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished">Dialogs</translation>
+ </message>
+ <message>
+ <source>Copy to Clipboard</source>
+ <translation type="unfinished">Nokopēt</translation>
+ </message>
+ <message>
+ <source>Save…</source>
+ <translation type="unfinished">SaglabÄt...</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished">Aiztaisīt</translation>
+ </message>
</context>
<context>
<name>PeerTableModel</name>
@@ -1084,10 +1165,6 @@
<source>Message:</source>
<translation type="unfinished">Ziņojums:</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">MaksÄt:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -1223,6 +1300,10 @@
<context>
<name>WalletFrame</name>
<message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Izveidot jaunu maciņu</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">Kļūda</translation>
</message>
diff --git a/src/qt/locale/bitcoin_mk.ts b/src/qt/locale/bitcoin_mk.ts
index 9c428ee03a..8558fe17ba 100644
--- a/src/qt/locale/bitcoin_mk.ts
+++ b/src/qt/locale/bitcoin_mk.ts
@@ -341,6 +341,30 @@
<translation type="unfinished">Биткоин</translation>
</message>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_ml.ts b/src/qt/locale/bitcoin_ml.ts
index c0294c8a08..16456cfc86 100644
--- a/src/qt/locale/bitcoin_ml.ts
+++ b/src/qt/locale/bitcoin_ml.ts
@@ -317,10 +317,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ഡാറàµà´±à´¾à´¬àµ‡à´¸à´¿àµ½ നിനàµà´¨àµà´‚ വായിചàµà´šàµ†à´Ÿàµà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ തടസം നേരിടàµà´Ÿàµ, à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´‚ അവസാനിപàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">ചെയിൻസàµà´±àµà´±àµ‡à´±àµà´±àµ ഡാറàµà´±à´¾à´¬àµ‡à´¸àµ à´…à´ªàµà´—àµà´°àµ‡à´¡àµ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ തടസം നേരിടàµà´Ÿàµ</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Error: %s ൽ à´¡à´¿à´¸àµà´•àµ à´¸àµà´ªàµ‡à´¸àµ വളരെ à´•àµà´±à´µà´¾à´£àµ</translation>
</message>
@@ -624,6 +620,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">വാലറàµà´±àµ à´’à´¨àµà´¨àµà´‚ ലഭàµà´¯à´‚ à´…à´²àµà´² </translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">വാലറàµà´±àµ പേരàµ</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;ജാലകം </translation>
</message>
@@ -986,6 +987,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ബിറàµà´±àµà´•àµ‹à´¯à´¿àµ»</translation>
</message>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -1234,10 +1256,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Copy change</source>
<translation type="unfinished">ചേഞàµà´šàµ പകർതàµà´¤àµ</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">പെയàµà´®àµ†à´¨àµà´±à´¿à´¨àµà´³àµà´³ à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ പോയിരികàµà´•àµà´¨àµà´¨àµ. </translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -1272,6 +1290,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>TransactionDesc</name>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 à´¸àµà´¥à´¿à´°àµ€à´•à´°à´£à´™àµà´™àµ¾</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_mn.ts b/src/qt/locale/bitcoin_mn.ts
index ae0831c418..d74acfb083 100644
--- a/src/qt/locale/bitcoin_mn.ts
+++ b/src/qt/locale/bitcoin_mn.ts
@@ -81,7 +81,11 @@
<source>Export Address List</source>
<translation type="unfinished">ЭкÑпорт хийх хаÑгуудын жагÑаалт</translation>
</message>
- </context>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">ЭкÑпорт амжилтгүй боллоо</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
<message>
@@ -161,6 +165,13 @@
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">Дотоод алдаа</translation>
+ </message>
+ </context>
+<context>
<name>QObject</name>
<message>
<source>Error: %1</source>
@@ -259,10 +270,19 @@
<translation type="unfinished">Клиентийн тухай мÑдÑÑллийг харуул</translation>
</message>
<message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Ð¨Ð¸Ð½Ñ Ñ‚Ò¯Ñ€Ð¸Ð¹Ð²Ñ‡ Ò¯Ò¯ÑгÑÑ…</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Ð¥ÑÑ‚Ñвч:</translation>
</message>
<message>
+ <source>Network activity disabled.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">СүлжÑÑний үйл ажиллагааг идÑвхгүй болгоÑон.</translation>
+ </message>
+ <message>
<source>Change the passphrase used for wallet encryption</source>
<translation type="unfinished">Түрүйвчийг цоожлох нууц үгийг Ñолих</translation>
</message>
@@ -335,6 +355,46 @@
<translation type="unfinished">Ðлдаа: %1</translation>
</message>
<message>
+ <source>Warning: %1</source>
+ <translation type="unfinished">Ðнхааруулга:%1</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation type="unfinished">Огноо%1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation type="unfinished">Дүн: %1
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation type="unfinished">Түрийвч: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation type="unfinished">Төрөл: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation type="unfinished">Шошго: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation type="unfinished">ХаÑг: %1
+</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation type="unfinished">Гадагшаа гүйлгÑÑ</translation>
</message>
@@ -350,7 +410,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation type="unfinished">Түрүйвч &lt;b&gt;цоожтой&lt;/b&gt; ба одоогоор цоож &lt;b&gt;хаалттай&lt;/b&gt; байна</translation>
</message>
- </context>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">Эх зурваÑ:</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -439,6 +503,27 @@
<translation type="unfinished">Биткойн</translation>
</message>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -500,6 +585,7 @@
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Ѳѳрчлѳлтүүдийг идÑвхижүүлхийн тулд клиентийг ахин ÑхлүүлÑÑ… шаардлагтай</translation>
</message>
<message>
@@ -779,10 +865,6 @@
<source>Message:</source>
<translation type="unfinished">ЗурваÑ:</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Тѳлѳх хаÑг:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -799,10 +881,12 @@
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/баталгаажаагүй</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 баталгаажилтууд</translation>
</message>
<message>
@@ -990,6 +1074,10 @@
<translation type="unfinished">Тодорхойлолт</translation>
</message>
<message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">ЭкÑпорт амжилтгүй боллоо</translation>
+ </message>
+ <message>
<source>The transaction history was successfully saved to %1.</source>
<translation type="unfinished">ГүйлгÑÑнүй түүхийг %1-д амжилттай хадгаллаа.</translation>
</message>
@@ -1001,6 +1089,10 @@
<context>
<name>WalletFrame</name>
<message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Ð¨Ð¸Ð½Ñ Ñ‚Ò¯Ñ€Ð¸Ð¹Ð²Ñ‡ Ò¯Ò¯ÑгÑÑ…</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">Ðлдаа</translation>
</message>
diff --git a/src/qt/locale/bitcoin_mr_IN.ts b/src/qt/locale/bitcoin_mr_IN.ts
index d06e977f93..2ab2f65628 100644
--- a/src/qt/locale/bitcoin_mr_IN.ts
+++ b/src/qt/locale/bitcoin_mr_IN.ts
@@ -86,6 +86,11 @@
<translation type="unfinished">पतà¥à¤¤à¥à¤¯à¤¾à¤šà¥€ निरà¥à¤¯à¤¾à¤¤ करा</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">कॉमा सेपरेटेड फ़ाइल</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation type="unfinished">निरà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€</translation>
</message>
@@ -106,7 +111,22 @@
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">à¤à¤• गंभीर तà¥à¤°à¥à¤Ÿà¥€ आली. %1यापà¥à¤¢à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤ªà¤£à¥‡ सà¥à¤°à¥‚ ठेवू शकत नाही आणि संपेल.</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">अंतरà¥à¤—त तà¥à¤°à¥à¤Ÿà¥€</translation>
+ </message>
+ </context>
+<context>
<name>QObject</name>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1अजून सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤ªà¤£à¥‡ बाहेर पडलो नाही...</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
@@ -151,7 +171,79 @@
</message>
</context>
<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">सेटिंगà¥à¤œ फाइल वाचता आली नाही</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">सेटिंगà¥à¤œ फाइल लिहिता आली नाही</translation>
+ </message>
+ </context>
+<context>
<name>BitcoinGUI</name>
+ <message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;मिनीमाइज़</translation>
+ </message>
+ <message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;परà¥à¤¯à¤¾à¤¯</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;à¤à¤¨à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ वॉलेट</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;बॅकअप वॉलेट…
+ </translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;पासफà¥à¤°à¥‡à¤œ बदला...</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€ आणि संदेश...</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;संदेश सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤ करा...</translation>
+ </message>
+ <message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">फाइलमधून PSBT &amp;लोड करा...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">वॉलेट बंद करा...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">वॉलेट तयार करा...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">सरà¥à¤µ वॉलेट बंद करा...</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">शीरà¥à¤·à¤²à¥‡à¤– समकà¥à¤°à¤®à¤¿à¤¤ करत आहे (%1%)…</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">नेटवरà¥à¤•à¤¸à¤¹ सिंकà¥à¤°à¥‹à¤¨à¤¾à¤‡à¤ करत आहे...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">डिसà¥à¤•à¤µà¤° बà¥à¤²à¥‰à¤• अनà¥à¤•à¥à¤°à¤®à¤¿à¤¤ करत आहे...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">डिसà¥à¤•à¤µà¤° बà¥à¤²à¥‰à¤•à¥à¤¸à¤µà¤° पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ करत आहे...</translation>
+ </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
@@ -178,6 +270,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -243,6 +356,11 @@
<context>
<name>TransactionView</name>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">कॉमा सेपरेटेड फ़ाइल</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">लेबल</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ms.ts b/src/qt/locale/bitcoin_ms.ts
index 7ed9148806..e55ad6f43e 100644
--- a/src/qt/locale/bitcoin_ms.ts
+++ b/src/qt/locale/bitcoin_ms.ts
@@ -445,6 +445,24 @@ Alihkan fail data ke dalam tab semasa</translation>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(of %n GB needed)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_my.ts b/src/qt/locale/bitcoin_my.ts
index 7418bf8aeb..54711d381f 100644
--- a/src/qt/locale/bitcoin_my.ts
+++ b/src/qt/locale/bitcoin_my.ts
@@ -66,6 +66,10 @@
<translation type="unfinished">လိပ်စာလက်á€á€¶á€›á€›á€¾á€­á€žá€Šá€º</translation>
</message>
<message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;ပြင်ဆင်</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation type="unfinished">á€á€„်ပို့မှုမအောင်မြင်ပါ</translation>
</message>
@@ -83,6 +87,10 @@
</context>
<context>
<name>QObject</name>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">အမှား-%1</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
@@ -155,6 +163,10 @@
<numerusform />
</translation>
</message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">အမှား-%1</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -174,6 +186,24 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts
index ab2f00860e..40e813fb07 100644
--- a/src/qt/locale/bitcoin_nb.ts
+++ b/src/qt/locale/bitcoin_nb.ts
@@ -269,6 +269,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Vil du tilbakestille innstillingene til utgangsverdiene, eller vil du avbryte uten å gjøre endringer?</translation>
</message>
<message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">En fatal feil har oppstått. Sjekk at filen med innstillinger er skrivbar eller prøv å kjøre med -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Feil: Den spesifiserte datamappen "%1" finnes ikke.</translation>
</message>
@@ -321,6 +326,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Blokkrelé</translation>
</message>
<message>
+ <source>Manual</source>
+ <extracomment>Peer connection type established manually through one of several methods.</extracomment>
+ <translation type="unfinished">HÃ¥ndbok</translation>
+ </message>
+ <message>
<source>Feeler</source>
<extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment>
<translation type="unfinished">Føler</translation>
@@ -345,36 +355,36 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n sekund</numerusform>
+ <numerusform>%n sekunder</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minutt</numerusform>
+ <numerusform>%n minutter</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n time</numerusform>
+ <numerusform>%n timer</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n dag</numerusform>
+ <numerusform>%n dager</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n uke</numerusform>
+ <numerusform>%n uker</numerusform>
</translation>
</message>
<message>
@@ -384,8 +394,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n år</numerusform>
+ <numerusform>%n år</numerusform>
</translation>
</message>
</context>
@@ -444,10 +454,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Feil: Dumpfil versjon er ikke støttet. Denne versjonen av bitcoin-lommebok støtter kun versjon 1 dumpfiler. Fikk dumpfil med versjon %s</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Feil: Lytting etter innkommende tilkoblinger feilet (lytting returnerte feil %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Avgiftsberegning mislyktes. Fallbackfee er deaktivert. Vent et par blokker eller aktiver -fallbackfee.</translation>
</message>
@@ -552,6 +558,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kan ikke sette -peerblockfilters uten -blockfilterindex</translation>
</message>
<message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Kunne ikke gjenopprette sikkerhetskopi av lommebok.</translation>
+ </message>
+ <message>
<source>Copyright (C) %i-%i</source>
<translation type="unfinished">Kopirett © %i-%i</translation>
</message>
@@ -624,10 +636,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Feil ved lesing av neste oppføring fra lommebokdatabase</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Feil ved oppgradering av kjedetilstandsdatabase</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Feil: Ikke nok ledig diskplass for %s</translation>
</message>
@@ -656,6 +664,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Feil: Ingen %s adresser tilgjengelige.</translation>
</message>
<message>
+ <source>Error: Unable to write record to new wallet</source>
+ <translation type="unfinished">Feil: Kan ikke skrive rekord til ny lommebok</translation>
+ </message>
+ <message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation type="unfinished">Kunne ikke lytte på noen port. Bruk -listen=0 hvis det er dette du vil.</translation>
</message>
@@ -688,6 +700,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Sunnhetssjekk ved oppstart mislyktes. %s skrus av.</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Finner ikke data eller er allerede brukt</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">Utilstrekkelige midler</translation>
</message>
@@ -736,12 +752,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Laster lommebok...</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Mangler beløp</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">MÃ¥ oppgi en port med -whitebind: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Ingen proxyserver er spesifisert. Bruk -proxy=&lt;ip&gt; eller -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Ingen adresser tilgjengelig</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -752,10 +772,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Beskjæringsmodus kan ikke konfigureres med en negativ verdi.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Beskjæringsmodus er inkompatibel med -coinstatsindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">Beskjæringsmodus er inkompatibel med -txindex.</translation>
</message>
@@ -768,6 +784,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Reduserer -maxconnections fra %d til %d, pga. systembegrensninger.</translation>
</message>
<message>
+ <source>Replaying blocks…</source>
+ <translation type="unfinished">Spiller av blokker på nytt …</translation>
+ </message>
+ <message>
<source>Rescanning…</source>
<translation type="unfinished">Leser gjennom igjen...</translation>
</message>
@@ -892,10 +912,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ustøttet loggingskategori %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Oppgraderer UTXO-database</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">User Agent kommentar (%s) inneholder utrygge tegn.</translation>
</message>
@@ -1187,6 +1203,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Lukk lommebok</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Gjenopprett lommebok...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Gjenopprett en lommebok fra en sikkerhetskopi</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Lukk alle lommebøker</translation>
</message>
@@ -1211,6 +1237,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ingen lommebøker tilgjengelig</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Lommebokdata</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Last lommebok sikkerhetskopi</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Gjenopprett lommebok</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Lommeboknavn</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Vindu</translation>
</message>
@@ -1226,8 +1272,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform> %n aktiv tilkobling til Bitcoin-nettverket.</numerusform>
+ <numerusform>%n aktive tilkoblinger til Bitcoin-nettverket.</numerusform>
</translation>
</message>
<message>
@@ -1251,6 +1297,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Klikk for å aktivere nettverksaktivitet.</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Synkroniserer blokkhoder (%1%)...</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Feil: %1</translation>
</message>
@@ -1499,7 +1549,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">Kan ikke vise liste over undertegnere</translation>
</message>
-</context>
+ </context>
<context>
<name>LoadWalletsActivity</name>
<message>
@@ -1539,6 +1589,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Gjenopprett lommebok</translation>
+ </message>
+ </context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1709,13 +1767,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(av %1 GB som trengs)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB kreves for hele kjeden)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(av %n GB som trengs)</numerusform>
+ <numerusform>(av %n GB som trengs)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB kreves for hele kjeden)</numerusform>
+ <numerusform>(%n GB kreves for hele kjeden)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1729,8 +1800,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(Tilstrekkelig å gjenopprette backuper som er %n dag gammel) </numerusform>
+ <numerusform>(Tilstrekkelig å gjenopprette backuper som er %n dager gamle) </numerusform>
</translation>
</message>
<message>
@@ -1762,10 +1833,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Siden dette er første gang programmet starter, kan du nå velge hvor %1 skal lagre sine data.</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 type="unfinished">Når du klikker OK, vil %1 starte nedlasting og behandle hele den %4 blokkjeden (%2GB) fra de eldste transaksjonene i %3 når %4 først startet.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Begrens blokkjedelagring til</translation>
</message>
@@ -1870,7 +1937,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
<translation type="unfinished">%1 synkroniseres for øyeblikket. Den vil laste ned blokkhoder og blokker fra likemenn og validere dem til de når enden av blokkjeden.</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Ukjent.Synkroniser blokkhoder (%1,%2%)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -1922,6 +1993,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Minimer i stedet for å avslutte applikasjonen når vinduet lukkes. Når dette er valgt, vil applikasjonen avsluttes kun etter at Avslutte er valgt i menyen.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Alternativer som er satt i denne dialogboksen overstyres av kommandolinjen:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Ã…pne %1-oppsettsfila fra arbeidsmappen.</translation>
</message>
@@ -2082,10 +2157,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">nærmeste treff "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Alternativer som er satt i denne dialogboksen overstyres av kommandolinjen eller i konfigurasjonsfilen:</translation>
- </message>
- <message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Avbryt</translation>
</message>
@@ -2104,14 +2175,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Bekreft tilbakestilling av innstillinger</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Omstart av klienten er nødvendig for å aktivere endringene.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Klienten vil bli lukket. Ønsker du å gå videre?</translation>
</message>
<message>
@@ -2332,6 +2406,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transaksjonen trenger signatur(er).</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Men ingen lommebok er lastet.)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Men denne lommeboken kan ikke signere transaksjoner.)</translation>
</message>
@@ -2401,6 +2479,11 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<translation type="unfinished">Likemann</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Alder</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Retning</translation>
@@ -2571,6 +2654,10 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<translation type="unfinished">Synkroniserte Blokker</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Siste transaksjon</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">Det kartlagte Autonome Systemet som brukes til å diversifisere valg av likemenn.</translation>
</message>
@@ -2579,6 +2666,11 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<translation type="unfinished">Kartlagt AS</translation>
</message>
<message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Adresser Prosessert</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">Brukeragent</translation>
</message>
@@ -3249,6 +3341,11 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<translation type="unfinished">Se over ditt transaksjonsforslag. Dette kommer til å produsere en Delvis Signert Bitcoin Transaksjon (PSBT) som du kan lagre eller kopiere og så signere med f.eks. en offline %1 lommebok, eller en PSBT kompatibel hardware lommebok.</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Vil du lage denne transaksjonen?</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Vennligst se over transaksjonen din.</translation>
@@ -3301,10 +3398,6 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Et gebyr høyere enn %1 anses som absurd høyt.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Tidsavbrudd for betalingsforespørsel</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -3384,14 +3477,6 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<translation type="unfinished">Melding:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Dette er en uautorisert betalingsetterspørring.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Dette er en autorisert betalingsetterspørring.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Skriv inn en merkelapp for denne adressen for å legge den til listen av brukte adresser</translation>
</message>
@@ -3399,11 +3484,7 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<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 type="unfinished">En melding som var tilknyttet bitcoinen: URI vil bli lagret med transaksjonen for din oversikt. Denne meldingen vil ikke bli sendt over Bitcoin-nettverket.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Betal Til:</translation>
- </message>
- </context>
+</context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -3560,35 +3641,31 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<source>(press q to shutdown and continue later)</source>
<translation type="unfinished">(trykk q for å skru av og fortsette senere)</translation>
</message>
- </context>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">trykk på q for å slå av</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">gikk ikke overens med en transaksjon med %1 bekreftelser</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/ubekreftet, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">i minnepool</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">ikke i minnepool</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">forlatt</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/ubekreftet</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 bekreftelser</translation>
</message>
<message>
@@ -3634,8 +3711,8 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>modner om %n blokk</numerusform>
+ <numerusform>modner om %n blokker</numerusform>
</translation>
</message>
<message>
@@ -4072,7 +4149,7 @@ Gå til Fil &gt; Åpne lommebok for å laste en lommebok.
<name>WalletView</name>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">&amp;Eksporter</translation>
+ <translation type="unfinished">&amp;Eksport</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
diff --git a/src/qt/locale/bitcoin_ne.ts b/src/qt/locale/bitcoin_ne.ts
index a9b0e65e42..e3ca99b20f 100644
--- a/src/qt/locale/bitcoin_ne.ts
+++ b/src/qt/locale/bitcoin_ne.ts
@@ -23,13 +23,17 @@
</message>
<message>
<source>C&amp;lose</source>
- <translation type="unfinished">बनà¥à¤¦ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+ <translation type="unfinished">छनौट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
<translation type="unfinished">भरà¥à¤–रै चयन गरेको ठेगाना सूचीबाट मेटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
</message>
<message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">खोजà¥à¤¨à¤•à¥‹ लागि ठेगाना वा लेबल दरà¥à¤¤à¤¾ गरà¥à¤¨à¥à¤¹à¥‹à¤¸</translation>
+ </message>
+ <message>
<source>Export the data in the current tab to a file</source>
<translation type="unfinished">वरà¥à¤¤à¤®à¤¾à¤¨ टà¥à¤¯à¤¾à¤¬à¤•à¥‹ डाटालाई फाइलमा निरà¥à¤¯à¤¾à¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
</message>
@@ -42,21 +46,70 @@
<translation type="unfinished">&amp;amp;मेटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
</message>
<message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">सिकà¥à¤•à¤¾à¤¹à¤°à¥ पठाउने ठेगाना छानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ </translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">सिकà¥à¤•à¤¾à¤¹à¤°à¥ पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤¨à¥‡ ठेगाना छानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+ </message>
+ <message>
<source>C&amp;hoose</source>
<translation type="unfinished">छनौट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥...</translation>
</message>
<message>
<source>Sending addresses</source>
- <translation type="unfinished">पठाउने ठेगानाहरू...</translation>
+ <translation type="unfinished">पठाउने ठेगानाहरू</translation>
</message>
<message>
<source>Receiving addresses</source>
<translation type="unfinished">पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤¨à¥‡ ठेगानाहरू...</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 type="unfinished">यी भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ गरà¥à¤¨à¤•à¤¾ लागि तपाइका बिटà¥à¤•à¥‹à¤‡à¤¨ ठेगानाहरू हà¥à¤¨à¥à¥¤ सिकà¥à¤•à¤¾à¤¹à¤°à¥‚ पठाउनà¥à¤…घि रकम र पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤¨à¥‡ ठेगाना जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥¤</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">ठेगाना कपी गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
</message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">लेबल कपी गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">समà¥à¤ªà¤¾à¤¦à¤¨</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">ठेगाना सà¥à¤šà¥€ निरà¥à¤¯à¤¾à¤¤</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">अलà¥à¤ªà¤µà¤¿à¤°à¤¾à¤®à¤²à¥‡ छà¥à¤Ÿà¥à¤Ÿà¤¿à¤à¤•à¥‹ फाइल</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
+ <translation type="unfinished">ठेगाना सà¥à¤šà¥€ %1मा बचत गरà¥à¤¨à¥‡ पà¥à¤°à¤¯à¤¾à¤¸à¤®à¤¾ तà¥à¤°à¥à¤Ÿà¤¿ भà¤à¤•à¥‹ छ। कृपया पà¥à¤¨à¤ƒ पà¥à¤°à¤¯à¤¾à¤¸ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥¤</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">निरà¥à¤¯à¤¾à¤¤ असफल</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">लेबल</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">ठेगाना</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -76,6 +129,30 @@
<source>Repeat new passphrase</source>
<translation type="unfinished">नयाठपासफà¥à¤°à¥‡à¤œ दोहोरà¥à¤¯à¤¾à¤‰à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
</message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">वालेट इनà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ </translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation type="unfinished">वालेट इनà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤¸à¤¨ सà¥à¤¨à¤¿à¤¶à¥à¤šà¤¿à¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished">वालेट इनà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ भयो</translation>
+ </message>
+ <message>
+ <source>Your wallet is now encrypted. </source>
+ <translation type="unfinished">अब वालेट इनà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ भà¤à¤•à¥‹ छ।</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation type="unfinished">वालेट इनà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤¸à¤¨ असफल </translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation type="unfinished">वालेट अनलक असफल </translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -144,10 +221,6 @@
<context>
<name>bitcoin-core</name>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">तà¥à¤°à¥à¤Ÿà¤¿: आगमन कनेकà¥à¤¸à¤¨à¤®à¤¾ सà¥à¤¨à¥à¤¨à¥‡ कारà¥à¤¯ असफल भयो (सà¥à¤¨à¥à¤¨à¥‡ कारà¥à¤¯à¤²à¥‡ तà¥à¤°à¥à¤Ÿà¤¿ %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 type="unfinished">maxtxfee=&amp;lt;रकम&amp;gt;: का लागि अमानà¥à¤¯ रकम &amp;apos;%s&amp;apos; (कारोबारलाई अडà¥à¤•à¤¨ नदिन अनिवारà¥à¤¯ रूपमा कमà¥à¤¤à¤¿à¤®à¤¾ %s को नà¥à¤¯à¥‚नतम रिले शà¥à¤²à¥à¤• हà¥à¤¨à¥ परà¥à¤›)</translation>
</message>
@@ -288,6 +361,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -339,7 +433,7 @@
</message>
<message>
<source>Balances</source>
- <translation type="unfinished">बà¥à¤¯à¤¾à¤²à¥‡à¤¨à¥à¤¸</translation>
+ <translation type="unfinished">बà¥à¤¯à¤¾à¤²à¥‡à¤¨à¥à¤¸à¤¹à¤°à¥</translation>
</message>
<message>
<source>Mined balance in watch-only addresses that has not yet matured</source>
@@ -357,6 +451,11 @@
<extracomment>Title of Peers Table column which contains the peer's User Agent string.</extracomment>
<translation type="unfinished">पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾ à¤à¤œà¥‡à¤¨à¥à¤Ÿ</translation>
</message>
+ <message>
+ <source>Address</source>
+ <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
+ <translation type="unfinished">ठेगाना</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -370,6 +469,13 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">लेबल</translation>
+ </message>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
@@ -397,7 +503,7 @@
<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 type="unfinished">बिटकोइनमा संलगà¥à¤¨ गरिà¤à¤•à¥‹ सनà¥à¤¦à¥‡à¤¶: तपाईंको मधà¥à¤¯à¤¸à¥à¤¥à¤•à¥‹ लागि कारोबारको साथमा भणà¥à¤¡à¤¾à¤°à¤£ गरिने URI । नोट: यो सनà¥à¤¦à¥‡à¤¶ बिटकोइन नेटवरà¥à¤• मारà¥à¤«à¤¤ पठाइने छैन ।</translation>
</message>
- </context>
+</context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
@@ -432,6 +538,33 @@
</message>
</context>
<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">लेबल</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">अलà¥à¤ªà¤µà¤¿à¤°à¤¾à¤®à¤²à¥‡ छà¥à¤Ÿà¥à¤Ÿà¤¿à¤à¤•à¥‹ फाइल</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">लेबल</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">ठेगाना</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">निरà¥à¤¯à¤¾à¤¤ असफल</translation>
+ </message>
+ </context>
+<context>
<name>WalletView</name>
<message>
<source>&amp;Export</source>
diff --git a/src/qt/locale/bitcoin_no.ts b/src/qt/locale/bitcoin_no.ts
index 569715c814..bfd524d525 100644
--- a/src/qt/locale/bitcoin_no.ts
+++ b/src/qt/locale/bitcoin_no.ts
@@ -152,6 +152,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_pa.ts b/src/qt/locale/bitcoin_pa.ts
new file mode 100644
index 0000000000..426656332a
--- /dev/null
+++ b/src/qt/locale/bitcoin_pa.ts
@@ -0,0 +1,492 @@
+<TS version="2.1" language="pa">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation type="unfinished">ਪਤੇ ਜਾਂ ਲੇਬਲ ਦਾ ਸੰਪਾਦਨ ਕਰਨ ਲਈ ਸੱਜਾ-ਕਲਿੱਕ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation type="unfinished">ਨਵਾਂ ਪਤਾ ਬਣਾਓ</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation type="unfinished">&amp;ਨਵਾਂ</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation type="unfinished">ਚà©à¨£à©‡ ਪਤੇ ਦੀ ਸਿਸਟਮ ਦੀ ਚੂੰਢੀ-ਤਖਤੀ 'ਤੇ ਨਕਲ ਲਾਹੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation type="unfinished">&amp;ਨਕਲ ਲਾਹੋ</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation type="unfinished">ਬੰ&amp;ਦ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">ਚà©à¨£à©‡ ਪਤੇ ਨੂੰ ਸੂਚੀ ਵਿੱਚੋਂ ਮਿਟਾਓ</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">ਖੋਜਣ ਲਈ ਪਤਾ ਜਾਂ ਲੇਬਲ ਦਾਖਲ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">ਮੌਜੂਦਾ ਟੈਬ ਵਿੱਚ ਡੇਟਾ ਨੂੰ ਫਾਈਲ ਵਿੱਚ à¨à¨•à¨¸à¨ªà©‹à¨°à¨Ÿ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;ਨਿਰਯਾਤ</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation type="unfinished">&amp;ਮਿਟਾਓ</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">ਸਿੱਕੇ ਭੇਜਣ ਲਈ ਪਤਾ ਚà©à¨£à©‹</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">ਸਿੱਕੇ ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰਨ ਲਈ ਪਤਾ ਚà©à¨£à©‹</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation type="unfinished">ਚà©à¨£à©‹ </translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation type="unfinished">bhejan wale pate</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation type="unfinished">ਆਉਣ ਵਾਲੇ ਪਤੇ </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 type="unfinished">ਇਹ ਭà©à¨—ਤਾਨ ਭੇਜਣ ਲਈ ਤà©à¨¹à¨¾à¨¡à©‡ ਬਿਟਕੋਇਨ ਪਤੇ ਹਨ। ਸਿੱਕੇ ਭੇਜਣ ਤੋਂ ਪਹਿਲਾਂ ਹਮੇਸ਼ਾਂ ਰਕਮ ਅਤੇ ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰਨ ਵਾਲੇ ਪਤੇ ਦੀ ਜਾਂਚ ਕਰੋ।</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">à¨à¨¹ ਤà©à¨¹à¨¾à¨¡à©‡ ਰਕਮ ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰਨ ਵਾਲੇ ਬਿਟਕਾਅਨ ਪਤੇ ਹਨ। ਪà©à¨°à¨¾à¨ªà¨¤à©€ ਟੈਬ ਤੇ ਨਵੇਂ ਪਤੇ ਦਰਜ ਕਰਨ ਲਈ "ਨਵਾਂ ਪà©à¨°à¨¾à¨ªà¨¤à©€ ਪਤਾ ਦਰਜ ਕਰੋ" ਬਟਨ ਤੇ ਟੈਪ ਕਰੋ। ਜà©à©œà¨¨ ਲਈ "ਲੈਗਸੀ" ਪà©à¨°à¨•à¨¾à¨° ਦੇ ਹੀ ਪਤੇ ਦਰਜ ਕੀਤੇ ਜਾਂ ਸਕਦੇ ਹਨ। </translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished">&amp;ਕਾਪੀ ਪਤਾ</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">&amp;ਲੇਬਲ ਕਾਪੀ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;ਸੋਧੋ</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">ਪਤਾ ਸੂਚੀ ਨਿਰਯਾਤ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">ਕਾਮੇ ਨਾਲ ਵੱਖ ਕੀਤੀ ਫਾਈਲ</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">ਨਿਰਯਾਤ ਅਸਫਲ ਰਿਹਾ</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">ਲੇਬਲ</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">ਪਤਾ</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">ਕੋਈ ਲੇਬਲ ਨਹੀਂ </translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ ਡਾਇਲਾਗ</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ ਲਿਖੋ</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation type="unfinished">ਨਵਾਂ ਪਾਸਫਰੇਜ</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation type="unfinished">ਨਵਾਂ ਪਾਸਫਰੇਜ ਦà©à¨¹à¨°à¨¾à¨“</translation>
+ </message>
+ <message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ ਦਿਖਾਓ</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">ਵਾਲਿਟ à¨à¨¨à¨•à©à¨°à¨¿à¨ªà¨Ÿ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation type="unfinished">à¨à¨¸ ਕਾਰੇ ਲਈ ਤà©à¨¹à¨¾à¨¡à¨¾ ਵੱਲੇਟ ਖੋਲਣ ਵਾਸਤੇ ਵੱਲੇਟ ਪਾਸ ਲੱਗੇਗਾ </translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਨੂੰ ਅਨਲੌਕ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ ਬਦਲੋ</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਇਨਕà©à¨°à¨¿à¨ªà¨¸à¨¼à¨¨ ਦੀ ਪà©à¨¸à¨¼à¨Ÿà©€ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished">ਕੀ ਤà©à¨¸à©€à¨‚ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਆਪਣੇ ਵਾਲਿਟ ਨੂੰ à¨à¨¨à¨•à©à¨°à¨¿à¨ªà¨Ÿ ਕਰਨਾ ਚਾਹà©à©°à¨¦à©‡ ਹੋ?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਨੂੰ à¨à¨¨à¨•à©à¨°à¨¿à¨ªà¨Ÿ ਕੀਤਾ ਗਿਆ</translation>
+ </message>
+ <message>
+ <source>Wallet to be encrypted</source>
+ <translation type="unfinished">ਇਨਕà©à¨°à¨¿à¨ªà¨Ÿà¨¡ ਹੋਣ ਲਈ ਵਾਲਿਟ</translation>
+ </message>
+ <message>
+ <source>Your wallet is about to be encrypted. </source>
+ <translation type="unfinished">ਤà©à¨¹à¨¾à¨¡à¨¾ ਵਾਲਿਟ à¨à¨¨à¨•à©à¨°à¨¿à¨ªà¨Ÿ ਹੋਣ ਵਾਲਾ ਹੈ।</translation>
+ </message>
+ <message>
+ <source>Your wallet is now encrypted. </source>
+ <translation type="unfinished">ਤà©à¨¹à¨¾à¨¡à¨¾ ਵਾਲਿਟ ਹà©à¨£ à¨à¨¨à¨•à©à¨°à¨¿à¨ªà¨Ÿ ਹੋ ਗਿਆ ਹੈ।</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਇਨਕà©à¨°à¨¿à¨ªà¨¸à¨¼à¨¨ ਅਸਫਲ</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">ਸਪਲਾਈ ਕੀਤੇ ਪਾਸਫਰੇਜ਼ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ।</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਅਨਲੌਕ ਅਸਫਲ ਰਿਹਾ</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਪਾਸਫਰੇਜ ਸਫਲਤਾਪੂਰਵਕ ਬਦਲਿਆ ਗਿਆ।</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished">ਚੇਤਾਵਨੀ: Caps Lock ਕà©à©°à¨œà©€ ਚਾਲੂ ਹੈ!</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">ਇੱਕ ਘਾਤਕ ਗਲਤੀ ਆਈ ਹੈ। %1ਹà©à¨£ ਸà©à¨°à©±à¨–ਿਅਤ ਢੰਗ ਨਾਲ ਜਾਰੀ ਨਹੀਂ ਰਹਿ ਸਕਦਾ ਹੈ ਅਤੇ ਛੱਡ ਦੇਵੇਗਾ।</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">ਅੰਦਰੂਨੀ ਗੜਬੜ</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">ਗਲਤੀ: %1</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">ਸੈਟਿੰਗ ਫਾਈਲ ਨੂੰ ਪੜà©à¨¹à¨¨ ਵਿੱਚ ਅਸਫਲ</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">ਸੈਟਿੰਗ ਫਾਈਲ ਲਿਖਣ ਵਿੱਚ ਅਸਫਲ</translation>
+ </message>
+ </context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>&amp;Overview</source>
+ <translation type="unfinished">&amp;ਓਵਰਵਿਊ</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation type="unfinished">&amp;ਲੈਣ-ਦੇਣ</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation type="unfinished">ਲੈਣ-ਦੇਣ ਦਾ ਇਤਿਹਾਸ ਬà©à¨°à¨¾à¨Šà¨œà¨¼ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation type="unfinished">à¨à¨ªà¨²à©€à¨•à©‡à¨¸à¨¼à¨¨ ਛੱਡੋ</translation>
+ </message>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">ਨਵਾਂ ਵਾਲਿਟ ਬਣਾਓ</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">ਬਟੂਆ: </translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation type="unfinished">ਬਿਟਕੋਇਨ ਪਤੇ 'ਤੇ ਸਿੱਕੇ ਭੇਜੋ</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਨੂੰ ਕਿਸੇ ਹੋਰ ਥਾਂ 'ਤੇ ਬੈਕਅੱਪ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਇਨਕà©à¨°à¨¿à¨ªà¨¸à¨¼à¨¨ ਲਈ ਵਰਤਿਆ ਜਾਣ ਵਾਲਾ ਪਾਸਫਰੇਜ ਬਦਲੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation type="unfinished">&amp;ਭੇਜੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation type="unfinished">&amp;ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;ਵਾਲਿਟ ਇਨਕà©à¨°à¨¿à¨ªà¨Ÿ ਕਰੋ...</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">ਨਿੱਜੀ ਕà©à©°à¨œà©€à¨†à¨‚ ਨੂੰ à¨à¨¨à¨•à©à¨°à¨¿à¨ªà¨Ÿ ਕਰੋ ਜੋ ਤà©à¨¹à¨¾à¨¡à©‡ ਵਾਲਿਟ ਨਾਲ ਸਬੰਧਤ ਹਨ</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;ਬੈਕਅੱਪ ਵਾਲਿਟ…</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ &amp;ਬਦਲੋ...</translation>
+ </message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">ਗਲਤੀ: %1</translation>
+ </message>
+ </context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">ਕੋਈ ਲੇਬਲ ਨਹੀਂ </translation>
+ </message>
+ </context>
+<context>
+ <name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(sufficient to restore backups %n day(s) old)</source>
+ <extracomment>Explanatory text on the capability of the current prune target.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ <message>
+ <source>Address</source>
+ <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
+ <translation type="unfinished">ਪਤਾ</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">ਬਟੂਆ: </translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">ਲੇਬਲ</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">ਕੋਈ ਲੇਬਲ ਨਹੀਂ </translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">ਕੋਈ ਲੇਬਲ ਨਹੀਂ </translation>
+ </message>
+</context>
+<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">ਲੇਬਲ</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">ਕੋਈ ਲੇਬਲ ਨਹੀਂ </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">ਕਾਮੇ ਨਾਲ ਵੱਖ ਕੀਤੀ ਫਾਈਲ</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">ਲੇਬਲ</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">ਪਤਾ</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">ਨਿਰਯਾਤ ਅਸਫਲ ਰਿਹਾ</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">ਨਵਾਂ ਵਾਲਿਟ ਬਣਾਓ</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;ਨਿਰਯਾਤ</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">ਮੌਜੂਦਾ ਟੈਬ ਵਿੱਚ ਡੇਟਾ ਨੂੰ ਫਾਈਲ ਵਿੱਚ à¨à¨•à¨¸à¨ªà©‹à¨°à¨Ÿ ਕਰੋ</translation>
+ </message>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_pam.ts b/src/qt/locale/bitcoin_pam.ts
index 99247f1579..d25f00c415 100644
--- a/src/qt/locale/bitcoin_pam.ts
+++ b/src/qt/locale/bitcoin_pam.ts
@@ -427,6 +427,24 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -745,10 +763,6 @@
<source>Message:</source>
<translation type="unfinished">Mensayi:</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Ibayad kang:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -865,10 +879,12 @@
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/ali me-kumpirma</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 kumpirmasion</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts
index 6fc1f2e032..e2f851bc5f 100644
--- a/src/qt/locale/bitcoin_pl.ts
+++ b/src/qt/locale/bitcoin_pl.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">Kliknij prawy przycisk myszy, aby edytować adres lub etykietę</translation>
+ <translation type="unfinished">Kliknij prawym przyciskiem myszy, aby edytować adres lub etykietę</translation>
</message>
<message>
<source>Create a new address</source>
@@ -43,7 +43,7 @@
</message>
<message>
<source>&amp;Delete</source>
- <translation type="unfinished">Usuń</translation>
+ <translation type="unfinished">&amp;Usuń</translation>
</message>
<message>
<source>Choose the address to send coins to</source>
@@ -59,7 +59,7 @@
</message>
<message>
<source>Sending addresses</source>
- <translation type="unfinished">Wysyłające adresy</translation>
+ <translation type="unfinished">&amp;Adresy wysyłania8f0451c0-ec7d-4357-a370-eff72fb0685f</translation>
</message>
<message>
<source>Receiving addresses</source>
@@ -103,7 +103,7 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished"> Eksportowanie nie powiodło się </translation>
+ <translation type="unfinished">Eksportowanie nie powiodło się </translation>
</message>
</context>
<context>
@@ -125,7 +125,7 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<name>AskPassphraseDialog</name>
<message>
<source>Passphrase Dialog</source>
- <translation type="unfinished"> Okienko Hasła </translation>
+ <translation type="unfinished">Okienko Hasła </translation>
</message>
<message>
<source>Enter passphrase</source>
@@ -157,7 +157,7 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>Change passphrase</source>
- <translation type="unfinished"> Zmień hasło </translation>
+ <translation type="unfinished">Zmień hasło </translation>
</message>
<message>
<source>Confirm wallet encryption</source>
@@ -185,11 +185,11 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
- <translation type="unfinished">Zwróć uwagę, że zaszyfrowanie portfela nie zabezpieczy się w pełni przed kradzieżą przez malware jakie może zainfekować twój komputer. </translation>
+ <translation type="unfinished">Pamiętaj, że zaszyfrowanie portfela nie pomoże w zapobiegnięciu kradzieży twoich bitcoinów jeśli komputer zostanie zainfekowany przez złośliwe oprogramowanie.</translation>
</message>
<message>
<source>Wallet to be encrypted</source>
- <translation type="unfinished"> Portfel do zaszyfrowania </translation>
+ <translation type="unfinished">Portfel do zaszyfrowania </translation>
</message>
<message>
<source>Your wallet is about to be encrypted. </source>
@@ -246,8 +246,16 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Plik ustawień 1%1 może być uszkodzony lub nieprawidłowy</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">BÅ‚Ä…d zapisu do portfela</translation>
+ </message>
+ <message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <translation type="unfinished">Wystąpił krytyczny błąd. %1 nie może dalej bezpiecznie pracować i zostanie zakończony.</translation>
+ <translation type="unfinished">Wystąpił fatalny błąd. %1 nie może być kontynuowany i zostanie zakończony.</translation>
</message>
<message>
<source>Internal error</source>
@@ -261,6 +269,16 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Przywrócić ustawienia domyślne czy zrezygnować bez dokonywania zmian?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Wystąpił krytyczny błąd. Upewnij się, że plik ustawień można nadpisać lub uruchom klienta z parametrem -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Błąd: Określony folder danych "%1" nie istnieje.</translation>
</message>
@@ -303,11 +321,31 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Wyjściowy</translation>
</message>
<message>
+ <source>Full Relay</source>
+ <extracomment>Peer connection type that relays all network information.</extracomment>
+ <translation type="unfinished">Pełny Przekaźnik</translation>
+ </message>
+ <message>
+ <source>Block Relay</source>
+ <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Przekaźnik Blokowy</translation>
+ </message>
+ <message>
<source>Manual</source>
<extracomment>Peer connection type established manually through one of several methods.</extracomment>
<translation type="unfinished">Ręczny</translation>
</message>
<message>
+ <source>Feeler</source>
+ <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Szczelinomierz</translation>
+ </message>
+ <message>
+ <source>Address Fetch</source>
+ <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
+ <translation type="unfinished">Pobieranie adresu</translation>
+ </message>
+ <message>
<source>None</source>
<translation type="unfinished">Żaden</translation>
</message>
@@ -318,41 +356,41 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n sekunda</numerusform>
+ <numerusform>%n sekund</numerusform>
+ <numerusform>%n sekund</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n minuta</numerusform>
+ <numerusform>%n minut</numerusform>
+ <numerusform>%n minut</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n godzina</numerusform>
+ <numerusform>%n godzin</numerusform>
+ <numerusform>%n godzin</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n dzień</numerusform>
+ <numerusform>%n dni</numerusform>
+ <numerusform>%n dni</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n tydzień</numerusform>
+ <numerusform>%n tygodnie</numerusform>
+ <numerusform>%n tygodnie</numerusform>
</translation>
</message>
<message>
@@ -362,15 +400,23 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n rok</numerusform>
+ <numerusform>%n lata</numerusform>
+ <numerusform>%n lata</numerusform>
</translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Nie udało się odczytać pliku ustawień</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Nie udało się zapisać pliku ustawień</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">Deweloperzy %s</translation>
</message>
@@ -383,10 +429,18 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">-maxtxfee ma ustawioną badzo dużą wartość! Tak wysokie opłaty mogą być zapłacone w jednej transakcji.</translation>
</message>
<message>
+ <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
+ <translation type="unfinished">Nie można zmienić wersji portfela z wersji %ina wersje %i. Wersja portfela pozostaje niezmieniona.</translation>
+ </message>
+ <message>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<translation type="unfinished">Nie można uzyskać blokady na katalogu z danymi %s. %s najprawdopodobniej jest już uruchomiony.</translation>
</message>
<message>
+ <source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
+ <translation type="unfinished">Nie można zaktualizować portfela dzielonego innego niż HD z wersji 1%i do wersji 1%i bez aktualizacji w celu obsługi wstępnie podzielonej puli kluczy. Użyj wersji 1%i lub nie określono wersji.</translation>
+ </message>
+ <message>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished">Rozprowadzane na licencji MIT, zobacz dołączony plik %s lub %s</translation>
</message>
@@ -395,18 +449,54 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Błąd odczytu %s! Wszystkie klucze zostały odczytane poprawnie, ale może brakować danych transakcji lub wpisów w książce adresowej, lub mogą one być nieprawidłowe.</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Błąd: Nasłuchiwanie połączeń przychodzących nie powiodło się (nasłuch zwrócił błąd %s)</translation>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">Błąd odczytu 1%s! Może brakować danych transakcji lub mogą być one nieprawidłowe. Ponowne skanowanie portfela.</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
+ <translation type="unfinished">BÅ‚Ä…d: rekord formatu pliku zrzutu jest nieprawidÅ‚owy. Otrzymano „1%sâ€, oczekiwany „formatâ€.</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source>
+ <translation type="unfinished">BÅ‚Ä…d: rekord identyfikatora pliku zrzutu jest nieprawidÅ‚owy. Otrzymano „1%sâ€, oczekiwano „1%sâ€.</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
+ <translation type="unfinished">Błąd: wersja pliku zrzutu nie jest obsługiwana. Ta wersja bitcoin-wallet obsługuje tylko pliki zrzutów w wersji 1. Mam plik zrzutu w wersji 1%s</translation>
+ </message>
+ <message>
+ <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
+ <translation type="unfinished">BÅ‚Ä…d: starsze portfele obsÅ‚ugujÄ… tylko typy adresów „legacyâ€, „p2sh-segwit†i „bech32â€</translation>
</message>
<message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Estymacja opłat nieudana. Domyślna opłata jest wyłączona. Poczekaj kilka bloków lub włącz -fallbackfee.</translation>
</message>
<message>
+ <source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
+ <translation type="unfinished">Plik 1%s już istnieje. Jeśli jesteś pewien, że tego chcesz, najpierw usuń to z drogi.</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 type="unfinished">Niewłaściwa ilość dla -maxtxfee=&lt;ilość&gt;: '%s' (musi wynosić przynajmniej minimalną wielkość %s aby zapobiec utknięciu transakcji)</translation>
</message>
<message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">Nieprawidłowy lub uszkodzony plik peers.dat (1%s). Jeśli uważasz, że to błąd, zgłoś go do 1%s. Jako obejście, możesz przenieść plik (1%s) z drogi (zmień nazwę, przenieś lub usuń), aby przy następnym uruchomieniu utworzyć nowy.</translation>
+ </message>
+ <message>
+ <source>No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">Nie dostarczono pliku zrzutu. Aby użyć funkcji createfromdump, należy podać -dumpfile=1.</translation>
+ </message>
+ <message>
+ <source>No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">Nie dostarczono pliku zrzutu. Aby użyć funkcji createfromdump, należy podać -dumpfile=1.</translation>
+ </message>
+ <message>
+ <source>No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
+ <translation type="unfinished">Nie dostarczono pliku zrzutu. Aby użyć funkcji createfromdump, należy podać -dumpfile=1.</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 type="unfinished">Proszę sprawdzić czy data i czas na Twoim komputerze są poprawne! Jeżeli ustawienia zegara będą złe, %s nie będzie działał prawidłowo.</translation>
</message>
@@ -431,6 +521,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Baza bloków zawiera blok, który wydaje się pochodzić z przyszłości. Może to wynikać z nieprawidłowego ustawienia daty i godziny Twojego komputera. Bazę danych bloków dobuduj tylko, jeśli masz pewność, że data i godzina twojego komputera są poprawne</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">Baza danych indeksu bloku zawiera odziedziczony „txindexâ€. Aby wyczyÅ›cić zajÄ™te miejsce na dysku, uruchom peÅ‚nÄ… indeksacjÄ™, w przeciwnym razie zignoruj ten bÅ‚Ä…d. Ten komunikat o bÅ‚Ä™dzie nie zostanie ponownie wyÅ›wietlony.</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished">Zbyt niska kwota transakcji do wysłania po odjęciu opłaty</translation>
</message>
@@ -463,6 +557,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Nie można przetworzyć bloków. Konieczne będzie przebudowanie bazy danych za pomocą -reindex-chainstate.</translation>
</message>
<message>
+ <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source>
+ <translation type="unfinished">Podano nieznany typ pliku portfela "%s". Proszę podać jeden z "bdb" lub "sqlite".</translation>
+ </message>
+ <message>
<source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
<translation type="unfinished">Uwaga: Wykryto klucze prywatne w portfelu [%s] który ma wyłączone klucze prywatne</translation>
</message>
@@ -499,6 +597,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Nie mogę zapisać do katalogu danych '%s'; sprawdź uprawnienia.</translation>
</message>
<message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Zmiana nazwy nieprawidłowego pliku peers.dat nie powiodła się. Przenieś go lub usuń i spróbuj ponownie.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">Ustawienie konfiguracyjne %s działa na sieć %s tylko, jeżeli jest w sekcji [%s].</translation>
</message>
@@ -531,6 +633,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Wczytywanie zakończone</translation>
</message>
<message>
+ <source>Error creating %s</source>
+ <translation type="unfinished">BÅ‚Ä…d podczas tworzenia %s</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
<translation type="unfinished">Błąd inicjowania bazy danych bloków</translation>
</message>
@@ -567,18 +673,34 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Błąd odczytu z bazy danych, wyłączam się.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Błąd ładowania bazy bloków</translation>
+ <source>Error reading next record from wallet database</source>
+ <translation type="unfinished">BÅ‚Ä…d odczytu kolejnego rekordu z bazy danych portfela</translation>
</message>
<message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Błąd: zbyt mało miejsca na dysku dla %s</translation>
</message>
<message>
+ <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
+ <translation type="unfinished">BÅ‚Ä…d: Plik zrzutu suma kontrolna nie pasuje. Obliczone %s, spodziewane %s</translation>
+ </message>
+ <message>
<source>Error: Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished">Błąd: Pula kluczy jest pusta, odwołaj się do puli kluczy.</translation>
</message>
<message>
+ <source>Error: Missing checksum</source>
+ <translation type="unfinished">BÅ‚ad: Brak suma kontroly</translation>
+ </message>
+ <message>
+ <source>Error: No %s addresses available.</source>
+ <translation type="unfinished">Błąd: %s adres nie dostępny</translation>
+ </message>
+ <message>
+ <source>Error: Unable to write record to new wallet</source>
+ <translation type="unfinished">Błąd: Wpisanie rekordu do nowego portfela jest niemożliwe</translation>
+ </message>
+ <message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation type="unfinished">Próba nasłuchiwania na jakimkolwiek porcie nie powiodła się. Użyj -listen=0 jeśli tego chcesz.</translation>
</message>
@@ -599,6 +721,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Ignorowanie duplikatu -wallet %s</translation>
</message>
<message>
+ <source>Importing…</source>
+ <translation type="unfinished">Importowanie...</translation>
+ </message>
+ <message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
<translation type="unfinished">Nieprawidłowy lub brak bloku genezy. Błędny folder_danych dla sieci?</translation>
</message>
@@ -643,12 +769,32 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Nieprawidłowa maska sieci określona w -whitelist: '%s'</translation>
</message>
<message>
+ <source>Loading P2P addresses…</source>
+ <translation type="unfinished">Åadowanie adresów P2P...</translation>
+ </message>
+ <message>
+ <source>Loading banlist…</source>
+ <translation type="unfinished">Åadowanie listy zablokowanych...</translation>
+ </message>
+ <message>
+ <source>Loading block index…</source>
+ <translation type="unfinished">Åadowanie indeksu bloku...</translation>
+ </message>
+ <message>
+ <source>Loading wallet…</source>
+ <translation type="unfinished">Åadowanie portfela...</translation>
+ </message>
+ <message>
+ <source>Missing amount</source>
+ <translation type="unfinished">BrakujÄ…ca kwota</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">Musisz określić port z -whitebind: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Żaden serwer proxy nie jest ustawiony. Użyj -proxy=&lt;ip&gt; lub -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Brak dostępnych adresów</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -667,6 +813,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Zmniejszanie -maxconnections z %d do %d z powodu ograniczeń systemu.</translation>
</message>
<message>
+ <source>Rescanning…</source>
+ <translation type="unfinished">Ponowne skanowanie...</translation>
+ </message>
+ <message>
<source>SQLiteDatabase: Failed to execute statement to verify database: %s</source>
<translation type="unfinished">SQLiteDatabase: nie powiodło się wykonanie instrukcji weryfikującej bazę danych: %s</translation>
</message>
@@ -708,6 +858,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</translation>
</message>
<message>
+ <source>Starting network threads…</source>
+ <translation type="unfinished">Startowanie wątków sieciowych...</translation>
+ </message>
+ <message>
<source>The source code is available from %s.</source>
<translation type="unfinished">Kod źródłowy dostępny jest z %s.</translation>
</message>
@@ -772,6 +926,14 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Nie można wygenerować kluczy</translation>
</message>
<message>
+ <source>Unable to open %s for writing</source>
+ <translation type="unfinished">Nie można otworzyć %s w celu zapisu</translation>
+ </message>
+ <message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">Nie można przeanalizować -maxuploadtarget: „%sâ€</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">Uruchomienie serwera HTTP nie powiodło się. Zobacz dziennik debugowania, aby uzyskać więcej szczegółów.</translation>
</message>
@@ -792,18 +954,26 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Nieznana sieć w -onlynet: '%s'</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">Nieobsługiwana kategoria rejestrowania %s=%s.</translation>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished">Aktywowano nieznane nowe reguły (versionbit %i)</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Aktualizowanie bazy danych UTXO</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Nieobsługiwana kategoria rejestrowania %s=%s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Komentarz User Agent (%s) zawiera niebezpieczne znaki.</translation>
</message>
<message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">Weryfikowanie bloków...</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)…</source>
+ <translation type="unfinished">Weryfikowanie porfela(li)...</translation>
+ </message>
+ <message>
<source>Wallet needed to be rewritten: restart %s to complete</source>
<translation type="unfinished">Portfel wymaga przepisania: zrestartuj %s aby ukończyć</translation>
</message>
@@ -859,6 +1029,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Stwórz nowy portfel</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">Z&amp;minimalizuj</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Portfel:</translation>
</message>
@@ -897,13 +1071,17 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>&amp;Encrypt Wallet…</source>
- <translation type="unfinished">Zaszyfruj portf&amp;el...</translation>
+ <translation type="unfinished">&amp;Zaszyfruj portfel</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">Szyfruj klucze prywatne, które są w twoim portfelu</translation>
</message>
<message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">Utwórz kopię zapasową portfela...</translation>
+ </message>
+ <message>
<source>&amp;Change Passphrase…</source>
<translation type="unfinished">&amp;Zmień hasło...</translation>
</message>
@@ -913,7 +1091,7 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation type="unfinished">Podpisz wiadomości swoim adresem, aby udowodnić jego posiadanie</translation>
+ <translation type="unfinished">Podpisz wiadomości swoim adresem aby udowodnić jego posiadanie</translation>
</message>
<message>
<source>&amp;Verify message…</source>
@@ -924,6 +1102,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Zweryfikuj wiadomość, aby upewnić się, że została podpisana podanym adresem bitcoinowym.</translation>
</message>
<message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">Wczytaj PSBT z pliku...</translation>
+ </message>
+ <message>
<source>Open &amp;URI…</source>
<translation type="unfinished">Otwórz &amp;URI...</translation>
</message>
@@ -956,8 +1138,32 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Pasek zakładek</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Synchronizuję nagłówki (%1%)…</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Synchronizacja z sieciÄ…...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Indeksowanie bloków...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Przetwarzanie bloków...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Ponowne indeksowanie bloków...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">ÅÄ…czenie z uczestnikami sieci...</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation type="unfinished">Żądaj płatności (generuje kod QR oraz bitcoinowe URI)</translation>
+ <translation type="unfinished">Zażądaj płatności (wygeneruj QE code i bitcoin: URI)</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
@@ -974,9 +1180,9 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Przetworzono %n blok historii transakcji.</numerusform>
+ <numerusform>Przetworzono 1%n bloków historii transakcji.</numerusform>
+ <numerusform>Przetworzono 1%n bloków historii transakcji.</numerusform>
</translation>
</message>
<message>
@@ -984,6 +1190,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">%1 za</translation>
</message>
<message>
+ <source>Catching up…</source>
+ <translation type="unfinished">SynchronizujÄ™...</translation>
+ </message>
+ <message>
<source>Last received block was generated %1 ago.</source>
<translation type="unfinished">Ostatni otrzymany blok został wygenerowany %1 temu.</translation>
</message>
@@ -1012,6 +1222,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Załaduj częściowo podpisaną transakcję Bitcoin</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">Wczytaj PSBT ze schowka...</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">Załaduj częściowo podpisaną transakcję Bitcoin ze schowka</translation>
</message>
@@ -1048,6 +1262,16 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Zamknij portfel</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Przywróć Portfel…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Przywróć portfel z pliku kopii zapasowej</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Zamknij wszystkie portfele</translation>
</message>
@@ -1072,6 +1296,26 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Brak dostępnych portfeli</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Informacje portfela</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Załaduj kopię zapasową portfela</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Przywróć portfel</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nazwa portfela</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Okno</translation>
</message>
@@ -1087,16 +1331,40 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<source>%1 client</source>
<translation type="unfinished">%1 klient</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Ukryj</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n aktywne połączenie z siecią Bitcoin.</numerusform>
+ <numerusform>%n aktywnych połączeń z siecią Bitcoin.</numerusform>
+ <numerusform>%n aktywnych połączeń z siecią Bitcoin.</numerusform>
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Kliknij po więcej funkcji.</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Wyświetl połączenia</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">Wyłącz aktywność sieciową</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">Włącz aktywność sieciową</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">BÅ‚Ä…d: %1</translation>
</message>
@@ -1170,7 +1438,7 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>Original message:</source>
- <translation type="unfinished">Wiadomość oryginalna:</translation>
+ <translation type="unfinished">Orginalna wiadomość:</translation>
</message>
</context>
<context>
@@ -1212,11 +1480,11 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>Change:</source>
- <translation type="unfinished">Reszta:</translation>
+ <translation type="unfinished">Zmiana:</translation>
</message>
<message>
<source>(un)select all</source>
- <translation type="unfinished">Zaznacz/Odznacz wszystko</translation>
+ <translation type="unfinished">zaznacz/odznacz wszytsko</translation>
</message>
<message>
<source>Tree mode</source>
@@ -1244,17 +1512,41 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>Confirmations</source>
- <translation type="unfinished">Potwierdzenia</translation>
+ <translation type="unfinished">Potwierdzenie</translation>
</message>
<message>
<source>Confirmed</source>
- <translation type="unfinished">Potwierdzony</translation>
+ <translation type="unfinished">Potwerdzone</translation>
</message>
<message>
<source>Copy amount</source>
+ <translation type="unfinished">Kopiuj kwote</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">Kopiuj adres</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiuj etykietÄ™</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
<translation type="unfinished">Kopiuj kwotÄ™</translation>
</message>
<message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Skopiuj &amp;ID transakcji oraz wyjściowy indeks</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">Zabl&amp;okuj niewydane</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">Odblok&amp;uj niewydane</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Skopiuj ilość</translation>
</message>
@@ -1316,31 +1608,48 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<message>
<source>Create Wallet</source>
<extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
- <translation type="unfinished">Stwórz portfel</translation>
+ <translation type="unfinished">Stwórz potrfel</translation>
</message>
<message>
<source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
- <translation type="unfinished">Otwieranie portfela &lt;b&gt;%1&lt;/b&gt;...</translation>
+ <translation type="unfinished">Tworzenie portfela &lt;b&gt;%1&lt;/b&gt;...</translation>
</message>
<message>
<source>Create wallet failed</source>
- <translation type="unfinished">Tworzenie portfela nieudane</translation>
+ <translation type="unfinished">Nieudane tworzenie potrfela</translation>
</message>
<message>
<source>Create wallet warning</source>
<translation type="unfinished">Ostrzeżenie przy tworzeniu portfela</translation>
</message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Nie można wyświetlić sygnatariuszy</translation>
+ </message>
</context>
<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished"> Åaduj portfele</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">Åadowanie portfeli...</translation>
+ </message>
+</context>
+<context>
<name>OpenWalletActivity</name>
<message>
<source>Open wallet failed</source>
- <translation type="unfinished">Otwarcie portfela nie powiodło się</translation>
+ <translation type="unfinished">Otworzenie portfela nie powiodło się</translation>
</message>
<message>
<source>Open wallet warning</source>
- <translation type="unfinished">Ostrzeżenie przy otwieraniu portfela</translation>
+ <translation type="unfinished">Ostrzeżenie przy otworzeniu potrfela</translation>
</message>
<message>
<source>default wallet</source>
@@ -1351,6 +1660,19 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">Otwórz Portfel</translation>
</message>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">Otwieranie portfela &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Przywróć portfel</translation>
+ </message>
</context>
<context>
<name>WalletController</name>
@@ -1379,7 +1701,7 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<name>CreateWalletDialog</name>
<message>
<source>Create Wallet</source>
- <translation type="unfinished">Stwórz portfel</translation>
+ <translation type="unfinished">Stwórz potrfel</translation>
</message>
<message>
<source>Wallet Name</source>
@@ -1426,6 +1748,14 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Portfel deskryptora</translation>
</message>
<message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Użyj zewnętrznego urządzenia podpisującego, takiego jak portfel sprzętowy. Najpierw skonfiguruj zewnętrzny skrypt podpisujący w preferencjach portfela.</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">Zewnętrzny sygnatariusz</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">Stwórz</translation>
</message>
@@ -1433,7 +1763,12 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<source>Compiled without sqlite support (required for descriptor wallets)</source>
<translation type="unfinished">Skompilowano bez wsparcia sqlite (wymaganego dla deskryptorów potfeli)</translation>
</message>
- </context>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Skompilowany bez obsługi podpisywania zewnętrznego (wymagany do podpisywania zewnętrzengo)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -1514,6 +1849,30 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(z %n GB potrzebnych)</numerusform>
+ <numerusform>(z %n GB potrzebnych)</numerusform>
+ <numerusform>(z %n GB potrzebnych)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB potrzebny na pełny łańcuch)</numerusform>
+ <numerusform>(%n GB potrzebne na pełny łańcuch)</numerusform>
+ <numerusform>(%n GB potrzebnych na pełny łańcuch)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Co najmniej %1 GB danych, zostanie zapisane w tym katalogu, dane te będą przyrastały w czasie.</translation>
@@ -1526,9 +1885,9 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>(wystarcza do przywrócenia kopii zapasowych sprzed %n dnia)</numerusform>
+ <numerusform>(wystarcza do przywrócenia kopii zapasowych sprzed %n dni)</numerusform>
+ <numerusform>(wystarcza do przywrócenia kopii zapasowych sprzed %n dni)</numerusform>
</translation>
</message>
<message>
@@ -1560,14 +1919,18 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Ponieważ jest to pierwsze uruchomienie programu, możesz wybrać gdzie %1 będzie przechowywał swoje dane.</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 type="unfinished">Gdy naciśniesz OK, %1 zacznie się pobieranie i przetwarzanie całego %4 łańcucha bloków (%2GB) zaczynając od najwcześniejszych transakcji w %3 gdy %4 został uruchomiony.</translation>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">Ogranicz przechowywanie łańcucha bloków do</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">Wyłączenie tej opcji spowoduje konieczność pobrania całego łańcucha bloków. Szybciej jest najpierw pobrać cały łańcuch a następnie go przyciąć (prune). Wyłącza niektóre zaawansowane funkcje.</translation>
</message>
<message>
+ <source> GB</source>
+ <translation type="unfinished">GB</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 type="unfinished">Wstępna synchronizacja jest bardzo wymagająca i może ujawnić wcześniej niezauważone problemy sprzętowe. Za każdym uruchomieniem %1 pobieranie będzie kontynuowane od miejsca w którym zostało zatrzymane.</translation>
</message>
@@ -1602,6 +1965,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 siÄ™ zamyka...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation type="unfinished">Nie wyłączaj komputera dopóki to okno nie zniknie.</translation>
</message>
@@ -1625,6 +1992,14 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Pozostało bloków</translation>
</message>
<message>
+ <source>Unknown…</source>
+ <translation type="unfinished">Nieznany...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">obliczanie...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation type="unfinished">Czas ostatniego bloku</translation>
</message>
@@ -1652,6 +2027,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
<translation type="unfinished">%1 jest w trakcie synchronizacji. Trwa pobieranie i weryfikacja nagłówków oraz bloków z sieci w celu uzyskania aktualnego stanu łańcucha.</translation>
</message>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">nieznany, Synchronizowanie nagłówków (1%1, 2%2%)</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -1684,6 +2063,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Uruchamiaj %1 wraz z zalogowaniem do &amp;systemu</translation>
</message>
<message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Włączenie czyszczenia znacznie zmniejsza ilość miejsca na dysku wymaganego do przechowywania transakcji. Wszystkie bloki są nadal w pełni zweryfikowane. Przywrócenie tego ustawienia wymaga ponownego pobrania całego łańcucha bloków.</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation type="unfinished">Wielkość bufora bazy &amp;danych</translation>
</message>
@@ -1732,14 +2115,44 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Cofnięcie tego ustawienia wymaga ponownego załadowania całego łańcucha bloków.</translation>
</message>
<message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">Maksymalny rozmiar pamięci podręcznej bazy danych. Większa pamięć podręczna może przyczynić się do szybszej synchronizacji, po której korzyści są mniej widoczne w większości przypadków użycia. Zmniejszenie rozmiaru pamięci podręcznej zmniejszy zużycie pamięci. Nieużywana pamięć mempool jest współdzielona dla tej pamięci podręcznej.</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Ustaw liczbę wątków weryfikacji skryptu. Wartości ujemne odpowiadają liczbie rdzeni, które chcesz pozostawić systemowi.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = automatycznie, &lt;0 = zostaw tyle wolnych rdzeni)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Umożliwia tobie lub narzędziu innej firmy komunikowanie się z węzłem za pomocą wiersza polecenia i poleceń JSON-RPC.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">WÅ‚Ä…cz serwer R&amp;PC</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">Portfel</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Czy ustawić opłatę odejmowaną od kwoty jako domyślną, czy nie.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Domyślnie odejmij opłatę od kwoty</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">Ekspert</translation>
</message>
@@ -1756,6 +2169,28 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Wydaj niepotwierdzonÄ… re&amp;sztÄ™</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">WÅ‚Ä…cz ustawienia &amp;PSBT</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Czy wyświetlać opcje PSBT.</translation>
+ </message>
+ <message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">Zewnętrzny sygnatariusz (np. portfel sprzętowy) </translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;Ścieżka zewnętrznego skryptu podpisującego</translation>
+ </message>
+ <message>
+ <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished">Pełna ścieżka do skryptu zgodnego z Bitcoin Core (np. C:\Downloads\hwi.exe lub /Users/you/Downloads/hwi.py). Uwaga: złośliwe oprogramowanie może ukraść Twoje monety!</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 type="unfinished">Automatycznie otwiera port klienta Bitcoin na routerze. Ta opcja dzieła tylko jeśli twój router wspiera UPnP i jest ono włączone.</translation>
</message>
@@ -1764,6 +2199,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Mapuj port używając &amp;UPnP</translation>
</message>
<message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
+ <translation type="unfinished">Automatycznie otwiera port klienta Bitcoin w routerze. Działa jedynie wtedy, gdy router wspiera NAT-PMP i usługa ta jest włączona. Zewnętrzny port może być losowy.</translation>
+ </message>
+ <message>
<source>Map port using NA&amp;T-PMP</source>
<translation type="unfinished">Mapuj port przy użyciu NA&amp;T-PMP</translation>
</message>
@@ -1840,6 +2279,14 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Wybierz podział jednostki pokazywany w interfejsie oraz podczas wysyłania monet</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 type="unfinished">Adresy URL stron trzecich (np. eksplorator bloków), które pojawiają się na karcie transakcji jako pozycje menu kontekstowego. %s w adresie URL jest zastępowane hashem transakcji. Wiele adresów URL jest oddzielonych pionową kreską |.</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;Adresy URL transakcji stron trzecich</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">Wybierz pokazywanie lub nie funkcji kontroli monet.</translation>
</message>
@@ -1852,14 +2299,23 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Użyj oddzielnego proxy SOCKS&amp;5 aby osiągnąć węzły w ukrytych usługach Tor:</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Opcje ustawione w tym oknie sÄ… nadpisane przez liniÄ™ komend lub plik konfiguracyjny:</translation>
+ <source>Monospaced font in the Overview tab:</source>
+ <translation type="unfinished">Czcionka o stałej szerokości w zakładce Przegląd:</translation>
+ </message>
+ <message>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">najbliższy pasujący "%1"</translation>
</message>
<message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Anuluj</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Skompilowany bez obsługi podpisywania zewnętrznego (wymagany do podpisywania zewnętrzengo)</translation>
+ </message>
+ <message>
<source>default</source>
<translation type="unfinished">domyślny</translation>
</message>
@@ -1869,14 +2325,17 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Potwierdź reset ustawień</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Wymagany restart programu, aby uaktywnić zmiany.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Program zostanie wyłączony. Czy chcesz kontynuować?</translation>
</message>
<message>
@@ -1890,6 +2349,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Plik konfiguracyjny jest używany celem zdefiniowania zaawansowanych opcji nadpisujących ustawienia aplikacji okienkowej (GUI). Parametry zdefiniowane z poziomu linii poleceń nadpisują parametry określone w tym pliku.</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">Kontynuuj</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">Anuluj</translation>
</message>
@@ -2004,6 +2467,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Kopiuj do schowka</translation>
</message>
<message>
+ <source>Save…</source>
+ <translation type="unfinished">Zapisz...</translation>
+ </message>
+ <message>
<source>Close</source>
<translation type="unfinished">Zamknij</translation>
</message>
@@ -2016,6 +2483,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Nie udało się podpisać transakcji: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">Nie można podpisywać danych wejściowych, gdy portfel jest zablokowany.</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">Nie udało się podpisać więcej wejść.</translation>
</message>
@@ -2044,6 +2515,11 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Zapisz dane transakcji</translation>
</message>
<message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">Częściowo podpisana transakcja (binarna)</translation>
+ </message>
+ <message>
<source>PSBT saved to disk.</source>
<translation type="unfinished">PSBT zapisane na dysk.</translation>
</message>
@@ -2080,6 +2556,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Transakcja ciÄ…gle oczekuje na podpis(y).</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Ale żaden portfel nie jest załadowany.)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Ale ten portfel nie może podipisać transakcji.)</translation>
</message>
@@ -2115,6 +2595,14 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">'bitcoin://' nie jest poprawnym URI. Użyj 'bitcoin:'.</translation>
</message>
<message>
+ <source>Cannot process payment request because BIP70 is not supported.
+Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
+If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
+ <translation type="unfinished">Nie można przetworzyć żądanie zapłaty poniewasz BIP70 nie jest obsługiwany.
+Ze względu na wady bezpieczeństwa w BIP70 jest zalecane ignorować wszelkich instrukcji od sprzedawcę dotyczących zmiany portfela.
+Jeśli pojawia się ten błąd, poproś sprzedawcę o podanie URI zgodnego z BIP21. </translation>
+ </message>
+ <message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<translation type="unfinished">Nie można przeanalizować identyfikatora URI! Może to być spowodowane nieważnym adresem Bitcoin lub nieprawidłowymi parametrami URI.</translation>
</message>
@@ -2174,6 +2662,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<context>
<name>QRImageWidget</name>
<message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">Zapi&amp;sz Obraz...</translation>
+ </message>
+ <message>
<source>&amp;Copy Image</source>
<translation type="unfinished">&amp;Kopiuj obraz</translation>
</message>
@@ -2306,6 +2798,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Zsynchronizowane bloki</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Ostatnia Transakcja</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">Zmapowany autonomiczny system (ang. asmap) używany do dywersyfikacji wyboru węzłów.</translation>
</message>
@@ -2314,6 +2810,26 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Zmapowany autonomiczny system (ang. asmap)</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Czy przekazujemy adresy do tego peera.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Adres Przekaźnika</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Przetworzone Adresy</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Wskaźnik-Ograniczeń Adresów</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">Aplikacja kliencka</translation>
</message>
@@ -2342,6 +2858,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Uprawnienia</translation>
</message>
<message>
+ <source>Direction/Type</source>
+ <translation type="unfinished">Kierunek/Rodzaj</translation>
+ </message>
+ <message>
<source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
<translation type="unfinished">Protokół sieciowy używany przez ten węzeł: IPv4, IPv6, Onion, I2P, lub CJDNS.</translation>
</message>
@@ -2350,6 +2870,22 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Usługi</translation>
</message>
<message>
+ <source>Whether the peer requested us to relay transactions.</source>
+ <translation type="unfinished">Czy peer poprosił nas o przekazanie transakcji.</translation>
+ </message>
+ <message>
+ <source>Wants Tx Relay</source>
+ <translation type="unfinished">Chce przekaźnik Tx</translation>
+ </message>
+ <message>
+ <source>High bandwidth BIP152 compact block relay: %1</source>
+ <translation type="unfinished">Kompaktowy przekaźnik blokowy BIP152 o dużej przepustowości: 1 %1</translation>
+ </message>
+ <message>
+ <source>High Bandwidth</source>
+ <translation type="unfinished">Wysoka Przepustowość</translation>
+ </message>
+ <message>
<source>Connection Time</source>
<translation type="unfinished">Czas połączenia</translation>
</message>
@@ -2358,6 +2894,11 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Ostatni Blok</translation>
</message>
<message>
+ <source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
+ <extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
+ <translation type="unfinished">Czas, który upłynął od otrzymania nowej transakcji przyjętej do naszej pamięci od tego partnera.</translation>
+ </message>
+ <message>
<source>Last Send</source>
<translation type="unfinished">Ostatnio wysłano</translation>
</message>
@@ -2427,6 +2968,48 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Przychodzące: zainicjowane przez węzeł</translation>
</message>
<message>
+ <source>Outbound Full Relay: default</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment>
+ <translation type="unfinished">Pełny przekaźnik wychodzący: domyślnie</translation>
+ </message>
+ <message>
+ <source>Outbound Block Relay: does not relay transactions or addresses</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Outbound Block Relay: nie przekazuje transakcji ani adresów</translation>
+ </message>
+ <message>
+ <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
+ <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment>
+ <translation type="unfinished">Outbound Manual: dodano przy użyciu opcji konfiguracyjnych RPC 1%1 lub 2%2/3%3</translation>
+ </message>
+ <message>
+ <source>Outbound Feeler: short-lived, for testing addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Outbound Feeler: krótkotrwały, do testowania adresów</translation>
+ </message>
+ <message>
+ <source>Outbound Address Fetch: short-lived, for soliciting addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment>
+ <translation type="unfinished">Pobieranie adresu wychodzącego: krótkotrwałe, do pozyskiwania adresów</translation>
+ </message>
+ <message>
+ <source>we selected the peer for high bandwidth relay</source>
+ <translation type="unfinished">wybraliśmy peera dla przekaźnika o dużej przepustowości</translation>
+ </message>
+ <message>
+ <source>the peer selected us for high bandwidth relay</source>
+ <translation type="unfinished">peer wybrał nas do przekaźnika o dużej przepustowości</translation>
+ </message>
+ <message>
+ <source>no high bandwidth relay selected</source>
+ <translation type="unfinished">nie wybrano przekaźnika o dużej przepustowości</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">Kopiuj adres</translation>
+ </message>
+ <message>
<source>&amp;Disconnect</source>
<translation type="unfinished">&amp;Rozłącz</translation>
</message>
@@ -2435,6 +3018,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">1 &amp;godzina</translation>
</message>
<message>
+ <source>1 d&amp;ay</source>
+ <translation type="unfinished">1 dzień</translation>
+ </message>
+ <message>
<source>1 &amp;week</source>
<translation type="unfinished">1 &amp;tydzień</translation>
</message>
@@ -2443,6 +3030,11 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">1 &amp;rok</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">Skopiuj IP/MaskÄ™ Sieci</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Odblokuj</translation>
</message>
@@ -2459,6 +3051,11 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Wykonuję komendę używając portfela "%1"</translation>
</message>
<message>
+ <source>Executing…</source>
+ <extracomment>A console message indicating an entered command is currently being executed.</extracomment>
+ <translation type="unfinished">WykonujÄ™...</translation>
+ </message>
+ <message>
<source>via %1</source>
<translation type="unfinished">przez %1</translation>
</message>
@@ -2566,6 +3163,22 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Kopiuj &amp;URI</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">Kopiuj adres</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiuj etykietÄ™</translation>
+ </message>
+ <message>
+ <source>Copy &amp;message</source>
+ <translation type="unfinished">Skopiuj wiado&amp;mość</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopiuj kwotÄ™</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">Nie można było odblokować portfela.</translation>
</message>
@@ -2577,6 +3190,10 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>Request payment to …</source>
+ <translation type="unfinished">Żądaj płatności do ...</translation>
+ </message>
+ <message>
<source>Address:</source>
<translation type="unfinished">Adres:</translation>
</message>
@@ -2605,6 +3222,18 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
<translation type="unfinished">Kopiuj &amp;adres</translation>
</message>
<message>
+ <source>&amp;Verify</source>
+ <translation type="unfinished">Zweryfikuj</translation>
+ </message>
+ <message>
+ <source>Verify this address on e.g. a hardware wallet screen</source>
+ <translation type="unfinished">Zweryfikuj ten adres np. na ekranie portfela sprzętowego</translation>
+ </message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">Zapi&amp;sz Obraz...</translation>
+ </message>
+ <message>
<source>Payment information</source>
<translation type="unfinished">Informacje o płatności</translation>
</message>
@@ -2684,7 +3313,7 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation>
</message>
<message>
<source>Change:</source>
- <translation type="unfinished">Reszta:</translation>
+ <translation type="unfinished">Zmiana:</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>
@@ -2736,14 +3365,30 @@ Korzystanie z opłaty domyślnej może skutkować wysłaniem transakcji, która
<translation type="unfinished">Wyczyść wszystkie pola formularza.</translation>
</message>
<message>
+ <source>Inputs…</source>
+ <translation type="unfinished">Wejścia…</translation>
+ </message>
+ <message>
<source>Dust:</source>
<translation type="unfinished">Pył:</translation>
</message>
<message>
+ <source>Choose…</source>
+ <translation type="unfinished">Wybierz...</translation>
+ </message>
+ <message>
<source>Hide transaction fee settings</source>
<translation type="unfinished">Ukryj ustawienia opłat transakcyjnych</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 rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation type="unfinished">Określ niestandardową opłatę za kB (1000 bajtów) wirtualnego rozmiaru transakcji.
+
+Uwaga: Ponieważ opłata jest naliczana za każdy bajt, opłata "100 satoshi za kB" w przypadku transakcji o wielkości 500 bajtów (połowa 1 kB) ostatecznie da opłatę w wysokości tylko 50 satoshi.</translation>
+ </message>
+ <message>
<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">Gdy ilość transakcji jest mniejsza niż ilość miejsca w bloku, górnicy i węzły przekazujące wymagają minimalnej opłaty. Zapłata tylko tej wartości jest dopuszczalna, lecz może skutkować transakcją która nigdy nie zostanie potwierdzona w sytuacji, gdy ilość transakcji przekroczy przepustowość sieci.</translation>
</message>
@@ -2752,6 +3397,10 @@ Korzystanie z opłaty domyślnej może skutkować wysłaniem transakcji, która
<translation type="unfinished">Zbyt niska opłata może spowodować, że transakcja nigdy nie zostanie zatwierdzona (przeczytaj podpowiedź)</translation>
</message>
<message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source>
+ <translation type="unfinished">(Sprytne opłaty nie są jeszcze zainicjowane. Trwa to zwykle kilka bloków...)</translation>
+ </message>
+ <message>
<source>Confirmation time target:</source>
<translation type="unfinished">Docelowy czas potwierdzenia:</translation>
</message>
@@ -2785,7 +3434,7 @@ Korzystanie z opłaty domyślnej może skutkować wysłaniem transakcji, która
</message>
<message>
<source>Copy amount</source>
- <translation type="unfinished">Kopiuj kwotÄ™</translation>
+ <translation type="unfinished">Kopiuj kwote</translation>
</message>
<message>
<source>Copy fee</source>
@@ -2809,7 +3458,21 @@ Korzystanie z opłaty domyślnej może skutkować wysłaniem transakcji, która
</message>
<message>
<source>%1 (%2 blocks)</source>
- <translation type="unfinished">%1 (%2 bloków)</translation>
+ <translation type="unfinished">%1 (%2 bloków)github.com </translation>
+ </message>
+ <message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">Podpisz na urzÄ…dzeniu</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">Najpierw podłącz swój sprzętowy portfel.</translation>
+ </message>
+ <message>
+ <source>Set external signer script path in Options -&gt; Wallet</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Ustaw ścieżkę zewnętrznego skryptu podpisującego w Opcje -&gt; Portfel</translation>
</message>
<message>
<source>Cr&amp;eate Unsigned</source>
@@ -2825,25 +3488,48 @@ Korzystanie z opłaty domyślnej może skutkować wysłaniem transakcji, która
</message>
<message>
<source>%1 to '%2'</source>
- <translation type="unfinished">%1 do '%2'</translation>
+ <translation type="unfinished">%1 do '%2'8f0451c0-ec7d-4357-a370-eff72fb0685f</translation>
</message>
<message>
<source>%1 to %2</source>
<translation type="unfinished">%1 do %2</translation>
</message>
<message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">Aby przejrzeć listę odbiorców kliknij "Pokaż szczegóły..."</translation>
+ </message>
+ <message>
<source>Sign failed</source>
<translation type="unfinished">Podpisywanie nie powiodło się.</translation>
</message>
<message>
+ <source>External signer not found</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Nie znaleziono zewnętrznego sygnatariusza </translation>
+ </message>
+ <message>
+ <source>External signer failure</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Błąd zewnętrznego sygnatariusza </translation>
+ </message>
+ <message>
<source>Save Transaction Data</source>
<translation type="unfinished">Zapisz dane transakcji</translation>
</message>
<message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">Częściowo podpisana transakcja (binarna)</translation>
+ </message>
+ <message>
<source>PSBT saved</source>
<translation type="unfinished">Zapisano PSBT</translation>
</message>
<message>
+ <source>External balance:</source>
+ <translation type="unfinished">Zewnętrzny balans:</translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">lub</translation>
</message>
@@ -2857,6 +3543,16 @@ Korzystanie z opłaty domyślnej może skutkować wysłaniem transakcji, która
<translation type="unfinished">Proszę przejrzeć propozycję transakcji. Zostanie utworzona częściowo podpisana transakcja (ang. PSBT), którą można skopiować, a następnie podpisać np. offline z portfelem %1 lub z innym portfelem zgodnym z PSBT.</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Czy chcesz utworzyć tę transakcję?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Proszę przejrzeć propozycję transakcji. Zostanie utworzona częściowo podpisana transakcja (ang. PSBT), którą można skopiować, a następnie podpisać np. offline z portfelem %1 lub z innym portfelem zgodnym z PSBT.</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">ProszÄ™, zweryfikuj swojÄ… transakcjÄ™.</translation>
@@ -2909,16 +3605,12 @@ Korzystanie z opłaty domyślnej może skutkować wysłaniem transakcji, która
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Opłata wyższa niż %1 jest uznawana za absurdalnie dużą.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Żądanie płatności upłynęło.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Szacuje się, że potwierdzenie rozpocznie się w %n bloku.</numerusform>
+ <numerusform>Szacuje się, że potwierdzenie rozpocznie się w %n bloków.</numerusform>
+ <numerusform>Szacuje się, że potwierdzenie rozpocznie się w %n bloków.</numerusform>
</translation>
</message>
<message>
@@ -2993,14 +3685,6 @@ Korzystanie z opłaty domyślnej może skutkować wysłaniem transakcji, która
<translation type="unfinished">Wiadomość:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">To żądanie zapłaty nie zostało zweryfikowane.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">To żądanie zapłaty jest zweryfikowane.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Wprowadź etykietę dla tego adresu by dodać go do listy użytych adresów</translation>
</message>
@@ -3008,14 +3692,6 @@ Korzystanie z opłaty domyślnej może skutkować wysłaniem transakcji, która
<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 type="unfinished">Wiadomość, która została dołączona do URI bitcoin:, która będzie przechowywana wraz z transakcją w celach informacyjnych. Uwaga: Ta wiadomość nie będzie rozsyłana w sieci Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Wpłać do:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Notatka:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3178,35 +3854,31 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<source>(press q to shutdown and continue later)</source>
<translation type="unfinished">(naciśnij q by zamknąć i kontynuować póżniej)</translation>
</message>
- </context>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">wciśnij q aby wyłączyć</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">sprzeczny z transakcją posiadającą %1 potwierdzeń</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/niezatwierdzone, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">w obszarze pamięci</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">nie w obszarze pamięci</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">porzucone</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/niezatwierdzone</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 potwierdzeń</translation>
</message>
<message>
@@ -3507,6 +4179,55 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation type="unfinished">Minimalna kwota</translation>
</message>
<message>
+ <source>Range…</source>
+ <translation type="unfinished">Zakres...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">Kopiuj adres</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Kopiuj etykietÄ™</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopiuj kwotÄ™</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">Skopiuj &amp;ID transakcji</translation>
+ </message>
+ <message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">Kopiuj &amp;raw transakcje</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">Skopiuj pełne &amp;detale transakcji</translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">Wyświetl &amp;szczegóły transakcji</translation>
+ </message>
+ <message>
+ <source>Increase transaction &amp;fee</source>
+ <translation type="unfinished">Zwiększ opłatę transakcji</translation>
+ </message>
+ <message>
+ <source>A&amp;bandon transaction</source>
+ <translation type="unfinished">Porzuć transakcję</translation>
+ </message>
+ <message>
+ <source>&amp;Edit address label</source>
+ <translation type="unfinished">Wy&amp;edytuj adres etykiety</translation>
+ </message>
+ <message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Wyświetl w %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Eksport historii transakcji</translation>
</message>
@@ -3517,7 +4238,7 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
</message>
<message>
<source>Confirmed</source>
- <translation type="unfinished">Potwierdzony</translation>
+ <translation type="unfinished">Potwerdzone</translation>
</message>
<message>
<source>Watch-only</source>
@@ -3541,7 +4262,7 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished"> Eksportowanie nie powiodło się </translation>
+ <translation type="unfinished">Eksportowanie nie powiodło się </translation>
</message>
<message>
<source>There was an error trying to save the transaction history to %1.</source>
@@ -3635,6 +4356,10 @@ Przejdź do Plik &gt; Otwórz Portfel aby wgrać portfel.
<translation type="unfinished">Nowa opłata:</translation>
</message>
<message>
+ <source>Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
+ <translation type="unfinished">Ostrzeżenie: Może to spowodować uiszczenie dodatkowej opłaty poprzez zmniejszenie zmian wyjść lub dodanie danych wejściowych, jeśli jest to konieczne. Może dodać nowe wyjście zmiany, jeśli jeszcze nie istnieje. Te zmiany mogą potencjalnie spowodować utratę prywatności.</translation>
+ </message>
+ <message>
<source>Confirm fee bump</source>
<translation type="unfinished">Potwierdź zwiększenie opłaty</translation>
</message>
@@ -3655,6 +4380,10 @@ Przejdź do Plik &gt; Otwórz Portfel aby wgrać portfel.
<translation type="unfinished">Nie można zatwierdzić transakcji</translation>
</message>
<message>
+ <source>Can't display address</source>
+ <translation type="unfinished">Nie można wyświetlić adresu</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">domyślny portfel</translation>
</message>
@@ -3674,6 +4403,11 @@ Przejdź do Plik &gt; Otwórz Portfel aby wgrać portfel.
<translation type="unfinished">Kopia zapasowa portfela</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Informacje portfela</translation>
+ </message>
+ <message>
<source>Backup Failed</source>
<translation type="unfinished">Nie udało się wykonać kopii zapasowej</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pt.ts b/src/qt/locale/bitcoin_pt.ts
index 4e141c66a2..1991ff5eb3 100644
--- a/src/qt/locale/bitcoin_pt.ts
+++ b/src/qt/locale/bitcoin_pt.ts
@@ -165,7 +165,7 @@ Assinar só é possível com endereços do tipo "legado".</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 type="unfinished">Aviso: se encriptar a sua carteira e perder a sua frase de segurnça, &lt;b&gt;PERDERà TODOS OS SEUS BITCOINS&lt;/b&gt;!</translation>
+ <translation type="unfinished">Aviso: se encriptar a sua carteira e perder a sua frase de segurança, &lt;b&gt;PERDERà TODAS AS SUAS BITCOINS&lt;/b&gt;!</translation>
</message>
<message>
<source>Are you sure you wish to encrypt your wallet?</source>
@@ -246,6 +246,10 @@ Assinar só é possível com endereços do tipo "legado".</translation>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">O ficheiro de configurações %1 pode estar corrompido ou inválido.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">Exceção de Runaway</translation>
</message>
@@ -331,6 +335,11 @@ Assinar só é possível com endereços do tipo "legado".</translation>
<translation type="unfinished">Retransmissão de Blocos</translation>
</message>
<message>
+ <source>Feeler</source>
+ <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Antena</translation>
+ </message>
+ <message>
<source>Address Fetch</source>
<extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
<translation type="unfinished">Procura de endreços</translation>
@@ -346,36 +355,36 @@ Assinar só é possível com endereços do tipo "legado".</translation>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n segundo</numerusform>
+ <numerusform>%n segundos</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minuto</numerusform>
+ <numerusform>%n minutos</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n hora</numerusform>
+ <numerusform>%n horas</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n dia</numerusform>
+ <numerusform>%n dias</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n semana</numerusform>
+ <numerusform>%n semanas</numerusform>
</translation>
</message>
<message>
@@ -385,8 +394,8 @@ Assinar só é possível com endereços do tipo "legado".</translation>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n ano</numerusform>
+ <numerusform>%n anos </numerusform>
</translation>
</message>
</context>
@@ -433,10 +442,6 @@ Assinar só é possível com endereços do tipo "legado".</translation>
<translation type="unfinished">Erro: Esta versão do bitcoin-wallet apenas suporta arquivos de despejo na versão 1. (Versão atual: %s)</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Erro: a escuta de ligações de entrada falhou (escuta devolveu o erro %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Falha na estimativa de taxa. A taxa alternativa de recurso está desativada. Espere alguns blocos ou ative -fallbackfee.</translation>
</message>
@@ -630,10 +635,6 @@ deve ser fornecido.</translation>
<translation type="unfinished">Erro ao ler o registo seguinte da base de dados da carteira</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Erro ao atualizar a base de dados do estado da cadeia (chainstate)</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Erro: espaço em disco demasiado baixo para %s</translation>
</message>
@@ -662,6 +663,10 @@ deve ser fornecido.</translation>
<translation type="unfinished">Erro: Não foi possível converter versão %u como uint32_t</translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">Error: Não é possivel ler todos os registros no banco de dados</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
<translation type="unfinished">Erro: Não foi possível escrever registro para a nova carteira</translation>
</message>
@@ -754,12 +759,16 @@ deve ser fornecido.</translation>
<translation type="unfinished">A carregar a carteira…</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Falta a quantia</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">Necessário especificar uma porta com -whitebind: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Sem servidor de proxy especificado. Use -proxy=&lt;ip&gt; ou -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Sem endereços disponíveis</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -770,10 +779,6 @@ deve ser fornecido.</translation>
<translation type="unfinished">A redução não pode ser configurada com um valor negativo.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Modo de poda é incompatível com -coinstatsindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">O modo de redução é incompatível com -txindex.</translation>
</message>
@@ -884,6 +889,10 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">A transação dever pelo menos um destinatário</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">Transação precisa de uma mudança de endereço, mas nós não a podemos gerar.</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">Transação grande demais</translation>
</message>
@@ -940,10 +949,6 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Categoria de registos desconhecida %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">A atualizar a base de dados UTXO</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Comentário no User Agent (%s) contém caracteres inseguros.</translation>
</message>
@@ -1162,8 +1167,8 @@ A pasta de blocos especificados "%s" não existe.</translation>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform> %n bloco processado do histórico de transações.</numerusform>
+ <numerusform> %n blocos processados do histórico de transações.</numerusform>
</translation>
</message>
<message>
@@ -1243,6 +1248,16 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Fechar a carteira</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Restaurar carteira…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Restaurar uma carteira a partir de um ficheiro de cópia de segurança</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Fechar todas carteiras.</translation>
</message>
@@ -1267,6 +1282,26 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Sem carteiras disponíveis</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Dados da carteira</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Carregar cópia de segurança de carteira</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Restaurar carteira</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nome da Carteira</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Janela</translation>
</message>
@@ -1282,12 +1317,20 @@ A pasta de blocos especificados "%s" não existe.</translation>
<source>%1 client</source>
<translation type="unfinished">Cliente %1</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">Ocultar</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">Mo&amp;strar</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n conexão ativa na rede Bitcoin.</numerusform>
+ <numerusform>%n conexões ativas na rede Bitcoin.</numerusform>
</translation>
</message>
<message>
@@ -1311,6 +1354,10 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Activar atividade da rede</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">A pré-sincronizar cabeçalhos (%1%)…</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Erro: %1</translation>
</message>
@@ -1569,6 +1616,10 @@ A pasta de blocos especificados "%s" não existe.</translation>
<source>Can't list signers</source>
<translation type="unfinished">Não é possível listar signatários</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Encontrados demasiados assinantes externos</translation>
+ </message>
</context>
<context>
<name>LoadWalletsActivity</name>
@@ -1609,6 +1660,34 @@ A pasta de blocos especificados "%s" não existe.</translation>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Restaurar carteira</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">A restaurar a carteira &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Falha ao restaurar a carteira</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Aviso de restaurar carteira</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Mensagem de restaurar a carteira</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1783,13 +1862,26 @@ A pasta de blocos especificados "%s" não existe.</translation>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(de %1 GB necessários)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB de espaço disponível</numerusform>
+ <numerusform>%n GB de espaço disponível</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(1%1 GB necessários para a blockchain completa)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(de %n GB necessário)</numerusform>
+ <numerusform>(de %n GB necessários)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB necessário para a cadeia completa)</numerusform>
+ <numerusform>(%n GB necessários para a cadeia completa)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1803,8 +1895,8 @@ A pasta de blocos especificados "%s" não existe.</translation>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(suficiente para restaurar backups de %n dia atrás)</numerusform>
+ <numerusform>(suficiente para restaurar backups de %n dias atrás)</numerusform>
</translation>
</message>
<message>
@@ -1836,10 +1928,6 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Sendo esta a primeira vez que o programa é iniciado, poderá escolher onde o %1 irá guardar os seus dados.</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 type="unfinished">Quando clicar OK, %1 vai começar a descarregar e processar a cadeia de blocos %4 completa (%2GB) começando com as transações mais antigas em %3 quando a %4 foi inicialmente lançada.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Limitar o tamanho da blockchain para</translation>
</message>
@@ -1852,6 +1940,10 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Esta sincronização inicial é muito exigente, e pode expor problemas com o seu computador que previamente podem ter passado despercebidos. Cada vez que corre %1, este vai continuar a descarregar de onde deixou.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Quando clicar em OK, %1 iniciará o download e irá processar a cadeia de blocos completa %4 (%2 GB) iniciando com as transações mais recentes em %3 enquanto %4 é processado. </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 type="unfinished">Se escolheu limitar o armazenamento da cadeia de blocos (poda), a data histórica ainda tem de ser descarregada e processada, mas irá ser apagada no final para manter uma utilização baixa do espaço de disco.</translation>
</message>
@@ -1948,6 +2040,10 @@ A pasta de blocos especificados "%s" não existe.</translation>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Desconhecido. A sincronizar cabeçalhos (%1, %2%)...</translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Desconhecido. Pré-Sincronizando Cabeçalhos (%1, %2%)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -2004,6 +2100,10 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Minimize em vez de sair da aplicação quando a janela é fechada. Quando esta opção é ativada, a aplicação apenas será encerrada quando escolher Sair no menu.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Opções configuradas nessa caixa de diálogo serão sobrescritas pela linhas de comando: </translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Abrir o ficheiro de configuração %1 da pasta aberta.</translation>
</message>
@@ -2041,14 +2141,39 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Tamanho máximo da cache da base de dados. Uma cache maior pode contribuir para uma sincronização mais rápida, a partir do qual os benefícios são menos visíveis. Ao baixar o tamanho da cache irá diminuir a utilização de memória. Memória da mempool não usada será partilhada com esta cache.</translation>
</message>
<message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Define o número de threads do script de verificação. Valores negativos correspondem ao número de núcleos que deseja deixar livres para o sistema.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = automático, &lt;0 = deixar essa quantidade de núcleos livre)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Isto permite-lhe comunicar a si ou a ferramentas de terceiros com o nó através da linha de comandos e comandos JSON-RPC.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Ativar servidor R&amp;PC</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">C&amp;arteira</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Mostrar a quantia com a taxa já subtraída, por padrão.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Subtrair &amp;taxa da quantia por padrão</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">Técnicos</translation>
</message>
@@ -2065,6 +2190,16 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">&amp;Gastar troco não confirmado</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Ativar os controlos &amp;PSBT</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Mostrar os controlos PSBT.</translation>
+ </message>
+ <message>
<source>External Signer (e.g. hardware wallet)</source>
<translation type="unfinished">Signatário externo (ex: carteira física)</translation>
</message>
@@ -2085,6 +2220,10 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Mapear porta usando &amp;UPnP</translation>
</message>
<message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
+ <translation type="unfinished">Abrir a porta do cliente bitcoin automaticamente no seu router. Isto só funciona se o seu router suportar NAT-PMP e este se encontrar ligado. A porta externa poderá ser aleatória.</translation>
+ </message>
+ <message>
<source>Map port using NA&amp;T-PMP</source>
<translation type="unfinished">Mapear porta usando &amp;NAT-PMP</translation>
</message>
@@ -2165,6 +2304,14 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Escolha a unidade da subdivisão predefinida para ser mostrada na interface e quando enviar as moedas.</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 type="unfinished">URLs de outrem (ex. um explorador de blocos) que aparece no separador de transações como itens do menu de contexto. %s do URL é substituído pela hash de transação. Múltiplos URLs são separados pela barra vertical I.</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">URLs de transação de &amp;terceiros</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">Escolha se deve mostrar as funcionalidades de controlo de moedas ou não.</translation>
</message>
@@ -2181,8 +2328,12 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Fonte no painel de visualização:</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">As opções nesta janela são substituídas pela linha de comandos ou no ficheiro de configuração:</translation>
+ <source>embedded "%1"</source>
+ <translation type="unfinished">embutido "%1"</translation>
+ </message>
+ <message>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">resultado mais aproximado "%1"</translation>
</message>
<message>
<source>&amp;Cancel</source>
@@ -2203,14 +2354,22 @@ A pasta de blocos especificados "%s" não existe.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirme a reposição das opções</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">É necessário reiniciar o cliente para ativar as alterações.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Configuração atuais serão copiadas em "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">O cliente será desligado. Deseja continuar?</translation>
</message>
<message>
@@ -2224,6 +2383,10 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">O ficheiro de configuração é usado para especificar opções de utilizador avançado, que sobrescrevem as configurações do interface gráfico. Adicionalmente, qualquer opção da linha de comandos vai sobrescrever este ficheiro de configuração.</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">Continuar</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">Cancelar</translation>
</message>
@@ -2245,6 +2408,13 @@ A pasta de blocos especificados "%s" não existe.</translation>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Não foi possível ler as configurações "%1", %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2354,6 +2524,10 @@ A pasta de blocos especificados "%s" não existe.</translation>
<translation type="unfinished">Falha ao assinar transação: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">Não é possível assinar entradas enquanto a carteira está trancada.</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">Não pode assinar mais nenhuma entrada.</translation>
</message>
@@ -2428,6 +2602,10 @@ ID transação: %1</translation>
<translation type="unfinished">Transação continua precisando de assinatura(s).</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Mas nenhuma carteira está carregada)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Porém esta carteira não pode assinar transações.)</translation>
</message>
@@ -2463,6 +2641,14 @@ ID transação: %1</translation>
<translation type="unfinished">'bitcoin://' não é um URI válido. Utilize 'bitcoin:'.</translation>
</message>
<message>
+ <source>Cannot process payment request because BIP70 is not supported.
+Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
+If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
+ <translation type="unfinished">Não é possível processar o pagamento pedido porque o BIP70 não é suportado.
+Devido a falhas de segurança no BIP70, é recomendado que todas as instruçÅes ao comerciante para mudar de carteiras sejam ignorada.
+Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI compatível com BIP21.</translation>
+ </message>
+ <message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<translation type="unfinished">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>
@@ -2484,6 +2670,11 @@ ID transação: %1</translation>
<translation type="unfinished">Par</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">idade</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Direção</translation>
@@ -2663,6 +2854,10 @@ ID transação: %1</translation>
<translation type="unfinished">Blocos Sincronizados</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Última Transação</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">O sistema autónomo mapeado usado para diversificar a seleção de pares.</translation>
</message>
@@ -2671,6 +2866,36 @@ ID transação: %1</translation>
<translation type="unfinished">Mapeado como</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Endereços são retransmitidos para este nó.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Retransmissão de endereços</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">O número total de endereços recebidos deste peer que foram processados (exclui endereços que foram descartados devido à limitação de taxa).</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">O número total de endereços recebidos deste peer que não foram processados devido à limitação da taxa.</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Endereços Processados</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Endereços com limite de taxa</translation>
+ </message>
+ <message>
<source>Node window</source>
<translation type="unfinished">Janela do nó</translation>
</message>
@@ -2842,6 +3067,11 @@ ID transação: %1</translation>
<translation type="unfinished">1 &amp;ano</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Copiar IP/Netmask</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Desbanir</translation>
</message>
@@ -3200,6 +3430,14 @@ Para mais informação acerca da utilização desta consola, escreva %6.
<translation type="unfinished">Esconder configurações de taxas de transação</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 rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation type="unfinished">Especifique uma taxa personalizada por kB (1.000 bytes) do tamanho virtual da transação.
+
+Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para um tamanho de transação de 500 bytes virtuais (metade de 1 kvB) resultaria em uma taxa de apenas 50 satoshis.</translation>
+ </message>
+ <message>
<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">Quando o volume de transações é maior que o espaço nos blocos, os mineradores, bem como os nós de retransmissão, podem impor uma taxa mínima. Pagar apenas esta taxa mínima é muito bom, mas esteja ciente que isso pode resultar numa transação nunca confirmada, uma vez que há mais pedidos para transações do que a rede pode processar.</translation>
</message>
@@ -3245,7 +3483,7 @@ Para mais informação acerca da utilização desta consola, escreva %6.
</message>
<message>
<source>Copy amount</source>
- <translation type="unfinished">Copiar quantia</translation>
+ <translation type="unfinished">Copiar valor</translation>
</message>
<message>
<source>Copy fee</source>
@@ -3281,6 +3519,11 @@ Para mais informação acerca da utilização desta consola, escreva %6.
<translation type="unfinished">Por favor conecte a sua wallet física primeiro.</translation>
</message>
<message>
+ <source>Set external signer script path in Options -&gt; Wallet</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Defina o caminho do script do assinante externo em Opções -&gt; Carteira</translation>
+ </message>
+ <message>
<source>Cr&amp;eate Unsigned</source>
<translation type="unfinished">Criar não assinado</translation>
</message>
@@ -3349,6 +3592,16 @@ Para mais informação acerca da utilização desta consola, escreva %6.
<translation type="unfinished">Por favor, reveja sua proposta de transação. Isto irá produzir uma Transação de Bitcoin parcialmente assinada (PSBT, sigla em inglês) a qual você pode salvar ou copiar e então assinar com por exemplo uma carteira %1 offiline ou uma PSBT compatível com carteira de hardware.</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Deseja criar esta transação?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Por favor, revise sua transação. Você pode assinar e enviar a transação ou criar uma Transação de Bitcoin Parcialmente Assinada (PSBT), que você pode copiar e assinar com, por exemplo, uma carteira %1 offline ou uma carteira física compatível com PSBT.</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Por favor, reveja a sua transação.</translation>
@@ -3401,15 +3654,11 @@ Para mais informação acerca da utilização desta consola, escreva %6.
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Uma taxa superior a %1 é considerada uma taxa altamente absurda.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Pedido de pagamento expirado.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Confirmação estimada para iniciar em %n bloco.</numerusform>
+ <numerusform>Confirmação estimada para iniciar em %n blocos.</numerusform>
</translation>
</message>
<message>
@@ -3484,14 +3733,6 @@ Para mais informação acerca da utilização desta consola, escreva %6.
<translation type="unfinished">Mensagem:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Pedido de pagamento não autenticado.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Pedido de pagamento autenticado.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Introduza uma etiqueta para este endereço para o adicionar à sua lista de endereços usados</translation>
</message>
@@ -3499,14 +3740,6 @@ Para mais informação acerca da utilização desta consola, escreva %6.
<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 type="unfinished">Uma mensagem que estava anexada ao URI bitcoin: que será armazenada com a transação para sua referência. Nota: Esta mensagem não será enviada através da rede Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Pagar a:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Memorando:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3663,33 +3896,46 @@ Para mais informação acerca da utilização desta consola, escreva %6.
</message>
</context>
<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished">(tecle q para desligar e continuar mais tarde)</translation>
+ </message>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">Carregue q para desligar</translation>
+ </message>
+</context>
+<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">incompatível com uma transação com %1 confirmações</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/não confirmada, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">no banco de memória</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/não confirmada, no memory pool</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">não está no banco de memória</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/não confirmada, ausente no memory pool</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">abandonada</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/não confirmada</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 confirmações</translation>
</message>
<message>
@@ -3739,8 +3985,8 @@ Para mais informação acerca da utilização desta consola, escreva %6.
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>pronta em mais %n bloco</numerusform>
+ <numerusform>prontas em mais %n blocos</numerusform>
</translation>
</message>
<message>
@@ -4013,10 +4259,35 @@ Para mais informação acerca da utilização desta consola, escreva %6.
<translation type="unfinished">Copiar Id. da transação</translation>
</message>
<message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">Copiar &amp;transação bruta</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">Copie toda a transação &amp;details</translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">Mo&amp;strar detalhes da transação</translation>
+ </message>
+ <message>
+ <source>Increase transaction &amp;fee</source>
+ <translation type="unfinished">Aumentar &amp;taxa da transação</translation>
+ </message>
+ <message>
+ <source>A&amp;bandon transaction</source>
+ <translation type="unfinished">A&amp;bandonar transação</translation>
+ </message>
+ <message>
<source>&amp;Edit address label</source>
<translation type="unfinished">&amp;Editar etiqueta do endereço</translation>
</message>
<message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Mostrar em %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Exportar Histórico de Transações</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts
index c531a992a2..024652c5a6 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 type="unfinished">Clique com o botão direito para editar endereço ou etiqueta</translation>
+ <translation type="unfinished">Clique com o botão direito para editar o endereço ou a etiqueta</translation>
</message>
<message>
<source>Create a new address</source>
@@ -35,7 +35,7 @@
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation type="unfinished">Exportar os dados do separador atual para um ficheiro</translation>
+ <translation type="unfinished">Exportar os dados do separador atual para um arquivo</translation>
</message>
<message>
<source>&amp;Export</source>
@@ -43,7 +43,7 @@
</message>
<message>
<source>&amp;Delete</source>
- <translation type="unfinished">&amp;Excluir</translation>
+ <translation type="unfinished">E&amp;xcluir</translation>
</message>
<message>
<source>Choose the address to send coins to</source>
@@ -246,6 +246,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Arquivos de configurações %1 podem estar corrompidos ou inválidos</translation>
+ </message>
+ <message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
<translation type="unfinished">Aconteceu um erro fatal. %1 não pode continuar com segurança e será fechado.</translation>
</message>
@@ -295,6 +299,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Informe um endereço Bitcoin (ex: %1)</translation>
</message>
<message>
+ <source>Ctrl+W</source>
+ <translation type="unfinished">Control+W</translation>
+ </message>
+ <message>
<source>Inbound</source>
<extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
<translation type="unfinished">Entrada</translation>
@@ -311,36 +319,36 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n segundo</numerusform>
+ <numerusform>%n segundos</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minuto</numerusform>
+ <numerusform>%n minutos</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n hora</numerusform>
+ <numerusform>%n horas</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n dia</numerusform>
+ <numerusform>%n dias</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n semana</numerusform>
+ <numerusform>%n semanas</numerusform>
</translation>
</message>
<message>
@@ -350,8 +358,8 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n ano</numerusform>
+ <numerusform>%nanos </numerusform>
</translation>
</message>
</context>
@@ -390,8 +398,8 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Erro ao ler arquivo %s! Todas as chaves privadas foram lidas corretamente, mas os dados de transação ou o livro de endereços podem estar faltando ou incorretos.</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Erro: A escuta de conexões de entrada falhou (vincular retornou erro %s)</translation>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">Erro ao ler %s! Dados de transações podem estar incorretos ou faltando. Reescaneando a carteira.</translation>
</message>
<message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
@@ -402,6 +410,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Valor inválido para -maxtxfee=&lt;valor&gt;: '%s' (precisa ser pelo menos a taxa de minrelay de %s para prevenir que a transação nunca seja confirmada)</translation>
</message>
<message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">O arquivo peers.dat (%s) está corrompido ou inválido. Se você acredita se tratar de um bug, por favor reporte para %s. Como solução, você pode mover, renomear ou deletar (%s) para um novo ser criado na próxima inicialização</translation>
+ </message>
+ <message>
<source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
<translation type="unfinished">Mais de um endereço onion associado é fornecido. Usando %s para automaticamento criar serviço onion Tor.</translation>
</message>
@@ -418,6 +430,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Configuração de prune abaixo do mínimo de %d MiB.Por gentileza use um número mais alto.</translation>
</message>
<message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">O modo Prune é incompatível com a opção "-reindex-chainstate". Ao invés disso utilize "-reindex".</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 type="unfinished">Prune: A ultima sincronização da carteira foi além dos dados podados. Você precisa usar -reindex (fazer o download de toda a blockchain novamente no caso de nós com prune)</translation>
</message>
@@ -430,6 +446,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">O banco de dados de blocos contém um bloco que parece ser do futuro. Isso pode ser devido à data e hora do seu computador estarem configuradas incorretamente. Apenas reconstrua o banco de dados de blocos se você estiver certo de que a data e hora de seu computador estão corretas.</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">O banco de dados de índices de bloco contém um 'txindex' antigo. Faça um -reindex completo para liberar espaço em disco, se desejar. Este erro não será exibido novamente.</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished">A quantia da transação é muito pequena para mandar depois de deduzida a taxa</translation>
</message>
@@ -462,6 +482,14 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Não é possível reproduzir blocos. Você precisará reconstruir o banco de dados usando -reindex-chainstate.</translation>
</message>
<message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">Formato de banco de dados incompatível na chainstate. Por favor reinicie com a opção "-reindex-chainstate". Isto irá recriar o banco de dados da chainstate.</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Carteira criada com sucesso. As carteiras antigas estão sendo descontinuadas e o suporte para a criação de abertura de carteiras antigas será removido no futuro.</translation>
+ </message>
+ <message>
<source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
<translation type="unfinished">Aviso: Chaves privadas detectadas na carteira {%s} com chaves privadas desativadas</translation>
</message>
@@ -494,6 +522,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Não foi possível encontrar o endereço de -%s: '%s'</translation>
</message>
<message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">Não é possível definir -forcednsseed para true quando -dnsseed for false.</translation>
+ </message>
+ <message>
<source>Cannot set -peerblockfilters without -blockfilterindex.</source>
<translation type="unfinished">Não pode definir -peerblockfilters sem -blockfilterindex.</translation>
</message>
@@ -502,6 +534,98 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Não foi possível escrever no diretório '%s': verifique as permissões.</translation>
</message>
<message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">O processo de atualização do -txindex iniciado por uma versão anterior não foi concluído. Reinicie com a versão antiga ou faça um -reindex completo.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s solicitou abertura da porta %u. Esta porta é considerada "ruim" e é improvável que outros usuários do Bitcoin Core conseguirão se conectar. Veja doc/p2p-bad-ports.md para detalhes e uma lista completa.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">a opção "-reindex-chainstate" não é compatível com "-blockfilterindex". Por favor, desabilite temporariamente a opção "blockfilterindex" enquanto utilizar a opção "-reindex-chainstate", ou troque "-reindex-chainstate" por "-reindex" para recriar completamente todos os índices. </translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">a opção "-reindex-chainstate" não é compatível com a opção "-coinstatsindex". Por favor desative temporariamente a opção "coinstatsindex" enquanto estiver utilizando "-reindex-chainstate", ou troque "-reindex-chainstate" por "-reindex" para recriar completamente todos os índices.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">a opção "-reindex-chainstate" não é compatível com a opção "-coinstatsindex". Por favor desative temporariamente a opção "coinstatsindex" enquanto estiver utilizando "-reindex-chainstate", ou troque "-reindex-chainstate" por "-reindex" para recriar completamente todos os índices.</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">Assumed-valid: a ultima sincronização da carteira foi além dos blocos de dados disponíveis. Você deve aguardar que a validação em segundo plano baixe mais blocos. </translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Não é possível fornecer conexões específicas e ter addrman procurando conexões ao mesmo tempo.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Erro ao abrir %s: Carteira com assinador externo. Não foi compilado suporte para assinadores externos</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Erro: Os dados do livro de endereços da carteira não puderam ser identificados por pertencerem a carteiras migradas</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">Erro: Descritores duplicados criados durante a migração. Sua carteira pode estar corrompida.</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Erro: A transação %s na carteira não pôde ser identificada por pertencer a carteiras migradas</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">Erro: Impossível produzir descritores para esta carteira antiga. Certifique-se que a carteira foi desbloqueada antes</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Impossível renomear o arquivo peers.dat (inválido). Por favor mova-o ou delete-o e tente novamente.</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">Opções incompatíveis: "-dnsseed=1" foi explicitamente específicada, mas "-onlynet" proíbe conexões para IPv4/IPv6</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">As conexões de saída foram restringidas a rede Tor (-onlynet-onion) mas o proxy para alcançar a rede Tor foi explicitamente proibido: "-onion=0"</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">As conexões de saída foram restringidas a rede Tor (-onlynet=onion) mas o proxy para acessar a rede Tor não foi fornecido: nenhuma opção "-proxy", "-onion" ou "-listenonion" foi fornecida</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">Descriptor não reconhecido foi encontrado. Carregando carteira %s
+
+A carteira pode ter sido criada em uma versão mais nova.
+Por favor tente atualizar o software para a última versão.
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">Categoria especificada no nível de log não suportada "-loglevel=%s". Esperado "-loglevel=&lt;category&gt;:&lt;loglevel&gt;. Categorias validas: %s. Níveis de log válidos: %s.</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+Impossível limpar a falha de migração</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Impossível restaurar backup da carteira.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">A configuração %s somente é aplicada na rede %s quando na sessão [%s].</translation>
</message>
@@ -566,18 +690,58 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Erro ao ler o banco de dados. Encerrando.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Erro ao atualizar banco de dados do chainstate</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">Erro: impossível adicionar tx apenas-visualização para carteira apenas-visualização</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">Erro: Impossível excluir transações apenas-visualização </translation>
</message>
<message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Erro: Espaço em disco menor que %s</translation>
</message>
<message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">Erro: Falha ao criar carteira apenas-visualização</translation>
+ </message>
+ <message>
<source>Error: Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished">Keypool exaurida, por gentileza execute keypoolrefill primeiro</translation>
</message>
<message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">Erro: Nem todos os txs apenas-visualização foram excluídos</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">Erro: Essa carteira já utiliza o SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">Erro: Esta carteira já contém um descritor</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">Erro: impossível ler todos os registros no banco de dados</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">Erro: Impossível efetuar backup da carteira</translation>
+ </message>
+ <message>
+ <source>Error: Unable to parse version %u as a uint32_t</source>
+ <translation type="unfinished">Erro: Impossível analisar versão %u como uint32_t</translation>
+ </message>
+ <message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">Erro: Impossível ler todos os registros no banco de dados</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">Erro: Impossível remover dados somente-visualização do Livro de Endereços </translation>
+ </message>
+ <message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation type="unfinished">Falha ao escutar em qualquer porta. Use -listen=0 se você quiser isso.</translation>
</message>
@@ -610,6 +774,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">O teste de integridade de inicialização falhou. O %s está sendo desligado.</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Entrada não encontrada ou já gasta</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">Saldo insuficiente</translation>
</message>
@@ -646,6 +814,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Máscara de rede especificada em -whitelist: '%s' é inválida</translation>
</message>
<message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">A espera por conexões de entrada falharam (a espera retornou o erro %s)</translation>
+ </message>
+ <message>
<source>Loading P2P addresses…</source>
<translation type="unfinished">Carregando endereços P2P...</translation>
</message>
@@ -662,12 +834,20 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Carregando carteira...</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Faltando quantia</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">Não há dados suficientes para estimar o tamanho da transação</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">Necessário informar uma porta com -whitebind: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Nenhum servidor proxy especificado. Use -proxy=&lt;ip&gt; ou proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Nenhum endereço disponível</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -678,10 +858,6 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">O modo prune não pode ser configurado com um valor negativo.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">O modo prune é incompatível com -txindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">O modo prune é incompatível com -txindex.</translation>
</message>
@@ -778,6 +954,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">As quantidades nas transações não podem ser negativas.</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">Endereço de troco da transação fora da faixa</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">A transação demorou muito na memória</translation>
</message>
@@ -786,10 +966,18 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">A transação deve ter ao menos um destinatário</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">Transação necessita de um endereço de troco, mas não conseguimos gera-lo. </translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">Transação muito grande</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">Impossível alocar memória para a opção "-maxsigcachesize: '%s' MiB</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation type="unfinished">Erro ao vincular em %s neste computador (bind retornou erro %s)</translation>
</message>
@@ -802,6 +990,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Não foi possível criar arquivo de PID '%s': %s</translation>
</message>
<message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">Impossível localizar e entrada externa UTXO</translation>
+ </message>
+ <message>
<source>Unable to generate initial keys</source>
<translation type="unfinished">Não foi possível gerar as chaves iniciais</translation>
</message>
@@ -810,10 +1002,18 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Não foi possível gerar chaves</translation>
</message>
<message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">Impossível analisar -maxuploadtarget: '%s'</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">Não foi possível iniciar o servidor HTTP. Veja o log de depuração para detaihes.</translation>
</message>
<message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">Impossível desconectar carteira antes de migrá-la</translation>
+ </message>
+ <message>
<source>Unknown -blockfilterindex value %s.</source>
<translation type="unfinished">Valor do parâmetro -blockfilterindex desconhecido %s.</translation>
</message>
@@ -830,12 +1030,12 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Rede desconhecida especificada em -onlynet: '%s'</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">Categoria de log desconhecida %s=%s.</translation>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">Nível de log global inválido "-loglevel=%s". Valores válidos: %s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Atualizando banco de dados UTXO</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Categoria de log desconhecida %s=%s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
@@ -1056,8 +1256,8 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n bloco processado do histórico de transações.</numerusform>
+ <numerusform>%n blocos processados do histórico de transações.</numerusform>
</translation>
</message>
<message>
@@ -1094,7 +1294,7 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
</message>
<message>
<source>Load Partially Signed Bitcoin Transaction</source>
- <translation type="unfinished">Carregar Transação de Bitcoin Parcialmente Assinada</translation>
+ <translation type="unfinished">Carregar</translation>
</message>
<message>
<source>Load PSBT from &amp;clipboard…</source>
@@ -1137,6 +1337,16 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Fechar carteira</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Restaurar Carteira...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Restaurar uma carteira a partir de um arquivo de backup</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Fechar todas as carteiras</translation>
</message>
@@ -1161,6 +1371,21 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Nenhuma carteira disponível</translation>
</message>
<message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Carregar Backup da Carteira</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Restaurar Carteira</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Nome da Carteira</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Janelas</translation>
</message>
@@ -1178,18 +1403,18 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
</message>
<message>
<source>&amp;Hide</source>
- <translation type="unfinished">&amp;Esconder</translation>
+ <translation type="unfinished">E&amp;sconder</translation>
</message>
<message>
<source>S&amp;how</source>
- <translation type="unfinished">S&amp;como</translation>
+ <translation type="unfinished">Mo&amp;strar</translation>
</message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n conexão ativa na rede Bitcoin.</numerusform>
+ <numerusform>%nconexões ativas na rede Bitcoin.</numerusform>
</translation>
</message>
<message>
@@ -1200,7 +1425,7 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<message>
<source>Show Peers tab</source>
<extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
- <translation type="unfinished">Mostrar abas De pares.</translation>
+ <translation type="unfinished">Mostra aba de Pares</translation>
</message>
<message>
<source>Disable network activity</source>
@@ -1213,6 +1438,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Ativar atividade de conexões</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Pré-Sincronizando cabeçalhos (%1%)...</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Erro: %1</translation>
</message>
@@ -1447,7 +1676,11 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<source>Create wallet warning</source>
<translation type="unfinished">Criar carteira alerta</translation>
</message>
- </context>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Encontrados muitos assinantes externos</translation>
+ </message>
+</context>
<context>
<name>LoadWalletsActivity</name>
<message>
@@ -1487,6 +1720,34 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Restaurar Carteira</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Restaurando Carteira &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Falha ao restaurar carteira</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Aviso ao restaurar carteira</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Mensagem da carteira restaurada</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1648,17 +1909,26 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
</context>
<context>
<name>Intro</name>
- <message>
- <source>%1 GB of space available</source>
- <translation type="unfinished">%1 GB de espaço disponível</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB de espaço disponível</numerusform>
+ <numerusform>%n GB de espaço disponível</numerusform>
+ </translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(de %1 GB necessário)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(de %n GB necessário)</numerusform>
+ <numerusform>(de %n GB necessários)</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB necessário para a blockchain completa)</translation>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB necessário para a cadeia completa)</numerusform>
+ <numerusform>(%n GB necessários para a cadeia completa)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1672,8 +1942,8 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(suficiente para restaurar backup de %n dia atrás)</numerusform>
+ <numerusform>(suficiente para restaurar backups de %n dias atrás)</numerusform>
</translation>
</message>
<message>
@@ -1705,10 +1975,6 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Como essa é a primeira vez que o programa é executado, você pode escolher onde %1 armazenará seus dados.</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 type="unfinished">Quando você clica OK, %1 vai começar a baixar e processar todos os %4 da block chain (%2GB) começando com a mais recente transação em %3 quando %4 inicialmente foi lançado.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Limitar o tamanho da blockchain para</translation>
</message>
@@ -1725,6 +1991,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Esta sincronização inicial é muito exigente e pode expor problemas de hardware com o computador que passaram despercebidos anteriormente. Cada vez que você executar o %1, irá continuar baixando de onde parou.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Quando clicar em OK, %1 iniciará o download e irá processar a cadeia de blocos completa %4 (%2 GB) iniciando com as mais recentes transações em %3 enquanto %4 é processado. </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 type="unfinished">Se você escolheu limitar o armazenamento da block chain (prunando), os dados históricos ainda devem ser baixados e processados, mas serão apagados no final para manter o uso de disco baixo.</translation>
</message>
@@ -1817,6 +2087,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Desconhecido. Sincronizando cabeçalhos (%1, %2%)...</translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Desconhecido. Pré-Sincronizando Cabeçalhos (%1, %2%)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -1869,6 +2143,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Minimizar em vez de fechar o programa quando a janela for fechada. Quando essa opção estiver ativa, o programa só será fechado somente pela opção Sair no menu Arquivo.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Opções configuradas nessa caixa de diálogo serão sobrescritas pela linhas de comando: </translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Abrir o arquivo de configuração %1 apartir do diretório trabalho.</translation>
</message>
@@ -1897,10 +2175,25 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Reverter esta configuração requer baixar de novo a blockchain inteira.</translation>
</message>
<message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">Tamanho máximo do cache do banco de dados. Um cache maior pode contribuir para uma sincronização mais rápida, após a qual o benefício é menos pronunciado para a maioria dos casos de uso. Reduzir o tamanho do cache reduzirá o uso de memória. A memória do mempool não utilizada é compartilhada para este cache.</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Define o número de threads para script de verificação. Valores negativos correspondem ao número de núcleos que você quer deixar livre para o sistema.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = automático, &lt;0 = número de núcleos deixados livres)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Isso permite que você ou ferramentas de terceiros comunique-se com o node através de linha de comando e comandos JSON-RPC.</translation>
+ </message>
+ <message>
<source>Enable R&amp;PC server</source>
<extracomment>An Options window setting to enable the RPC server.</extracomment>
<translation type="unfinished">Ative servidor R&amp;PC</translation>
@@ -1910,6 +2203,11 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">C&amp;arteira</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Mostra a quantia com a taxa já subtraída.</translation>
+ </message>
+ <message>
<source>Subtract &amp;fee from amount by default</source>
<extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
<translation type="unfinished">Subtrair &amp;taxa da quantia por padrão</translation>
@@ -1936,6 +2234,11 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Ative controles &amp;PSBT</translation>
</message>
<message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Mostrar os controles de PSBT (Transação de Bitcoin Parcialmente Assinada).</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 type="unfinished">Abrir automaticamente no roteador as portas do cliente Bitcoin. Isto só funcionará se seu roteador suportar UPnP e esta função estiver habilitada.</translation>
</message>
@@ -2012,6 +2315,14 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Escolha a unidade de subdivisão padrão para exibição na interface ou quando enviando moedas.</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 type="unfinished">URLs de terceiros (exemplo: explorador de blocos) que aparecem na aba de transações como itens do menu de contexto. %s na URL é substituido pela hash da transação. Múltiplas URLs são separadas pela barra vertical |.</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">URLs de transação de &amp;terceiros</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">Mostrar ou não opções de controle da moeda.</translation>
</message>
@@ -2028,10 +2339,6 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Fonte no painel de visualização:</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Opções nesta tela foram sobreescritas por comandos ou no arquivo de configuração:</translation>
- </message>
- <message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Cancelar</translation>
</message>
@@ -2045,14 +2352,22 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirmar redefinição de opções</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Reinicialização do aplicativo necessária para efetivar alterações.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Configuração atuais serão copiadas em "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">O programa será encerrado. Deseja continuar?</translation>
</message>
<message>
@@ -2087,6 +2402,13 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Não foi possível ler as configurações "%1", %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2196,6 +2518,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Falhou ao assinar transação: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">Não é possível assinar entradas enquanto a carteira está trancada.</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">Não foi possível assinar mais nenhuma entrada.</translation>
</message>
@@ -2319,6 +2645,11 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Nós</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Ano</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Direção</translation>
@@ -2502,17 +2833,43 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
</message>
<message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
- <translation type="unfinished">O sistema autônomo delineado usado para a diversificação de seleção de nós.</translation>
+ <translation type="unfinished">O sistema autônomo de mapeamento usado para a diversificação de seleção de nós.</translation>
</message>
<message>
<source>Mapped AS</source>
<translation type="unfinished">Mapeado como</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Endereços são retransmitidos para este nó.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Retransmissão de endereços</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">O número total de endereços recebidos deste peer que foram processados (exclui endereços que foram descartados devido à limitação de taxa).</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">O número total de endereços recebidos deste peer que não foram processados devido à limitação da taxa.</translation>
+ </message>
+ <message>
<source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
<translation type="unfinished">Endereços Processados</translation>
</message>
<message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Endereços com limite de taxa</translation>
+ </message>
+ <message>
<source>Node window</source>
<translation type="unfinished">Janela do Nó</translation>
</message>
@@ -2541,6 +2898,10 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Serviços</translation>
</message>
<message>
+ <source>Whether the peer requested us to relay transactions.</source>
+ <translation type="unfinished">O nó solicita retransmissão de transações.</translation>
+ </message>
+ <message>
<source>Connection Time</source>
<translation type="unfinished">Tempo de conexão</translation>
</message>
@@ -2638,6 +2999,22 @@ Somente é possível assinar com endereços do tipo 'legado'.</translation>
<translation type="unfinished">Executando comando sem nenhuma carteira</translation>
</message>
<message>
+ <source>Ctrl+I</source>
+ <translation type="unfinished">Control+I</translation>
+ </message>
+ <message>
+ <source>Ctrl+T</source>
+ <translation type="unfinished">Control+T</translation>
+ </message>
+ <message>
+ <source>Ctrl+N</source>
+ <translation type="unfinished">Control+N</translation>
+ </message>
+ <message>
+ <source>Ctrl+P</source>
+ <translation type="unfinished">Control+P</translation>
+ </message>
+ <message>
<source>Executing command using "%1" wallet</source>
<translation type="unfinished">Executando comando usando a carteira "%1"</translation>
</message>
@@ -3041,7 +3418,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
</message>
<message>
<source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
- <translation type="unfinished">Cria uma Transação de Bitcoin Parcialmente Assinada (PSBT) para usar com ex: uma carteira %1 offline, ou uma PSBT-compatível hardware wallet.</translation>
+ <translation type="unfinished">Cria uma Transação de Bitcoin Parcialmente Assinada (PSBT) para usar com, por exemplo, uma carteira %1 offline ou uma carteira física compatível com PSBTs.</translation>
</message>
<message>
<source> from wallet '%1'</source>
@@ -3082,7 +3459,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
<message>
<source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment>
- <translation type="unfinished">Por favor, reveja sua proposta de transação. Será produzido uma Transação de Bitcoin Parcialmente Assinada (PSBT) que você pode copiar e assinar com ex: uma carteira %1 offline, ou uma PSBT-compatível hardware wallet.</translation>
+ <translation type="unfinished">Por favor, revise a transação. Será produzido uma Transação de Bitcoin Parcialmente Assinada (PSBT) que você pode copiar e assinar com, por exemplo, uma carteira %1 offline, ou uma carteira física compatível com PSBTs.</translation>
</message>
<message>
<source>Do you want to create this transaction?</source>
@@ -3090,6 +3467,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
<translation type="unfinished">Deseja criar esta transação?</translation>
</message>
<message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Por favor, revise a transação. Você pode assinar e enviar a transação ou criar uma Transação de Bitcoin Parcialmente Assinada (PSBT), que você pode copiar e assinar com, por exemplo, uma carteira %1 offline ou uma carteira física compatível com PSBTs.</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Revise a sua transação.</translation>
@@ -3142,15 +3524,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Uma taxa maior que %1 é considerada uma taxa absurdamente alta.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Pedido de pagamento expirado.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Confirmação estimada para iniciar em %n bloco.</numerusform>
+ <numerusform>Confirmação estimada para iniciar em %n blocos.</numerusform>
</translation>
</message>
<message>
@@ -3225,14 +3603,6 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
<translation type="unfinished">Mensagem:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Esta é uma cobrança não autenticada.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Esta é uma cobrança autenticada.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Digite um rótulo para este endereço para adicioná-lo no catálogo</translation>
</message>
@@ -3240,14 +3610,6 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
<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 type="unfinished">A mensagem que foi anexada ao bitcoin: URI na qual será gravada na transação para sua referência. Nota: Essa mensagem não será gravada publicamente na rede Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Pague Para:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Memorizar:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3418,30 +3780,32 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">conflitado com uma transação com %1 confirmações</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/não confirmado, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">no pool de memória</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/não confirmada, na memória</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">não está no pool de memóra</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/não confirmada, fora da memória</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">abandonado</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/não confirmado</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 confirmações</translation>
</message>
<message>
@@ -3487,8 +3851,8 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>pronta em mais %n bloco</numerusform>
+ <numerusform>prontas em mais %n blocos</numerusform>
</translation>
</message>
<message>
@@ -3671,7 +4035,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
</message>
<message>
<source>Whether or not a watch-only address is involved in this transaction.</source>
- <translation type="unfinished">Mostrar ou não endereços monitorados na lista de transações.</translation>
+ <translation type="unfinished">Se um endereço monitorado está envolvido nesta transação.</translation>
</message>
<message>
<source>User-defined intent/purpose of the transaction.</source>
@@ -3741,6 +4105,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para
<translation type="unfinished">Alcance...</translation>
</message>
<message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Mostrar em %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Exportar histórico de transações</translation>
</message>
@@ -3832,7 +4201,7 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Unable to decode PSBT</source>
- <translation type="unfinished">Não foi possível decodificar PSDBT</translation>
+ <translation type="unfinished">Não foi possível decodificar PSBT</translation>
</message>
</context>
<context>
diff --git a/src/qt/locale/bitcoin_ro.ts b/src/qt/locale/bitcoin_ro.ts
index 714a317449..8fa1d6a393 100644
--- a/src/qt/locale/bitcoin_ro.ts
+++ b/src/qt/locale/bitcoin_ro.ts
@@ -239,6 +239,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Fișierul de configurări %1 poate fi corupt sau invalid.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">Excepție de fugă</translation>
</message>
@@ -383,10 +387,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<translation type="unfinished">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>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Eroare: Ascultarea conexiunilor de intrare nu a reuÅŸit (ascultarea a reurnat eroarea %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Estimarea taxei a esuat. Taxa implicita este dezactivata. Asteptati cateva blocuri, sau activati -fallbackfee.</translation>
</message>
@@ -519,10 +519,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<translation type="unfinished">Eroare la citirea bazei de date. Oprire.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Eroare la actualizarea bazei de date chainstate</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Eroare: Spațiul pe disc este redus pentru %s</translation>
</message>
@@ -687,10 +683,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<translation type="unfinished">Categoria de logging %s=%s nu este suportata.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Actualizarea bazei de date UTXO</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Comentariul (%s) al Agentului Utilizator contine caractere nesigure.</translation>
</message>
@@ -999,6 +991,11 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<translation type="unfinished">Niciun portofel disponibil</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Numele portofelului</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Fereastră</translation>
</message>
@@ -1424,6 +1421,30 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(din %n GB necesar)</numerusform>
+ <numerusform>(din %n GB necesari)</numerusform>
+ <numerusform>(din %n GB necesari)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Cel putin %1GB de date vor fi stocate in acest director, si aceasta valoare va creste in timp.</translation>
@@ -1470,10 +1491,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<translation type="unfinished">Deoarece este prima lansare a programului poți alege unde %1 va stoca datele sale.</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 type="unfinished">Cand apasati OK, %1 va incepe descarcarea si procesarea intregului %4 blockchain (%2GB) incepand cu cele mai vechi tranzactii din %3 de la lansarea initiala a %4.</translation>
- </message>
- <message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">Revenirea la această setare necesită re-descărcarea întregului blockchain. Este mai rapid să descărcați mai întâi rețeaua complet și să o fragmentați mai târziu. Dezactivează unele funcții avansate.</translation>
</message>
@@ -1747,14 +1764,17 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Confirmă resetarea opţiunilor</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Este necesară repornirea clientului pentru a activa schimbările.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Clientul va fi închis. Doriţi să continuaţi?</translation>
</message>
<message>
@@ -2575,10 +2595,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">O taxă mai mare de %1 este considerată o taxă absurd de mare</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Cerere de plată expirata</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2655,14 +2671,6 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<translation type="unfinished">Mesaj:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Aceasta este o cerere de plata neautentificata.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Aceasta este o cerere de plata autentificata.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Introduceţi eticheta pentru ca această adresa să fie introdusă în lista de adrese folosite</translation>
</message>
@@ -2670,11 +2678,7 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<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 type="unfinished">un mesaj a fost ataşat la bitcoin: URI care va fi stocat cu tranzacţia pentru referinţa dvs. Notă: Acest mesaj nu va fi trimis către reţeaua bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Plăteşte către:</translation>
- </message>
- </context>
+</context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -2821,26 +2825,22 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">in conflict cu o tranzactie cu %1 confirmari</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/neconfirmat, %1</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">nu e in memory pool</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">abandonat</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/neconfirmat</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 confirmări</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts
index dd9bfec0dd..04ade7accc 100644
--- a/src/qt/locale/bitcoin_ru.ts
+++ b/src/qt/locale/bitcoin_ru.ts
@@ -6,12 +6,16 @@
<translation type="unfinished">Ðажмите правой кнопкой мыши, чтобы изменить Ð°Ð´Ñ€ÐµÑ Ð¸Ð»Ð¸ метку</translation>
</message>
<message>
+ <source>Create a new address</source>
+ <translation type="unfinished">Создать новый адреÑ</translation>
+ </message>
+ <message>
<source>&amp;New</source>
<translation type="unfinished">&amp;Ðовый</translation>
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation type="unfinished">Скопировать выбранный Ð°Ð´Ñ€ÐµÑ Ð² буфер обмена</translation>
+ <translation type="unfinished">Скопировать выбранные адреÑа в буфер обмена</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -23,7 +27,7 @@
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation type="unfinished">Удалить текущий выбранный Ð°Ð´Ñ€ÐµÑ Ð¸Ð· ÑпиÑка</translation>
+ <translation type="unfinished">Удалить выбранные адреÑа из ÑпиÑка</translation>
</message>
<message>
<source>Enter address or label to search</source>
@@ -35,15 +39,19 @@
</message>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">&amp;ЭкÑпорт</translation>
+ <translation type="unfinished">&amp;ЭкÑпортировать</translation>
</message>
<message>
<source>&amp;Delete</source>
<translation type="unfinished">&amp;Удалить</translation>
</message>
<message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">Выберите адреÑа, Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸ на них монет</translation>
+ </message>
+ <message>
<source>Choose the address to receive coins with</source>
- <translation type="unfinished">Выберите Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð½ÐµÑ‚</translation>
+ <translation type="unfinished">Выберите адреÑа Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð½ÐµÑ‚</translation>
</message>
<message>
<source>C&amp;hoose</source>
@@ -58,10 +66,14 @@
<translation type="unfinished">ÐдреÑа получениÑ</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 type="unfinished">Это ваши биткоин-адреÑа Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸ платежей. Ð’Ñегда проверÑйте Ñумму и Ð°Ð´Ñ€ÐµÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð°Ñ‚ÐµÐ»Ñ Ð¿ÐµÑ€ÐµÐ´ отправкой перевода.</translation>
+ </message>
+ <message>
<source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
Signing is only possible with addresses of the type 'legacy'.</source>
- <translation type="unfinished">Это ваши биткойн-адреÑа Ð´Ð»Ñ Ð¿Ñ€Ð¸ÐµÐ¼Ð° платежей. ИÑпользуйте кнопку 'Создать новый Ð°Ð´Ñ€ÐµÑ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ' на вкладке получениÑ, чтобы Ñоздать новые адреÑа.
-ПодпиÑÑŒ возможна только Ñ Ð°Ð´Ñ€ÐµÑами типа 'уÑтаревший'.</translation>
+ <translation type="unfinished">Это ваши биткоин-адреÑа Ð´Ð»Ñ Ð¿Ñ€Ð¸ÐµÐ¼Ð° платежей. ИÑпользуйте кнопку "Создать новый Ð°Ð´Ñ€ÐµÑ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ" на вкладке получениÑ, чтобы Ñоздать новые адреÑа.
+ПодпиÑÑŒ возможна только Ñ Ð°Ð´Ñ€ÐµÑами типа "уÑтаревший".</translation>
</message>
<message>
<source>&amp;Copy Address</source>
@@ -91,7 +103,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished">Ошибка ÑкÑпорта</translation>
+ <translation type="unfinished">Ошибка при ÑкÑпорте</translation>
</message>
</context>
<context>
@@ -137,7 +149,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation type="unfinished">Ð”Ð°Ð½Ð½Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ñ‚Ñ€ÐµÐ±ÑƒÐµÑ‚ Ð²Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð´Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ вашего кошелька.</translation>
+ <translation type="unfinished">Ð”Ð°Ð½Ð½Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ñ‚Ñ€ÐµÐ±ÑƒÐµÑ‚ Ð²Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»ÑŒÐ½Ð¾Ð¹ фразы Ð´Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ вашего кошелька.</translation>
</message>
<message>
<source>Unlock wallet</source>
@@ -169,11 +181,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Enter the old passphrase and new passphrase for the wallet.</source>
- <translation type="unfinished">Введите Ñтарый и новый пароли Ð´Ð»Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ°</translation>
+ <translation type="unfinished">Введите Ñтарую и новую парольные фразы Ð´Ð»Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ°</translation>
</message>
<message>
<source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
- <translation type="unfinished">Помните, что шифрование кошелька не может полноÑтью защитить ваши биткойны от кражи вредоноÑными программами, заразившими ваш компьютер.</translation>
+ <translation type="unfinished">Помните, что шифрование кошелька не может полноÑтью защитить ваши биткоины от кражи вредоноÑными программами, заразившими ваш компьютер.</translation>
</message>
<message>
<source>Wallet to be encrypted</source>
@@ -185,11 +197,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Your wallet is now encrypted. </source>
- <translation type="unfinished">Ваш кошелёк теперь зашифрован.</translation>
+ <translation type="unfinished">Ð¡ÐµÐ¹Ñ‡Ð°Ñ Ð²Ð°Ñˆ кошелёк зашифрован.</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 type="unfinished">Ð’ÐЖÐО: Ð’Ñе предыдущие резервные копии вашего кошелька, которые вы Ñделали, необходимо заменить недавно Ñгенерированным, зашифрованным файлом кошелька. Из Ñоображений безопаÑноÑти, предыдущие резервные копии незашифрованного файла кошелька Ñтанут беÑполезными как только вы начнёте иÑпользовать новый, зашифрованный кошелёк.</translation>
+ <translation type="unfinished">Ð’ÐЖÐО: Ð’Ñе ранее Ñозданные резервные копии вашего кошелька, необходимо заменить только что Ñгенерированным зашифрованным файлом кошелька. Как только вы начнёте иÑпользовать новый, зашифрованный кошелёк, из Ñоображений безопаÑноÑти, предыдущие резервные копии незашифрованного файла кошелька Ñтанут беÑполезными.</translation>
</message>
<message>
<source>Wallet encryption failed</source>
@@ -224,7 +236,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>BanTableModel</name>
<message>
<source>IP/Netmask</source>
- <translation type="unfinished">IP/маÑка подÑети</translation>
+ <translation type="unfinished">IP/МаÑка подÑети</translation>
</message>
<message>
<source>Banned Until</source>
@@ -234,12 +246,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Файл наÑтроек %1 повреждён или имеет неверный формат.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
- <translation type="unfinished">ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°</translation>
+ <translation type="unfinished">ÐеуправлÑемое иÑключение</translation>
</message>
<message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <translation type="unfinished">Произошла Ñ„Ð°Ñ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°. %1 больше не может безопаÑно продолжить и будет закрыт.</translation>
+ <translation type="unfinished">Произошла критичеÑÐºÐ°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°. %1 больше не может продолжать безопаÑную работу и будет закрыт.
+ </translation>
</message>
<message>
<source>Internal error</source>
@@ -247,12 +264,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
- <translation type="unfinished">Возникла внутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°. %1 попытаетÑÑ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶Ð¸Ñ‚ÑŒ работу безопаÑно. Это Ð½ÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°, о которой можно Ñообщить, как опиÑано ниже.</translation>
+ <translation type="unfinished">Произошла внутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°. %1 попытаетÑÑ Ð±ÐµÐ·Ð¾Ð¿Ð°Ñно продолжить работу. Ð’Ñ‹ можете Ñообщить об Ñтой ошибке по инÑтрукции ниже.</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">CброÑить наÑтройки до значений по умолчанию или завершить программу без внеÑÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Произошла Ñ„Ð°Ñ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°. Проверьте, доÑтупна ли запиÑÑŒ в файл наÑтроек, или повторите запуÑк Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Ошибка: указанный каталог данных "%1" не ÑущеÑтвует.</translation>
</message>
@@ -266,7 +293,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>%1 didn't yet exit safely…</source>
- <translation type="unfinished">%1 ещё не закрылÑÑ Ð±ÐµÐ·Ð¾Ð¿Ð°Ñно...</translation>
+ <translation type="unfinished">%1 ещё не закрылÑÑ Ð±ÐµÐ·Ð¾Ð¿Ð°Ñно…</translation>
</message>
<message>
<source>unknown</source>
@@ -278,7 +305,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Enter a Bitcoin address (e.g. %1)</source>
- <translation type="unfinished">Введите биткоин-Ð°Ð´Ñ€ÐµÑ (напр. %1)</translation>
+ <translation type="unfinished">Введите биткоин-Ð°Ð´Ñ€ÐµÑ (например,%1)</translation>
</message>
<message>
<source>Unroutable</source>
@@ -354,41 +381,41 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n Ñекунда</numerusform>
+ <numerusform>%n Ñекунды</numerusform>
+ <numerusform>%n Ñекунд</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n минута</numerusform>
+ <numerusform>%n минуты</numerusform>
+ <numerusform>%n минут</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n чаÑ</numerusform>
+ <numerusform>%n чаÑа</numerusform>
+ <numerusform>%n чаÑов</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n день</numerusform>
+ <numerusform>%n днÑ</numerusform>
+ <numerusform>%n дней</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n неделÑ</numerusform>
+ <numerusform>%n недели</numerusform>
+ <numerusform>%n недель</numerusform>
</translation>
</message>
<message>
@@ -398,9 +425,9 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n год</numerusform>
+ <numerusform>%n года</numerusform>
+ <numerusform>%n лет</numerusform>
</translation>
</message>
<message>
@@ -423,12 +450,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Файл наÑтроек не может быть прочитан</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Файл наÑтроек не может быть запиÑан</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">Разработчики %s</translation>
</message>
<message>
<source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
- <translation type="unfinished">%s иÑпорчен. Попробуйте воÑÑтановить Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ инÑтрумента bitcoin-wallet или воÑÑтановите из резервной копии.</translation>
+ <translation type="unfinished">%s иÑпорчен. Попробуйте воÑÑтановить его Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ инÑтрумента bitcoin-wallet или из резервной копии.</translation>
</message>
<message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
@@ -444,17 +479,21 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
- <translation type="unfinished">Ðевозможно обновить разделённый кошелёк без HD Ñ Ð²ÐµÑ€Ñии %i до верÑии %i, не обновившиÑÑŒ Ð´Ð»Ñ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ¸ предварительно разделённого пула ключей. ПожалуйÑта, иÑпользуйте верÑию %iили повторите без ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð²ÐµÑ€Ñии.</translation>
+ <translation type="unfinished">Ðевозможно обновить разделённый кошелёк без HD Ñ Ð²ÐµÑ€Ñии %i до верÑии %i, не обновившиÑÑŒ Ð´Ð»Ñ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ¸ предварительно разделённого пула ключей. ПожалуйÑта, иÑпользуйте верÑию %i или повторите без ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð²ÐµÑ€Ñии.</translation>
</message>
<message>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
- <translation type="unfinished">РаÑпроÑтранÑетÑÑ Ð¿Ð¾Ð´ лицензией MIT, Ñм. приложенный файл %s или %s</translation>
+ <translation type="unfinished">РаÑпроÑтранÑетÑÑ Ð¿Ð¾ лицензии MIT. Её текÑÑ‚ находитÑÑ Ð² файле %s и по адреÑу %s</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 type="unfinished">Ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ %s! Ð’Ñе ключи прочитаны верно, но данные транзакций или запиÑи адреÑной книги могут отÑутÑтвовать или быть неправильными.</translation>
</message>
<message>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">Ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ %s! Данные транзакций отÑутÑтвуют или неправильны. Кошелёк ÑканируетÑÑ Ð·Ð°Ð½Ð¾Ð²Ð¾.</translation>
+ </message>
+ <message>
<source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
<translation type="unfinished">Ошибка: запиÑÑŒ формата дамп-файла неверна. Обнаружено "%s", ожидалоÑÑŒ "format".</translation>
</message>
@@ -464,11 +503,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
- <translation type="unfinished">Ошибка: верÑÐ¸Ñ Ð´Ð°Ð¼Ð¿-файла не поддерживаетÑÑ. Эта верÑÐ¸Ñ bitcoin-wallet поддерживает только дамп-файлы верÑии 1. Обнаружено дамп-файл верÑии %s</translation>
+ <translation type="unfinished">Ошибка: верÑÐ¸Ñ Ð´Ð°Ð¼Ð¿-файла не поддерживаетÑÑ. Эта верÑÐ¸Ñ Ð±Ð¸Ñ‚ÐºÐ¾Ð¸Ð½-кошелька поддерживает только дамп-файлы верÑии 1. Обнаружен дамп-файл верÑии %s</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Ошибка: Ðе удалоÑÑŒ начать проÑлушивание входÑщих подключений (проÑлушивание вернуло ошибку %s)</translation>
+ <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
+ <translation type="unfinished">Ошибка: уÑтаревшие кошельки поддерживают только Ñледующие типы адреÑов: "legacy", "p2sh-segwit", и "bech32".</translation>
</message>
<message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
@@ -480,7 +519,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">Ðеверное значение Ð´Ð»Ñ -maxtxfee=&lt;amount&gt;: '%s' (должна быть не ниже минимально ретранÑлируемой комиÑÑии %s Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð·Ð°Ð²Ð¸ÑÐ°Ð½Ð¸Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¹)</translation>
+ <translation type="unfinished">Ðеверное значение Ð´Ð»Ñ -maxtxfee=&lt;amount&gt;: "%s" (должно быть не ниже минимально ретранÑлируемой комиÑÑии %s Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð·Ð°Ð²Ð¸ÑÐ°Ð½Ð¸Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¹)</translation>
+ </message>
+ <message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">Ðеверный или поврежденный peers.dat (%s). ЕÑли вы Ñчитаете что Ñто ошибка, Ñообщите о ней %s. Ð’ качеÑтве временной меры вы можете перемеÑтить, переименовать или удалить файл (%s). Ðовый файл будет Ñоздан при Ñледующем запуÑке программы.</translation>
</message>
<message>
<source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
@@ -500,7 +543,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">ПожалуйÑта, убедитеÑÑŒ, что на вашем компьютере верно уÑтановлены дата и времÑ. ЕÑли ваши чаÑÑ‹ неверны, %s не будет работать правильно.</translation>
+ <translation type="unfinished">ПожалуйÑта, убедитеÑÑŒ, что на вашем компьютере верно уÑтановлены дата и времÑ. ЕÑли ваши чаÑÑ‹ ÑбилиÑÑŒ, %s будет работать неправильно.</translation>
</message>
<message>
<source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
@@ -511,32 +554,40 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Обрезка блоков выÑтавлена меньше, чем минимум в %d МиБ. ПожалуйÑта, иÑпользуйте большее значение.</translation>
</message>
<message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">Режим обрезки неÑовмеÑтим Ñ -reindex-chainstate. ИÑпользуйте вмеÑто Ñтого полный -reindex.</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 type="unfinished">Обрезка: поÑледнÑÑ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ° вышла за рамки обрезанных данных. Ðеобходимо Ñделать -reindex (Ñнова Ñкачать вÑÑŽ цепочку блоков, еÑли у Ð²Ð°Ñ ÑƒÐ·ÐµÐ» Ñ Ð¾Ð±Ñ€ÐµÐ·ÐºÐ¾Ð¹)</translation>
</message>
<message>
<source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
- <translation type="unfinished">SQLiteDatabase: ÐеизвеÑÑ‚Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ñхемы sqlite кошелька: %d. ПоддерживаетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ верÑÐ¸Ñ %d</translation>
+ <translation type="unfinished">SQLiteDatabase: неизвеÑÑ‚Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ñхемы SQLite кошелька: %d. ПоддерживаетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ верÑÐ¸Ñ %d</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 type="unfinished">Ð’ базе данных блоков найден блок из будущего. Это может произойти из-за неверно уÑтановленных даты и времени на вашем компьютере. ПереÑтраивайте базу данных блоков только еÑли вы уверены, что дата и Ð²Ñ€ÐµÐ¼Ñ ÑƒÑтановлены верно.</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">База данных индекÑации блоков Ñодержит уÑтаревший "txindex". Чтобы оÑвободить меÑто на диÑке, выполните полный -reindex, или игнорируйте Ñту ошибку. Это Ñообщение об ошибке больше показано не будет.</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
- <translation type="unfinished">Сумма транзакции за вычетом комиÑÑии Ñлишком мала</translation>
+ <translation type="unfinished">Сумма транзакции за вычетом комиÑÑии Ñлишком мала Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸</translation>
</message>
<message>
<source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source>
- <translation type="unfinished">Ð”Ð°Ð½Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° может произойти в том Ñлучае, еÑли Ñтот кошелёк не был правильно закрыт и в поÑледний раз был загружен иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð²ÐµÑ€Ñию Ñ Ð±Ð¾Ð»ÐµÐµ новой верÑией Berkley DB. ЕÑли Ñто так, воÑпользуйтеÑÑŒ той программой, в которой Ñтот кошелёк открывалÑÑ Ð² поÑледний раз.</translation>
+ <translation type="unfinished">Это могло произойти, еÑли кошелёк был некорректно закрыт, а затем загружен Ñборкой Ñ Ð±Ð¾Ð»ÐµÐµ новой верÑией Berkley DB. ЕÑли Ñто так, воÑпользуйтеÑÑŒ Ñборкой, в которой Ñтот кошелёк открывалÑÑ Ð² поÑледний раз</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 type="unfinished">Это теÑÑ‚Ð¾Ð²Ð°Ñ Ñборка - иÑпользуйте на Ñвой Ñтрах и риÑк - не иÑпользуйте Ð´Ð»Ñ Ð´Ð¾Ð±Ñ‹Ñ‡Ð¸ или торговых приложений</translation>
+ <translation type="unfinished">Это теÑÑ‚Ð¾Ð²Ð°Ñ Ñборка. ИÑпользуйте её на Ñвой Ñтрах и риÑк. Ðе иÑпользуйте её Ð´Ð»Ñ Ð´Ð¾Ð±Ñ‹Ñ‡Ð¸ или в торговых приложениÑÑ…</translation>
</message>
<message>
<source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
- <translation type="unfinished">Это макÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ, которую вы заплатите (в добавок к обычной плате), чтобы отдать приоритет избежанию чаÑтичной траты перед обычным управлением монетами.</translation>
+ <translation type="unfinished">Это макÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð¼Ð¸ÑÑÐ¸Ñ Ð·Ð° транзакцию, которую вы заплатите (в добавок к обычной комиÑÑии), чтобы отдать приоритет избежанию чаÑтичной траты перед обычным управлением монетами.</translation>
</message>
<message>
<source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
@@ -552,15 +603,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
- <translation type="unfinished">Ðевозможно воÑпроизвеÑти блоки. Вам необходимо переÑтроить базу данных, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ -reindex-chaintate.</translation>
+ <translation type="unfinished">Ðевозможно воÑпроизвеÑти блоки. Вам необходимо переÑтроить базу данных, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ -reindex-chainstate.</translation>
</message>
<message>
<source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source>
<translation type="unfinished">Указан неизвеÑтный формат файла кошелька "%s". Укажите "bdb" либо "sqlite".</translation>
</message>
<message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">Обнаружен неподдерживаемый формат базы данных ÑоÑтоÑÐ½Ð¸Ñ Ñ†ÐµÐ¿Ð¾Ñ‡ÐºÐ¸ блоков. ПожалуйÑта, перезапуÑтите программу Ñ ÐºÐ»ÑŽÑ‡Ð¾Ð¼ -reindex-chainstate. Это переÑтроит базу данных ÑоÑтоÑÐ½Ð¸Ñ Ñ†ÐµÐ¿Ð¾Ñ‡ÐºÐ¸ блоков.</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Кошелёк уÑпешно Ñоздан. Старый формат кошелька признан уÑтаревшим. Поддержка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ° в Ñтом формате и его открытие в будущем будут удалены.</translation>
+ </message>
+ <message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
- <translation type="unfinished">Внимание: формат кошелька дамп-файла "%s" не ÑоответÑтвует указанному в командной Ñтроке формату "%s".</translation>
+ <translation type="unfinished">Внимание: формат дамп-файла кошелька "%s" не ÑоответÑтвует указанному в командной Ñтроке формату "%s".</translation>
</message>
<message>
<source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
@@ -568,7 +627,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">Внимание: мы не полноÑтью ÑоглаÑны Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ узлами! Вам или другим учаÑтникам, возможно, Ñледует обновить клиент.</translation>
+ <translation type="unfinished">Внимание: мы не полноÑтью ÑоглаÑны Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ узлами! Вам или другим учаÑтникам, возможно, Ñледует обновитьÑÑ.</translation>
</message>
<message>
<source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
@@ -584,27 +643,127 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
- <translation type="unfinished">-maxmempool должен быть как минимум %d МБ</translation>
+ <translation type="unfinished">-maxmempool должен быть минимум %d МБ</translation>
</message>
<message>
<source>A fatal internal error occurred, see debug.log for details</source>
- <translation type="unfinished">Ошибка: произошла критичеÑÐºÐ°Ñ Ð²Ð½ÑƒÑ‚Ñ€ÐµÐ½Ð½ÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°, Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð´ÐµÑ‚Ð°Ð»ÐµÐ¹ Ñм. debug.log</translation>
+ <translation type="unfinished">Произошла критичеÑÐºÐ°Ñ Ð²Ð½ÑƒÑ‚Ñ€ÐµÐ½Ð½ÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°, подробноÑти в файле debug.log</translation>
</message>
<message>
<source>Cannot resolve -%s address: '%s'</source>
- <translation type="unfinished">Ðе удаетÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐ¸Ñ‚ÑŒ -%s адреÑ: '%s'</translation>
+ <translation type="unfinished">Ðе удаетÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐ¸Ñ‚ÑŒ -%s адреÑ: "%s"</translation>
+ </message>
+ <message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">ÐÐµÐ»ÑŒÐ·Ñ ÑƒÑтановить -forcednsseed в true, еÑли -dnsseed уÑтановлен в false.</translation>
</message>
<message>
<source>Cannot set -peerblockfilters without -blockfilterindex.</source>
- <translation type="unfinished">ÐÐµÐ»ÑŒÐ·Ñ ÑƒÐºÐ°Ð·Ñ‹Ð²Ð°Ñ‚ÑŒ -peerblockfilters без -blockfilterindex.</translation>
+ <translation type="unfinished">ÐÐµÐ»ÑŒÐ·Ñ ÑƒÐºÐ°Ð·Ñ‹Ð²Ð°Ñ‚ÑŒ -peerblockfilters без ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ -blockfilterindex.</translation>
</message>
<message>
<source>Cannot write to data directory '%s'; check permissions.</source>
- <translation type="unfinished">Ðе удаетÑÑ Ð²Ñ‹Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÑŒ запиÑÑŒ в каталог данных '%s'; проверьте разрешениÑ.</translation>
+ <translation type="unfinished">Ðе удаетÑÑ Ð²Ñ‹Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÑŒ запиÑÑŒ в каталог данных "%s"; проверьте разрешениÑ.</translation>
+ </message>
+ <message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">Обновление -txindex, запущенное при предыдущей верÑии не может быть завершено. ПерезапуÑтите Ñ Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰ÐµÐ¹ верÑией или запуÑтите веÑÑŒ процеÑÑ Ð·Ð°Ð½Ð¾Ð²Ð¾ Ñ ÐºÐ»ÑŽÑ‡Ð¾Ð¼ -reindex.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s попыталÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ на проÑлушивание порт %u. Этот порт ÑчитаетÑÑ "плохим". ВероÑтноÑÑ‚ÑŒ, что узлы Bitcoin Core к нему подключатÑÑ, крайне мала. ПодробноÑти и полный ÑпиÑок плохих портов в документации: doc/p2p-bad-ports.md. </translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">ÐžÐ¿Ñ†Ð¸Ñ -reindex-chainstate не ÑовмеÑтима Ñ -blockfilterindex. ПожалуйÑта, выключите на Ð²Ñ€ÐµÐ¼Ñ blockfilterindex, пока иÑпользуетÑÑ -reindex-chainstate, либо замените -reindex-chainstate на -reindex Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð¹ переÑтройки вÑех индекÑов.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">ÐžÐ¿Ñ†Ð¸Ñ -reindex-chainstate не ÑовмеÑтима Ñ -coinstatsindex. ПожалуйÑта, выключите на Ð²Ñ€ÐµÐ¼Ñ coinstatsindex, пока иÑпользуетÑÑ -reindex-chainstate, либо замените -reindex-chainstate на -reindex Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð¹ переÑтройки вÑех индекÑов.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">ÐžÐ¿Ñ†Ð¸Ñ -reindex-chainstate не ÑовмеÑтима Ñ -txindex. ПожалуйÑта, выключите на Ð²Ñ€ÐµÐ¼Ñ txindex, пока иÑпользуетÑÑ -reindex-chainstate, либо замените -reindex-chainstate на -reindex Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð¹ переÑтройки вÑех индекÑов.</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">Предположительно дейÑтвительный: поÑледнÑÑ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ° была Ñ Ð±Ð¾Ð»ÐµÐµ новым блоком данных, чем имеетÑÑ Ñƒ наÑ. Подождите, пока фоновый процеÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ цепочки блоков загрузит новые данные.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Ðе удаётÑÑ Ð¿Ñ€ÐµÐ´Ð¾Ñтавить определённые ÑоединениÑ, чтобы при Ñтом addrman нашёл в них иÑходÑщие ÑоединениÑ.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Ошибка загрузки %s: не удалоÑÑŒ загрузить кошелёк Ñ Ð²Ð½ÐµÑˆÐ½ÐµÐ¹ подпиÑью, так как Ñта верÑÐ¸Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹ Ñобрана без поддержки внешней подпиÑи</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Ошибка: адреÑÐ½Ð°Ñ ÐºÐ½Ð¸Ð³Ð° в кошельке не принадлежит к мигрируемым кошелькам</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">Ошибка: при миграции были Ñозданы дублирующиеÑÑ Ð´ÐµÑкрипторы. Возможно, ваш кошелёк повреждён.</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Ошибка: Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ %s не принадлежит к мигрируемым кошелькам</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">Ошибка: не удалоÑÑŒ Ñоздать деÑкрипторы Ð´Ð»Ñ Ñтого кошелька Ñтарого формата. Ð”Ð»Ñ Ð½Ð°Ñ‡Ð°Ð»Ð° убедитеÑÑŒ, что кошелёк разблокирован</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Ðе удалоÑÑŒ переименовать файл peers.dat. ПожалуйÑта, перемеÑтите или удалите его и попробуйте Ñнова.</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">ÐеÑовмеÑтимые ключи: был Ñвно указан -dnsseed=1, но -onlynet не разрешены ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ‡ÐµÑ€ÐµÐ· IPv4/IPv6</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">ИÑходÑщие ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ñ‹ только через Ñеть Tor (-onlynet=onion), однако прокÑи Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñети Tor Ñвно запрещен: -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">ИÑходÑщие ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ñ‹ только через Ñеть Tor (-onlynet=onion), однако прокÑи Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñети Tor не указан: не заданы ни -proxy, ни -onion, ни -listenonion</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">При загрузке кошелька %s найден нераÑпознаваемый деÑкриптор
+
+Кошелёк мог быть Ñоздан на более новой верÑии программы.
+ПожалуйÑта, попробуйте обновить программу до поÑледней верÑии.
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">Ðеподдерживаемый уровень подробноÑти журнала Ð´Ð»Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ð¸ -loglevel=%s. ОжидалоÑÑŒ -loglevel=&lt;category&gt;:&lt;loglevel&gt;. ДоÑтупные категории: %s. ДоÑтупные уровни подробноÑти журнала: %s.</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+Ðе удалоÑÑŒ очиÑтить Ñледы поÑле неуÑпешной миграции</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Ðе удалоÑÑŒ воÑÑтановить кошелёк из резервной копии.</translation>
</message>
<message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
- <translation type="unfinished">ÐаÑтройка конфигурации %s применÑетÑÑ Ð² Ñети %s только еÑли находитÑÑ Ð² разделе [%s].</translation>
+ <translation type="unfinished">ÐаÑтройка конфигурации %s применÑетÑÑ Ð´Ð»Ñ Ñети %s только еÑли находитÑÑ Ð² разделе [%s].</translation>
+ </message>
+ <message>
+ <source>Copyright (C) %i-%i</source>
+ <translation type="unfinished">ÐвторÑкое право (C) %i-%i</translation>
</message>
<message>
<source>Corrupted block database detected</source>
@@ -616,11 +775,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Could not parse asmap file %s</source>
- <translation type="unfinished">Ðе могу разобрать файл asmap %s</translation>
+ <translation type="unfinished">Ðе удалоÑÑŒ разобрать файл asmap %s</translation>
</message>
<message>
<source>Disk space is too low!</source>
- <translation type="unfinished">Мало меÑта на диÑке!</translation>
+ <translation type="unfinished">МеÑто на диÑке заканчиваетÑÑ!</translation>
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
@@ -632,23 +791,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Dump file %s does not exist.</source>
- <translation type="unfinished">Дамп файл %s не ÑущеÑтвует.</translation>
+ <translation type="unfinished">Дамп-файл %s не ÑущеÑтвует.</translation>
</message>
<message>
<source>Error creating %s</source>
- <translation type="unfinished">Ошибка загрузки %s</translation>
+ <translation type="unfinished">Ошибка при Ñоздании %s</translation>
</message>
<message>
<source>Error initializing block database</source>
- <translation type="unfinished">Ошибка инициализации базы данных блоков</translation>
+ <translation type="unfinished">Ошибка при инициализации базы данных блоков</translation>
</message>
<message>
<source>Error initializing wallet database environment %s!</source>
- <translation type="unfinished">Ошибка инициализации Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных кошелька %s!</translation>
+ <translation type="unfinished">Ошибка при инициализации Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных кошелька %s!</translation>
</message>
<message>
<source>Error loading %s</source>
- <translation type="unfinished">Ошибка загрузки %s</translation>
+ <translation type="unfinished">Ошибка при загрузке %s</translation>
</message>
<message>
<source>Error loading %s: Private keys can only be disabled during creation</source>
@@ -679,8 +838,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñледующей запиÑи из базы данных кошелька</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Ошибка Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных chainstate</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">Ошибка: не удалоÑÑŒ добавить транзакцию Ð´Ð»Ñ Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ Ð² кошелек Ð´Ð»Ñ Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">Ошибка: транзакции только Ð´Ð»Ñ Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ Ð½Ðµ удалÑÑŽÑ‚ÑÑ</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
@@ -692,11 +855,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
- <translation type="unfinished">Ошибка: ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñумма дамп-файла не Ñовпадает. ВычиÑлено %s, ожидалоÑÑŒ %s.</translation>
+ <translation type="unfinished">Ошибка: контрольные Ñуммы дамп-файла не Ñовпадают. ВычиÑлено %s, ожидалоÑÑŒ %s.</translation>
+ </message>
+ <message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">Ошибка: не удалоÑÑŒ Ñоздать кошелёк только на проÑмотр</translation>
</message>
<message>
<source>Error: Got key that was not hex: %s</source>
- <translation type="unfinished">Ошибка: получен ключ, оказавшийÑÑ Ð½Ðµ шеÑтнадцатеричным: %s</translation>
+ <translation type="unfinished">Ошибка: получен ключ, не ÑвлÑющийÑÑ ÑˆÐµÑтнадцатеричным: %s</translation>
</message>
<message>
<source>Error: Got value that was not hex: %s</source>
@@ -704,23 +871,55 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Error: Keypool ran out, please call keypoolrefill first</source>
- <translation type="unfinished">Ошибка: пул ключей опуÑтел, пожалуйÑта Ñначала выполните keypoolrefill</translation>
+ <translation type="unfinished">Ошибка: пул ключей опуÑтел. ПожалуйÑта, выполните keypoolrefill</translation>
</message>
<message>
<source>Error: Missing checksum</source>
<translation type="unfinished">Ошибка: отÑутÑтвует ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñумма</translation>
</message>
<message>
+ <source>Error: No %s addresses available.</source>
+ <translation type="unfinished">Ошибка: нет %s доÑтупных адреÑов.</translation>
+ </message>
+ <message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">Ошибка: не вÑе наблюдаемые транзакции могут быть удалены</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">Ошибка: Ñтот кошелёк уже иÑпользует SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">Ошибка: Ñтот кошелёк уже ÑвлÑетÑÑ Ð´ÐµÑкрипторным</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">Ошибка: не удалоÑÑŒ начать читать вÑе запиÑи из базе данных</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">Ошибка: не удалоÑÑŒ Ñоздать резервную копию кошелька</translation>
+ </message>
+ <message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">Ошибка: невозможно разобрать верÑию %u как uint32_t</translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">Ошибка: не удалоÑÑŒ прочитать вÑе запиÑи из базе данных</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">Ошибка: не удалоÑÑŒ удалить данные из адреÑной книги только Ð´Ð»Ñ Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
<translation type="unfinished">Ошибка: невозможно произвеÑти запиÑÑŒ в новый кошелек</translation>
</message>
<message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
- <translation type="unfinished">Ðе удалоÑÑŒ начать проÑлушивание на порту. ИÑпользуйте -listen=0, еÑли Ð²Ð°Ñ Ñто уÑтраивает.</translation>
+ <translation type="unfinished">Ðе удалоÑÑŒ открыть никакой порт на проÑлушивание. ИÑпользуйте -listen=0, еÑли Ð²Ð°Ñ Ñто уÑтроит.</translation>
</message>
<message>
<source>Failed to rescan the wallet during initialization</source>
@@ -740,7 +939,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Importing…</source>
- <translation type="unfinished">Импорт...</translation>
+ <translation type="unfinished">Импорт…</translation>
</message>
<message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
@@ -751,68 +950,84 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ÐÐ°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° иÑправноÑти не удалаÑÑŒ. %s завершает работу.</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Вход Ð´Ð»Ñ Ñ‚Ñ€Ð°Ð·Ð°ÐºÑ†Ð¸Ð¸ не найден или уже иÑпользован</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">ÐедоÑтаточно ÑредÑтв</translation>
</message>
<message>
<source>Invalid -i2psam address or hostname: '%s'</source>
- <translation type="unfinished">Ðеверный Ð°Ð´Ñ€ÐµÑ Ð¸Ð»Ð¸ Ð¸Ð¼Ñ Ñ…Ð¾Ñта в -i2psam: '%s'</translation>
+ <translation type="unfinished">Ðеверный Ð°Ð´Ñ€ÐµÑ Ð¸Ð»Ð¸ Ð¸Ð¼Ñ Ñ…Ð¾Ñта в -i2psam: "%s"</translation>
</message>
<message>
<source>Invalid -onion address or hostname: '%s'</source>
- <translation type="unfinished">Ðеверный -onion Ð°Ð´Ñ€ÐµÑ Ð¸Ð»Ð¸ Ð¸Ð¼Ñ Ñ…Ð¾Ñта: '%s'</translation>
+ <translation type="unfinished">Ðеверный -onion Ð°Ð´Ñ€ÐµÑ Ð¸Ð»Ð¸ Ð¸Ð¼Ñ Ñ…Ð¾Ñта: "%s"</translation>
</message>
<message>
<source>Invalid -proxy address or hostname: '%s'</source>
- <translation type="unfinished">Ðеверный Ð°Ð´Ñ€ÐµÑ -proxy или Ð¸Ð¼Ñ Ñ…Ð¾Ñта: '%s'</translation>
+ <translation type="unfinished">Ðеверный Ð°Ð´Ñ€ÐµÑ -proxy или Ð¸Ð¼Ñ Ñ…Ð¾Ñта: "%s"</translation>
</message>
<message>
<source>Invalid P2P permission: '%s'</source>
- <translation type="unfinished">Ðеверные разрешение Ð´Ð»Ñ P2P: '%s'</translation>
+ <translation type="unfinished">Ðеверные Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð´Ð»Ñ P2P: "%s"</translation>
</message>
<message>
<source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñумма Ð´Ð»Ñ -%s=&lt;amount&gt;: '%s'</translation>
+ <translation type="unfinished">ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñумма Ð´Ð»Ñ -%s=&lt;amount&gt;: "%s"</translation>
</message>
<message>
<source>Invalid amount for -discardfee=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñумма Ð´Ð»Ñ -discardfee=&lt;amount&gt;: '%s'</translation>
+ <translation type="unfinished">ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñумма Ð´Ð»Ñ -discardfee=&lt;amount&gt;: "%s"</translation>
</message>
<message>
<source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñумма Ð´Ð»Ñ -fallbackfee=&lt;amount&gt;: '%s'</translation>
+ <translation type="unfinished">ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñумма Ð´Ð»Ñ -fallbackfee=&lt;amount&gt;: "%s"</translation>
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
- <translation type="unfinished">ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñумма Ð´Ð»Ñ -paytxfee=&lt;amount&gt;: '%s' (должно быть как минимум %s)</translation>
+ <translation type="unfinished">ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñумма Ð´Ð»Ñ -paytxfee=&lt;amount&gt;: "%s" (должно быть как минимум %s)</translation>
</message>
<message>
<source>Invalid netmask specified in -whitelist: '%s'</source>
- <translation type="unfinished">Указана Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÑÐµÑ‚ÐµÐ²Ð°Ñ Ð¼Ð°Ñка в -whitelist: '%s'</translation>
+ <translation type="unfinished">Указана Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÑÐµÑ‚ÐµÐ²Ð°Ñ Ð¼Ð°Ñка в -whitelist: "%s"</translation>
+ </message>
+ <message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">Ошибка при проÑлушивании входÑщих подключений (%s)</translation>
</message>
<message>
<source>Loading P2P addresses…</source>
- <translation type="unfinished">Загрузка P2P адреÑов...</translation>
+ <translation type="unfinished">Загрузка P2P адреÑов…</translation>
</message>
<message>
<source>Loading banlist…</source>
- <translation type="unfinished">Загрузка черного ÑпиÑка...</translation>
+ <translation type="unfinished">Загрузка черного ÑпиÑка…</translation>
</message>
<message>
<source>Loading block index…</source>
- <translation type="unfinished">Загрузка индекÑа блоков...</translation>
+ <translation type="unfinished">Загрузка индекÑа блоков…</translation>
</message>
<message>
<source>Loading wallet…</source>
- <translation type="unfinished">Загрузка кошелька...</translation>
+ <translation type="unfinished">Загрузка кошелька…</translation>
+ </message>
+ <message>
+ <source>Missing amount</source>
+ <translation type="unfinished">ОтÑутÑтвует Ñумма</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">ÐедоÑтаточно данных Ð´Ð»Ñ Ð¾Ñ†ÐµÐ½ÐºÐ¸ размера транзакции</translation>
</message>
<message>
<source>Need to specify a port with -whitebind: '%s'</source>
- <translation type="unfinished">Ðеобходимо указать порт Ñ -whitebind: '%s'</translation>
+ <translation type="unfinished">Ðеобходимо указать порт Ñ -whitebind: "%s"</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Ðе указан прокÑи-Ñервер. ИÑпользуйте -proxy=&lt;ip&gt; или -proxy=&lt;ip:port&gt;</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Ðет доÑтупных адреÑов</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -823,48 +1038,44 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Обрезка блоков не может иÑпользовать отрицательное значение.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Режим ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¾Ð² неÑовмеÑтим Ñ -coinstatsindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">Режим обрезки неÑовмеÑтим Ñ -txindex.</translation>
</message>
<message>
<source>Pruning blockstore…</source>
- <translation type="unfinished">Сокращение объема хранилища блоков...</translation>
+ <translation type="unfinished">Сокращение хранилища блоков…</translation>
</message>
<message>
<source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
- <translation type="unfinished">Уменьшите -maxconnections Ñ %d до %d из-за ограничений ÑиÑтемы.</translation>
+ <translation type="unfinished">Уменьшение -maxconnections Ñ %d до %d из-за ограничений ÑиÑтемы.</translation>
</message>
<message>
<source>Replaying blocks…</source>
- <translation type="unfinished">ПереÑборка блоков...</translation>
+ <translation type="unfinished">ПереÑборка блоков…</translation>
</message>
<message>
<source>Rescanning…</source>
- <translation type="unfinished">ПереÑканирование...</translation>
+ <translation type="unfinished">Повторное Ñканирование…</translation>
</message>
<message>
<source>SQLiteDatabase: Failed to execute statement to verify database: %s</source>
- <translation type="unfinished">SQLiteDatabase: Ðе удалоÑÑŒ выполнить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ базы данных: %s</translation>
+ <translation type="unfinished">SQLiteDatabase: не удалоÑÑŒ выполнить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ базы данных: %s</translation>
</message>
<message>
<source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source>
- <translation type="unfinished">SQLiteDatabase: Ðе удалоÑÑŒ подготовить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ базы данных: %s</translation>
+ <translation type="unfinished">SQLiteDatabase: не удалоÑÑŒ подготовить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ базы данных: %s</translation>
</message>
<message>
<source>SQLiteDatabase: Failed to read database verification error: %s</source>
- <translation type="unfinished">SQLiteDatabase: Ошибка при проверке базы данных: %s</translation>
+ <translation type="unfinished">SQLiteDatabase: ошибка при проверке базы данных: %s</translation>
</message>
<message>
<source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source>
- <translation type="unfinished">SQLiteDatabase: Ðеожиданный id приложениÑ. ОжидалоÑÑŒ %u, но получено %u</translation>
+ <translation type="unfinished">SQLiteDatabase: неожиданный id приложениÑ. ОжидалоÑÑŒ %u, но получено %u</translation>
</message>
<message>
<source>Section [%s] is not recognized.</source>
- <translation type="unfinished">Раздел [%s] не раÑпознан.</translation>
+ <translation type="unfinished">Ð¡ÐµÐºÑ†Ð¸Ñ [%s] не раÑпознана.</translation>
</message>
<message>
<source>Signing transaction failed</source>
@@ -880,19 +1091,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Specified -walletdir "%s" is not a directory</source>
- <translation type="unfinished">Указанный -walletdir "%s" не ÑвлÑетÑÑ Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸ÐµÐ¹</translation>
+ <translation type="unfinished">Указанный -walletdir "%s" не ÑвлÑетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¾Ð¼</translation>
</message>
<message>
<source>Specified blocks directory "%s" does not exist.</source>
- <translation type="unfinished">Ð£ÐºÐ°Ð·Ð°Ð½Ð½Ð°Ñ Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð´Ð»Ñ Ð±Ð»Ð¾ÐºÐ¾Ð² "%s" не ÑущеÑтвует.</translation>
+ <translation type="unfinished">Указанный каталог блоков "%s" не ÑущеÑтвует.</translation>
</message>
<message>
<source>Starting network threads…</source>
- <translation type="unfinished">ЗапуÑк Ñетевых потоков...</translation>
+ <translation type="unfinished">ЗапуÑк Ñетевых потоков…</translation>
</message>
<message>
<source>The source code is available from %s.</source>
- <translation type="unfinished">ИÑходный код доÑтупен в %s.</translation>
+ <translation type="unfinished">ИÑходный код доÑтупен по адреÑу %s.</translation>
</message>
<message>
<source>The specified config file %s does not exist</source>
@@ -904,11 +1115,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The wallet will avoid paying less than the minimum relay fee.</source>
- <translation type="unfinished">Кошелёк будет ÑтаратьÑÑ Ð½Ðµ платить меньше, чем Ð¼Ð¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð¼Ð¸ÑÑии ретранÑлÑции.</translation>
+ <translation type="unfinished">Кошелёк будет ÑтаратьÑÑ Ð¿Ð»Ð°Ñ‚Ð¸Ñ‚ÑŒ не меньше минимальной комиÑÑии Ð´Ð»Ñ Ñ€ÐµÑ‚Ñ€Ð°Ð½ÑлÑции.</translation>
</message>
<message>
<source>This is experimental software.</source>
- <translation type="unfinished">Это ÑкÑÐ¿ÐµÑ€Ð¸Ð¼ÐµÐ½Ñ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð°.</translation>
+ <translation type="unfinished">Это ÑкÑпериментальное программное обеÑпечение.</translation>
</message>
<message>
<source>This is the minimum transaction fee you pay on every transaction.</source>
@@ -927,28 +1138,44 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Сумма транзакции не должна быть отрицательной</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">Ð˜Ð½Ð´ÐµÐºÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð°Ñ‚ÐµÐ»Ñ Ð°Ð´Ñ€ÐµÑа Ñдачи вне диапазона</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
- <translation type="unfinished">Ð’ транзакции Ñлишком Ð´Ð»Ð¸Ð½Ð½Ð°Ñ Ñ†ÐµÐ¿Ð¾Ñ‡ÐºÐ° пула памÑти</translation>
+ <translation type="unfinished">У транзакции Ñлишком Ð´Ð»Ð¸Ð½Ð½Ð°Ñ Ñ†ÐµÐ¿Ð¾Ñ‡ÐºÐ° в пуле в памÑти</translation>
</message>
<message>
<source>Transaction must have at least one recipient</source>
<translation type="unfinished">Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° иметь Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одного получателÑ</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">Ð”Ð»Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¸ требуетÑÑ Ð°Ð´Ñ€ÐµÑ Ñдачи, но Ñгенерировать его не удалоÑÑŒ.</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ Ñлишком большаÑ</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">Ðе удалоÑÑŒ выделить памÑÑ‚ÑŒ Ð´Ð»Ñ -maxsigcachesize: "%s" МиБ</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
- <translation type="unfinished">Ðевозможно привÑзатьÑÑ Ðº %s на Ñтом компьютере (bind вернул ошибку %s)</translation>
+ <translation type="unfinished">Ðевозможно привÑзатьÑÑ (bind) к %s на Ñтом компьютере (ошибка %s)</translation>
</message>
<message>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
- <translation type="unfinished">Ðевозможно привÑзатьÑÑ Ðº %s на Ñтом компьютере. Возможно, %s уже запущен.</translation>
+ <translation type="unfinished">Ðевозможно привÑзатьÑÑ (bind) к %s на Ñтом компьютере. Возможно, %s уже запущен.</translation>
</message>
<message>
<source>Unable to create the PID file '%s': %s</source>
- <translation type="unfinished">Ðевозможно Ñоздать файл PID '%s': %s</translation>
+ <translation type="unfinished">Ðе удалоÑÑŒ Ñоздать PID-файл "%s": %s</translation>
+ </message>
+ <message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">Ðе удалоÑÑŒ найти UTXO Ð´Ð»Ñ Ð²Ð½ÐµÑˆÐ½ÐµÐ³Ð¾ входа</translation>
</message>
<message>
<source>Unable to generate initial keys</source>
@@ -963,8 +1190,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ %s Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи</translation>
</message>
<message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">Ошибка при разборе параметра -maxuploadtarget: "%s"</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
- <translation type="unfinished">Ðевозможно запуÑтить HTTP-Ñервер. См. подробноÑти в журнале отладки.</translation>
+ <translation type="unfinished">Ðевозможно запуÑтить HTTP-Ñервер. ПодробноÑти в файле debug.log.</translation>
+ </message>
+ <message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">Ðе удалоÑÑŒ выгрузить кошелёк перед миграцией</translation>
</message>
<message>
<source>Unknown -blockfilterindex value %s.</source>
@@ -972,23 +1207,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unknown address type '%s'</source>
- <translation type="unfinished">ÐеизвеÑтный тип адреÑа '%s'</translation>
+ <translation type="unfinished">ÐеизвеÑтный тип адреÑа "%s"</translation>
</message>
<message>
<source>Unknown change type '%s'</source>
- <translation type="unfinished">ÐеизвеÑтный тип Ñдачи '%s'</translation>
+ <translation type="unfinished">ÐеизвеÑтный тип Ñдачи "%s"</translation>
</message>
<message>
<source>Unknown network specified in -onlynet: '%s'</source>
- <translation type="unfinished">ÐеизвеÑÑ‚Ð½Ð°Ñ Ñеть указана в -onlynet: '%s'</translation>
+ <translation type="unfinished">Ð’ -onlynet указана неизвеÑÑ‚Ð½Ð°Ñ Ñеть: "%s"</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">ÐÐµÐ¿Ð¾Ð´Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ð° %s=%s.</translation>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished">Ð’ Ñилу вÑтупили неизвеÑтные правила (versionbit %i)</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Обновление базы данных UTXO</translation>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">Ðеподдерживаемый уровень подробноÑти Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ð° -loglevel=%s. ДоÑтупные значениÑ: %s.</translation>
+ </message>
+ <message>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Ðеподдерживаемый уровень Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ð° %s=%s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
@@ -996,15 +1235,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Verifying blocks…</source>
- <translation type="unfinished">Проверка блоков...</translation>
+ <translation type="unfinished">Проверка блоков…</translation>
</message>
<message>
<source>Verifying wallet(s)…</source>
- <translation type="unfinished">Проверка кошелька(ов)...</translation>
+ <translation type="unfinished">Проверка кошелька(ов)…</translation>
</message>
<message>
<source>Wallet needed to be rewritten: restart %s to complete</source>
- <translation type="unfinished">Ðеобходимо перезапиÑать кошелёк, перезапуÑтите %s Ð´Ð»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ð¸</translation>
+ <translation type="unfinished">Ðеобходимо перезапиÑать кошелёк. ПерезапуÑтите %s Ð´Ð»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ð¸</translation>
</message>
</context>
<context>
@@ -1015,7 +1254,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Show general overview of wallet</source>
- <translation type="unfinished">Отобразить оÑновное окно кошелька</translation>
+ <translation type="unfinished">Показать текущее ÑоÑтоÑние кошелька</translation>
</message>
<message>
<source>&amp;Transactions</source>
@@ -1058,6 +1297,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Создать новый кошелёк</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Свернуть</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Кошелёк:</translation>
</message>
@@ -1072,7 +1315,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Send coins to a Bitcoin address</source>
- <translation type="unfinished">Отправить ÑредÑтва на Биткоин адреÑ</translation>
+ <translation type="unfinished">Отправить ÑредÑтва на биткоин-адреÑ</translation>
</message>
<message>
<source>Backup wallet to another location</source>
@@ -1080,7 +1323,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Change the passphrase used for wallet encryption</source>
- <translation type="unfinished">Изменить пароль иÑпользуемый Ð´Ð»Ñ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ°</translation>
+ <translation type="unfinished">Изменить парольную фразу, иÑпользуемую Ð´Ð»Ñ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ°</translation>
</message>
<message>
<source>&amp;Send</source>
@@ -1092,11 +1335,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Options…</source>
- <translation type="unfinished">&amp;Параметры...</translation>
+ <translation type="unfinished">&amp;Параметры…</translation>
</message>
<message>
<source>&amp;Encrypt Wallet…</source>
- <translation type="unfinished">&amp;Зашифровать Кошелёк...</translation>
+ <translation type="unfinished">&amp;Зашифровать кошелёк…</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
@@ -1104,47 +1347,47 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Backup Wallet…</source>
- <translation type="unfinished">&amp;Создать резервную копию кошелька...</translation>
+ <translation type="unfinished">&amp;Сделать резервную копию кошелька…</translation>
</message>
<message>
<source>&amp;Change Passphrase…</source>
- <translation type="unfinished">&amp;Изменить пароль...</translation>
+ <translation type="unfinished">&amp;Изменить парольную фразу…</translation>
</message>
<message>
<source>Sign &amp;message…</source>
- <translation type="unfinished">ПодпиÑать &amp;Ñообщение...</translation>
+ <translation type="unfinished">ПодпиÑать &amp;Ñообщение…</translation>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation type="unfinished">ПодпиÑать ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñвоими Биткоин кошельками, что-бы доказать, что вы ими владеете</translation>
+ <translation type="unfinished">ПодпиÑать Ñообщение биткоин-адреÑом, чтобы доказать, что вы им владеете</translation>
</message>
<message>
<source>&amp;Verify message…</source>
- <translation type="unfinished">&amp;Проверить Ñообщение</translation>
+ <translation type="unfinished">&amp;Проверить Ñообщение…</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation type="unfinished">ПроверÑйте ÑообщениÑ, чтобы убедитьÑÑ, что они подпиÑаны конкретными биткоин-адреÑами</translation>
+ <translation type="unfinished">Проверить подпиÑÑŒ ÑообщениÑ, чтобы убедитьÑÑ, что оно подпиÑано конкретным биткоин-адреÑом</translation>
</message>
<message>
<source>&amp;Load PSBT from file…</source>
- <translation type="unfinished">&amp;Загрузить PSBT из файла...</translation>
+ <translation type="unfinished">&amp;Загрузить PSBT из файла…</translation>
</message>
<message>
<source>Open &amp;URI…</source>
- <translation type="unfinished">О&amp;ткрыть URI...</translation>
+ <translation type="unfinished">Открыть &amp;URI…</translation>
</message>
<message>
<source>Close Wallet…</source>
- <translation type="unfinished">Закрыть кошелёк...</translation>
+ <translation type="unfinished">Закрыть кошелёк…</translation>
</message>
<message>
<source>Create Wallet…</source>
- <translation type="unfinished">Создать кошелёк...</translation>
+ <translation type="unfinished">Создать кошелёк…</translation>
</message>
<message>
<source>Close All Wallets…</source>
- <translation type="unfinished">Закрыть вÑе кошельки...</translation>
+ <translation type="unfinished">Закрыть вÑе кошельки…</translation>
</message>
<message>
<source>&amp;File</source>
@@ -1164,27 +1407,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Syncing Headers (%1%)…</source>
- <translation type="unfinished">Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð² (%1%)...</translation>
+ <translation type="unfinished">Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð² (%1%)…</translation>
</message>
<message>
<source>Synchronizing with network…</source>
- <translation type="unfinished">Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ Ñетью...</translation>
+ <translation type="unfinished">Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ Ñетью…</translation>
</message>
<message>
<source>Indexing blocks on disk…</source>
- <translation type="unfinished">ИндекÑÐ°Ñ†Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¾Ð² на диÑке...</translation>
+ <translation type="unfinished">ИндекÑÐ°Ñ†Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¾Ð² на диÑке…</translation>
</message>
<message>
<source>Processing blocks on disk…</source>
- <translation type="unfinished">Обработка блоков на диÑке...</translation>
+ <translation type="unfinished">Обработка блоков на диÑке…</translation>
</message>
<message>
<source>Reindexing blocks on disk…</source>
- <translation type="unfinished">ПереиндекÑÐ°Ñ†Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¾Ð² на диÑке...</translation>
+ <translation type="unfinished">ПереиндекÑÐ°Ñ†Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¾Ð² на диÑке…</translation>
</message>
<message>
<source>Connecting to peers…</source>
- <translation type="unfinished">Подключение к узлам...</translation>
+ <translation type="unfinished">Подключение к узлам…</translation>
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
@@ -1192,22 +1435,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
- <translation type="unfinished">Показать ÑпиÑок адреÑов, на которые были отправлены ÑредÑтва, и их метки</translation>
+ <translation type="unfinished">Показать ÑпиÑок иÑпользованных адреÑов отправки и меток</translation>
</message>
<message>
<source>Show the list of used receiving addresses and labels</source>
- <translation type="unfinished">Показать ÑпиÑок адреÑов, на которые были получены ÑредÑтва, и их метки</translation>
+ <translation type="unfinished">Показать ÑпиÑок иÑпользованных адреÑов Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸ меток</translation>
</message>
<message>
<source>&amp;Command-line options</source>
- <translation type="unfinished">Параметры &amp;командной Ñтроки</translation>
+ <translation type="unfinished">&amp;Параметры командной Ñтроки</translation>
</message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Обработан %n блок иÑтории транзакций.</numerusform>
+ <numerusform>Обработано %n блока иÑтории транзакций.</numerusform>
+ <numerusform>Обработано %n блоков иÑтории транзакций.</numerusform>
</translation>
</message>
<message>
@@ -1216,7 +1459,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Catching up…</source>
- <translation type="unfinished">СинхронизациÑ...</translation>
+ <translation type="unfinished">СинхронизациÑ…</translation>
</message>
<message>
<source>Last received block was generated %1 ago.</source>
@@ -1240,13 +1483,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Up to date</source>
- <translation type="unfinished">Синхронизировано</translation>
+ <translation type="unfinished">Синхронизированно</translation>
</message>
<message>
<source>Load Partially Signed Bitcoin Transaction</source>
<translation type="unfinished">Загрузить чаÑтично подпиÑанную биткоин-транзакцию (PSBT)</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">Загрузить PSBT из &amp;буфера обмена…</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">Загрузить чаÑтично подпиÑанную биткоин-транзакцию из буфера обмена</translation>
</message>
@@ -1283,12 +1530,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Закрыть кошелёк</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">ВоÑÑтановить кошелёк…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">ВоÑÑтановить кошелек из резервной копии</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Закрыть вÑе кошельки</translation>
</message>
<message>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
- <translation type="unfinished">Показать помощь по %1, чтобы получить ÑпиÑок доÑтупных параметров командной Ñтроки</translation>
+ <translation type="unfinished">Показать Ñправку %1 Ñо ÑпиÑком доÑтупных параметров командной Ñтроки</translation>
</message>
<message>
<source>&amp;Mask values</source>
@@ -1307,12 +1564,32 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðет доÑтупных кошельков</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Данные кошелька</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Загрузить резервную копию кошелька</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">ВоÑÑтановить кошелёк</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Ðазвание кошелька</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Окно</translation>
</message>
<message>
<source>Zoom</source>
- <translation type="unfinished">МаÑштаб</translation>
+ <translation type="unfinished">Развернуть</translation>
</message>
<message>
<source>Main Window</source>
@@ -1322,13 +1599,21 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 клиент</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Скрыть</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">&amp;Показать</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n активное подключение к Ñети Bitcoin.</numerusform>
+ <numerusform>%n активных Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñети Bitcoin.</numerusform>
+ <numerusform>%n активных подключений к Ñети Bitcoin.</numerusform>
</translation>
</message>
<message>
@@ -1352,6 +1637,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Включить взаимодейÑтвие Ñ Ñетью</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">ПредÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð² (%1%)…</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Ошибка: %1</translation>
</message>
@@ -1386,7 +1675,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Label: %1
</source>
- <translation type="unfinished">Ярлык: %1
+ <translation type="unfinished">Метка: %1
</translation>
</message>
<message>
@@ -1487,7 +1776,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Received with label</source>
- <translation type="unfinished">Получено на метку</translation>
+ <translation type="unfinished">Получено Ñ Ð¼ÐµÑ‚ÐºÐ¾Ð¹</translation>
</message>
<message>
<source>Received with address</source>
@@ -1510,6 +1799,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Копировать Ñумму</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Копировать адреÑ</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Копировать &amp;метку</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Копировать Ñ&amp;умму</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Скопировать &amp;ID транзакции и Ð¸Ð½Ð´ÐµÐºÑ Ð²Ñ‹Ð²Ð¾Ð´Ð°</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">З&amp;аблокировать неизраÑходованный оÑтаток</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;Разблокировать неизраÑходованный оÑтаток</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Копировать количеÑтво</translation>
</message>
@@ -1519,7 +1832,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Copy after fee</source>
- <translation type="unfinished">Копировать поÑле комиÑÑии</translation>
+ <translation type="unfinished">Копировать Ñумму поÑле комиÑÑии</translation>
</message>
<message>
<source>Copy bytes</source>
@@ -1551,7 +1864,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
- <translation type="unfinished">Может менÑÑ‚ÑŒÑÑ +/- %1 Ñатоши за вход.</translation>
+ <translation type="unfinished">Может менÑÑ‚ÑŒÑÑ Ð½Ð° +/- %1 Ñатоши за каждый вход.</translation>
</message>
<message>
<source>(no label)</source>
@@ -1576,7 +1889,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
- <translation type="unfinished">Создание кошелька &lt;b&gt;%1&lt;/b&gt;...</translation>
+ <translation type="unfinished">Создание кошелька &lt;b&gt;%1&lt;/b&gt;…</translation>
</message>
<message>
<source>Create wallet failed</source>
@@ -1584,9 +1897,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Create wallet warning</source>
- <translation type="unfinished">Кошелёк Ñоздан</translation>
+ <translation type="unfinished">Предупреждение при Ñоздании кошелька</translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Ðевозможно отобразить подпиÑантов</translation>
</message>
- </context>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Обнаружено Ñлишком много внешних подпиÑантов</translation>
+ </message>
+</context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">Загрузить кошельки</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">Загрузка кошельков…</translation>
+ </message>
+</context>
<context>
<name>OpenWalletActivity</name>
<message>
@@ -1609,7 +1943,35 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
- <translation type="unfinished">ОткрываетÑÑ ÐºÐ¾ÑˆÐµÐ»Ñ‘Ðº &lt;b&gt;%1&lt;/b&gt;...</translation>
+ <translation type="unfinished">ОткрываетÑÑ ÐºÐ¾ÑˆÐµÐ»Ñ‘Ðº &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">ВоÑÑтановить кошелёк</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">ВоÑÑтановление кошелька &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Ðе удалоÑÑŒ воÑÑтановить кошелек</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Предупреждение при воÑÑтановлении кошелька</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Сообщение при воÑÑтановлении кошелька</translation>
</message>
</context>
<context>
@@ -1632,7 +1994,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Are you sure you wish to close all wallets?</source>
- <translation type="unfinished">Ð’Ñ‹ уверенны, что хотите закрыть вÑе кошельки?</translation>
+ <translation type="unfinished">Ð’Ñ‹ уверены, что хотите закрыть вÑе кошельки?</translation>
</message>
</context>
<context>
@@ -1663,7 +2025,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
- <translation type="unfinished">Отключить приватные ключи Ð´Ð»Ñ Ñтого кошелька. Ð’ кошельках Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ приватными ключами не ÑохранÑÑŽÑ‚ÑÑ Ð¿Ñ€Ð¸Ð²Ð°Ñ‚Ð½Ñ‹Ðµ ключи, в них Ð½ÐµÐ»ÑŒÐ·Ñ Ñоздать HD маÑтер-ключ или импортировать приватные ключи. Это удобно Ð´Ð»Ñ Ð½Ð°Ð±Ð»ÑŽÐ´Ð°ÑŽÑ‰Ð¸Ñ… кошельков.</translation>
+ <translation type="unfinished">Отключить приватные ключи Ð´Ð»Ñ Ñтого кошелька. Ð’ кошельках Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ приватными ключами не ÑохранÑÑŽÑ‚ÑÑ Ð¿Ñ€Ð¸Ð²Ð°Ñ‚Ð½Ñ‹Ðµ ключи, в них Ð½ÐµÐ»ÑŒÐ·Ñ Ñоздать HD маÑтер-ключ или импортировать приватные ключи. Это отличный вариант Ð´Ð»Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ¾Ð² Ð´Ð»Ñ Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ Ð·Ð° баланÑом.</translation>
</message>
<message>
<source>Disable Private Keys</source>
@@ -1686,14 +2048,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ДеÑкрипторный кошелёк</translation>
</message>
<message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">ИÑпользовать внешнее уÑтройÑтво Ð´Ð»Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñи. Ðапример, аппаратный кошелек. Сначала наÑтройте Ñценарий внешней подпиÑи в наÑтройках кошелька.</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">ВнешнÑÑ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ñторона</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">Создать</translation>
</message>
<message>
<source>Compiled without sqlite support (required for descriptor wallets)</source>
- <translation type="unfinished">Скомпилирован без поддержки sqlite (необходимо Ð´Ð»Ñ Ð´ÐµÑкрипторных кошельков)</translation>
+ <translation type="unfinished">Скомпилирован без поддержки SQLite (он необходим Ð´Ð»Ñ Ð´ÐµÑкрипторных кошельков)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Скомпилирован без поддержки внешней подпиÑи (требуетÑÑ Ð´Ð»Ñ Ð²Ð½ÐµÑˆÐ½ÐµÐ¹ подпиÑи)</translation>
</message>
- </context>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -1710,7 +2085,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
- <translation type="unfinished">ÐдреÑ, ÑвÑзанный Ñ Ñтой запиÑью адреÑной книги. Он может быть изменён только еÑли Ñто Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸.</translation>
+ <translation type="unfinished">ÐдреÑ, ÑвÑзанный Ñ Ñтой запиÑью адреÑной книги. ЕÑли Ñто Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸, его можно изменить.</translation>
</message>
<message>
<source>&amp;Address</source>
@@ -1718,15 +2093,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>New sending address</source>
- <translation type="unfinished">Ðовый Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸</translation>
+ <translation type="unfinished">Ðовый Ð°Ð´Ñ€ÐµÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸</translation>
</message>
<message>
<source>Edit receiving address</source>
- <translation type="unfinished">Изменить Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ</translation>
+ <translation type="unfinished">Изменить Ð°Ð´Ñ€ÐµÑ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ</translation>
</message>
<message>
<source>Edit sending address</source>
- <translation type="unfinished">Изменить Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸</translation>
+ <translation type="unfinished">Изменить Ð°Ð´Ñ€ÐµÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸</translation>
</message>
<message>
<source>The entered address "%1" is not a valid Bitcoin address.</source>
@@ -1746,74 +2121,86 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>New key generation failed.</source>
- <translation type="unfinished">Произошла ошибка при генерации нового ключа.</translation>
+ <translation type="unfinished">Ðе удалоÑÑŒ Ñгенерировать новый ключ.</translation>
</message>
</context>
<context>
<name>FreespaceChecker</name>
<message>
<source>A new data directory will be created.</source>
- <translation type="unfinished">Будет Ñоздана Ð½Ð¾Ð²Ð°Ñ Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ….</translation>
+ <translation type="unfinished">Будет Ñоздан новый каталог данных.</translation>
</message>
<message>
<source>name</source>
- <translation type="unfinished">имÑ</translation>
+ <translation type="unfinished">название</translation>
</message>
<message>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation type="unfinished">Ð”Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ ÑƒÐ¶Ðµ ÑущеÑтвует. Добавьте %1, еÑли хотите Ñоздать здеÑÑŒ новую директорию.</translation>
+ <translation type="unfinished">Каталог уже ÑущеÑтвует. Добавьте %1, еÑли хотите Ñоздать здеÑÑŒ новый каталог.</translation>
</message>
<message>
<source>Path already exists, and is not a directory.</source>
- <translation type="unfinished">Данный путь уже ÑущеÑтвует, и Ñто не директориÑ.</translation>
+ <translation type="unfinished">Данный путь уже ÑущеÑтвует, и Ñто не каталог.</translation>
</message>
<message>
<source>Cannot create data directory here.</source>
- <translation type="unfinished">Ðевозможно Ñоздать директорию данных здеÑÑŒ.</translation>
+ <translation type="unfinished">Ðевозможно Ñоздать здеÑÑŒ каталог данных.</translation>
</message>
</context>
<context>
<name>Intro</name>
- <message>
- <source>Bitcoin</source>
- <translation type="unfinished">биткоин</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n ГБ меÑта доÑтупен</numerusform>
+ <numerusform>%n ГБ меÑта доÑтупно</numerusform>
+ <numerusform>%n ГБ меÑта доÑтупно</numerusform>
+ </translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(из необходимых %1 ГБ)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(из требуемого %n ГБ)</numerusform>
+ <numerusform>(из требуемых %n ГБ)</numerusform>
+ <numerusform>(из требуемых %n ГБ)</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(необходимо %1 ГБ Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð¹ цепочки блоков)</translation>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n ГБ необходим Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð¹ цепочки)</numerusform>
+ <numerusform>(%n ГБ необходимо Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð¹ цепочки)</numerusform>
+ <numerusform>(%n ГБ необходимо Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð¹ цепочки)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
- <translation type="unfinished">Ð’ Ñту директорию будет Ñохранено не менее %1 ГБ данных, и Ñо временем их объём будет увеличиватьÑÑ.</translation>
+ <translation type="unfinished">Ð’ Ñтот каталог будет Ñохранено не менее %1 ГБ данных, и Ñо временем их объём будет увеличиватьÑÑ.</translation>
</message>
<message>
<source>Approximately %1 GB of data will be stored in this directory.</source>
- <translation type="unfinished">Ð’ Ñту директорию будет Ñохранено приблизительно %1 ГБ данных.</translation>
+ <translation type="unfinished">Ð’ Ñтот каталог будет Ñохранено приблизительно %1 ГБ данных.</translation>
</message>
<message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>(доÑтаточно Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ð¹ копии возраÑтом %n день)</numerusform>
+ <numerusform>(доÑтаточно Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ð¹ копии возраÑтом %n днÑ)</numerusform>
+ <numerusform>(доÑтаточно Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ð¹ копии возраÑтом %n дней)</numerusform>
</translation>
</message>
<message>
<source>%1 will download and store a copy of the Bitcoin block chain.</source>
- <translation type="unfinished">%1 Ñкачает и Ñохранит копию цепочки блоков биткоина.</translation>
+ <translation type="unfinished">%1 Ñкачает и Ñохранит копию цепочки блоков Bitcoin.</translation>
</message>
<message>
<source>The wallet will also be stored in this directory.</source>
- <translation type="unfinished">Кошелёк также будет Ñохранен в Ñту директорию.</translation>
+ <translation type="unfinished">Кошелёк также будет Ñохранён в Ñтот каталог.</translation>
</message>
<message>
<source>Error: Specified data directory "%1" cannot be created.</source>
- <translation type="unfinished">Ошибка: невозможно Ñоздать указанную директорию данных "%1".</translation>
+ <translation type="unfinished">Ошибка: не удалоÑÑŒ Ñоздать указанный каталог данных "%1".</translation>
</message>
<message>
<source>Error</source>
@@ -1832,10 +2219,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ПоÑкольку программа запущена впервые, вы можете выбрать, где %1 будет хранить Ñвои данные.</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 type="unfinished">Когда вы нажмёте ОК, %1 начнет Ñкачивать и обрабатывать полную цепочку блоков %4а (%2 ГБ), Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Ñамых первых транзакций в %3, когда %4 был изначально запущен.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Ограничить размер Ñохранённой цепочки блоков до</translation>
</message>
@@ -1852,16 +2235,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Эта Ð¿ÐµÑ€Ð²Ð¸Ñ‡Ð½Ð°Ñ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¾Ñ‡ÐµÐ½ÑŒ требовательна к реÑурÑам и может выÑвить проблемы Ñ Ð°Ð¿Ð¿Ð°Ñ€Ð°Ñ‚Ð½Ñ‹Ð¼ обеÑпечением вашего компьютера, которые ранее оÑтавалиÑÑŒ незамеченными. Каждый раз, когда вы запуÑкаете %1, Ñкачивание будет продолжено Ñ Ð¼ÐµÑта оÑтановки.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Когда вы нажмете ОК, %1 начнет загружать и обрабатывать полную цепочку блоков %4 (%2 ГБ) Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Ñамых ранних транзакций в %3, когда %4 был первоначально запущен.</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 type="unfinished">ЕÑли вы решили ограничить объём хранимого блокчейна (обрезка), вÑе иÑторичеÑкие данные вÑÑ‘ равно необходимо Ñкачать и обработать, но поÑле Ñтого они будут удалены Ð´Ð»Ñ Ñкономии меÑта на диÑке.</translation>
+ <translation type="unfinished">ЕÑли вы решили ограничить (обрезать) объём хранимой цепи блоков, вÑе ранние данные вÑÑ‘ равно должны быть Ñкачаны и обработаны. ПоÑле обработки они будут удалены Ñ Ñ†ÐµÐ»ÑŒÑŽ Ñкономии меÑта на диÑке.</translation>
</message>
<message>
<source>Use the default data directory</source>
- <translation type="unfinished">ИÑпользовать Ñтандартную директорию данных</translation>
+ <translation type="unfinished">ИÑпользовать каталог данных по умолчанию</translation>
</message>
<message>
<source>Use a custom data directory:</source>
- <translation type="unfinished">ИÑпользовать пользовательÑкую директорию данных</translation>
+ <translation type="unfinished">ИÑпользовать пользовательÑкий каталог данных:</translation>
</message>
</context>
<context>
@@ -1876,14 +2263,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Command-line options</source>
- <translation type="unfinished">Параметры командной Ñтроки</translation>
+ <translation type="unfinished">Опции командной Ñтроки</translation>
</message>
</context>
<context>
<name>ShutdownWindow</name>
<message>
<source>%1 is shutting down…</source>
- <translation type="unfinished">%1 завершает работу...</translation>
+ <translation type="unfinished">%1 выключаетÑÑ…</translation>
</message>
<message>
<source>Do not shut down the computer until this window disappears.</source>
@@ -1898,11 +2285,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">Ðедавние транзакции могут быть пока не видны, и поÑтому отображаемый Ð±Ð°Ð»Ð°Ð½Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ кошелька может быть неверным. Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñтанет верной поÑле Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñинхронизации Ñ Ñетью биткоина, прогреÑÑ ÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð¹ вы можете видеть ниже.</translation>
+ <translation type="unfinished">Ðедавние транзакции могут быть пока не видны, и поÑтому отображаемый Ð±Ð°Ð»Ð°Ð½Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ кошелька может быть неверным. Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñтанет верной поÑле Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñинхронизации Ñ Ñетью 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 type="unfinished">Попытка потратить ÑредÑтва, затронутые не видными пока транзакциÑми, будет отклонена Ñетью.</translation>
+ <translation type="unfinished">Попытка потратить ÑредÑтва, иÑпользованные в транзакциÑÑ…, которые ещё не Ñинхронизированы, будет отклонена Ñетью.</translation>
</message>
<message>
<source>Number of blocks left</source>
@@ -1910,11 +2297,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unknown…</source>
- <translation type="unfinished">ÐеизвеÑтно...</translation>
+ <translation type="unfinished">ÐеизвеÑтно…</translation>
</message>
<message>
<source>calculating…</source>
- <translation type="unfinished">вычиÑлÑетÑÑ...</translation>
+ <translation type="unfinished">вычиÑлÑетÑÑ…</translation>
</message>
<message>
<source>Last block time</source>
@@ -1930,7 +2317,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Estimated time left until synced</source>
- <translation type="unfinished">РаÑчётное Ð²Ñ€ÐµÐ¼Ñ Ð´Ð¾ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñинхронизации</translation>
+ <translation type="unfinished">РаÑчетное Ð²Ñ€ÐµÐ¼Ñ Ð´Ð¾ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñинхронизации</translation>
</message>
<message>
<source>Hide</source>
@@ -1938,7 +2325,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Esc</source>
- <translation type="unfinished">Выйти</translation>
+ <translation type="unfinished">Выход</translation>
</message>
<message>
<source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
@@ -1946,14 +2333,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
- <translation type="unfinished">ÐеизвеÑтно. СинхронизируютÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¸ (%1, %2%)...</translation>
+ <translation type="unfinished">ÐеизвеÑтно. Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð² (%1, %2%)…</translation>
+ </message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">ÐеизвеÑтно. ПредÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð² (%1, %2%)…</translation>
</message>
</context>
<context>
<name>OpenURIDialog</name>
<message>
<source>Open bitcoin URI</source>
- <translation type="unfinished">Открыть URI биткоина</translation>
+ <translation type="unfinished">Открыть URI bitcoin</translation>
</message>
<message>
<source>Paste address from clipboard</source>
@@ -1969,11 +2360,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Main</source>
- <translation type="unfinished">&amp;Главные</translation>
+ <translation type="unfinished">&amp;ОÑновное</translation>
</message>
<message>
<source>Automatically start %1 after logging in to the system.</source>
- <translation type="unfinished">ÐвтоматичеÑки запуÑкать %1 поÑле входа в ÑиÑтему.</translation>
+ <translation type="unfinished">ÐвтоматичеÑки запуÑкать %1поÑле входа в ÑиÑтему.</translation>
</message>
<message>
<source>&amp;Start %1 on system login</source>
@@ -1997,15 +2388,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
- <translation type="unfinished">Показывает, иÑпользуетÑÑ Ð»Ð¸ прокÑи SOCKS5 по умолчанию Ð´Ð»Ñ Ð´Ð¾Ñтупа к узлам через Ñтот тип Ñети.</translation>
+ <translation type="unfinished">ИÑпользовать SOCKS5 прокÑи Ð´Ð»Ñ Ð´Ð¾Ñтупа к узлам через Ñтот тип Ñети.</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 type="unfinished">Сворачивать вмеÑто выхода из Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ закрытии окна. ЕÑли данный параметр включён, приложение закроетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ поÑле Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ "Выход" в меню.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Параметры командной Ñтроки, которые переопределили параметры из Ñтого окна:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
- <translation type="unfinished">Открывает файл конфигурации %1 из рабочей директории.</translation>
+ <translation type="unfinished">Открывает файл конфигурации %1 из рабочего каталога.</translation>
</message>
<message>
<source>Open Configuration File</source>
@@ -2025,7 +2420,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Prune &amp;block storage to</source>
- <translation type="unfinished">Обрезать объём хранимых блоков до</translation>
+ <translation type="unfinished">Обрезать &amp;объём хранимых блоков до</translation>
</message>
<message>
<source>GB</source>
@@ -2036,28 +2431,48 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Возврат Ñтой наÑтройки в прежнее значение потребует повторного ÑÐºÐ°Ñ‡Ð¸Ð²Ð°Ð½Ð¸Ñ Ð²Ñей цепочки блоков.</translation>
</message>
<message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">МакÑимальный размер кÑша базы данных. Большой размер кÑша может уÑкорить Ñинхронизацию, поÑле чего уже оÑобой роли не играет. Уменьшение размера кÑша уменьшит иÑпользование памÑти. ÐеиÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÐµÐ¼Ð°Ñ Ð¿Ð°Ð¼ÑÑ‚ÑŒ mempool иÑпользуетÑÑ ÑовмеÑтно Ð´Ð»Ñ Ñтого кÑша.</translation>
+ </message>
+ <message>
<source>MiB</source>
<translation type="unfinished">МиБ</translation>
</message>
<message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">ЧиÑло потоков проверки Ñкриптов. Отрицательные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð·Ð°Ð´Ð°ÑŽÑ‚ чиÑло Ñдер ЦП, которые не будут нагружатьÑÑ (оÑтанутÑÑ Ñвободны).</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = автоматичеÑки, &lt;0 = оÑтавить Ñтолько Ñдер Ñвободными)</translation>
</message>
<message>
<source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
<extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
- <translation type="unfinished">Это позволÑет вам или Ñторонней программе взаимодейÑтвовать Ñ Ñтим узлом через командную Ñтроку и команды JSON-RPC</translation>
+ <translation type="unfinished">Разрешает вам или Ñторонней программе взаимодейÑтвовать Ñ Ñтим узлом через командную Ñтроку и команды JSON-RPC.</translation>
</message>
<message>
<source>Enable R&amp;PC server</source>
<extracomment>An Options window setting to enable the RPC server.</extracomment>
- <translation type="unfinished">Включить R&amp;PC Ñервер</translation>
+ <translation type="unfinished">Включить RPC &amp;Ñервер</translation>
</message>
<message>
<source>W&amp;allet</source>
<translation type="unfinished">&amp;Кошелёк</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Вычитать комиÑÑию из Ñуммы по умолчанию или нет.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">ВычеÑÑ‚ÑŒ &amp;комиÑÑию из Ñуммы</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">ЭкÑпертные наÑтройки</translation>
</message>
@@ -2067,13 +2482,35 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">ЕÑли вы отключите трату неподтверждённой Ñдачи, Ñдачу от транзакции Ð½ÐµÐ»ÑŒÐ·Ñ Ð±ÑƒÐ´ÐµÑ‚ иÑпользвать до тех пор, пока у Ñтой транзакции не будет Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одного подтверждениÑ. Это также влиÑет на раÑчёт вашего баланÑа.</translation>
+ <translation type="unfinished">ЕÑли вы отключите трату неподтверждённой Ñдачи, Ñдачу от транзакции Ð½ÐµÐ»ÑŒÐ·Ñ Ð±ÑƒÐ´ÐµÑ‚ иÑпользовать до тех пор, пока у Ñтой транзакции не будет Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одного подтверждениÑ. Это также влиÑет на раÑчёт вашего баланÑа.</translation>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
<translation type="unfinished">&amp;Тратить неподтверждённую Ñдачу</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Включить управление чаÑтично подпиÑанными транзакциÑми (PSBT)</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Показать Ñлементы ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñ‡Ð°Ñтично подпиÑанными биткоин-транзакциÑми (PSBT)</translation>
+ </message>
+ <message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">Внешний подпиÑант (например, аппаратный кошелёк)</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;Внешний Ñкрипт Ð´Ð»Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñи</translation>
+ </message>
+ <message>
+ <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished">Путь к Ñкрипту, ÑовмеÑтимому Ñ Bitcoin Core (напр. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Внимание: оÑтерегайтеÑÑŒ вредоноÑных Ñкриптов!</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 type="unfinished">ÐвтоматичеÑки открыть порт биткоин-клиента на маршрутизаторе. Работает, еÑли ваш маршрутизатор поддерживает UPnP, и Ð´Ð°Ð½Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð½Ð° нём включена.</translation>
</message>
@@ -2083,7 +2520,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
- <translation type="unfinished">ÐвтоматичеÑки открыть порт биткоин-клиента на роутере. Работает? еÑли ваш роутер поддерживает NAT-PMP, и Ð´Ð°Ð½Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð½Ð° нём включена. Внешний порт может быть Ñлучайным.</translation>
+ <translation type="unfinished">ÐвтоматичеÑки открыть порт биткоин-клиента на роутере. Сработает только еÑли ваш роутер поддерживает NAT-PMP, и Ð´Ð°Ð½Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð½Ð° нём включена. Внешний порт может быть Ñлучайным.</translation>
</message>
<message>
<source>Map port using NA&amp;T-PMP</source>
@@ -2095,11 +2532,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Allow incomin&amp;g connections</source>
- <translation type="unfinished">Разрешить входÑщие ÑоединениÑ</translation>
+ <translation type="unfinished">Разрешить &amp;входÑщие ÑоединениÑ</translation>
</message>
<message>
<source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
- <translation type="unfinished">ПодключитьÑÑ Ðº Ñети биткоина через прокÑи SOCKS5.</translation>
+ <translation type="unfinished">ПодключитьÑÑ Ðº Ñети Bitcoin через SOCKS5 прокÑи.</translation>
</message>
<message>
<source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
@@ -2107,7 +2544,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Proxy &amp;IP:</source>
- <translation type="unfinished">IP прокÑи:</translation>
+ <translation type="unfinished">IP &amp;прокÑи:</translation>
</message>
<message>
<source>&amp;Port:</source>
@@ -2115,11 +2552,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Port of the proxy (e.g. 9050)</source>
- <translation type="unfinished">Порт прокÑи: (напр. 9050)</translation>
+ <translation type="unfinished">Порт прокÑи (например, 9050)</translation>
</message>
<message>
<source>Used for reaching peers via:</source>
- <translation type="unfinished">ИÑпользуетÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº узлам по:</translation>
+ <translation type="unfinished">ИÑпользовать Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº узлам по:</translation>
</message>
<message>
<source>&amp;Window</source>
@@ -2151,11 +2588,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>User Interface &amp;language:</source>
- <translation type="unfinished">Язык пользовательÑкого интерфейÑа:</translation>
+ <translation type="unfinished">Язык &amp;интерфейÑа:</translation>
</message>
<message>
<source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
- <translation type="unfinished">ЗдеÑÑŒ можно выбрать Ñзык пользовательÑкого интерфейÑа. Параметры будут применены поÑле перезапуÑка %1</translation>
+ <translation type="unfinished">ЗдеÑÑŒ можно выбрать Ñзык пользовательÑкого интерфейÑа. Язык будет изменён поÑле перезапуÑка %1.</translation>
</message>
<message>
<source>&amp;Unit to show amounts in:</source>
@@ -2166,16 +2603,24 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Выберите единицу измерениÑ, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±ÑƒÐ´ÐµÑ‚ показана по умолчанию в интерфейÑе и при отправке монет.</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 type="unfinished">Сторонние URL-адреÑа (например, на обозреватель блоков), которые будут показаны на вкладке транзакций в контекÑтном меню. %s в URL будет заменён на Ñ…Ñш транзакции. ÐеÑколько адреÑов разделÑÑŽÑ‚ÑÑ Ð´Ñ€ÑƒÐ³ от друга вертикальной чертой |.</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;СÑылки на транзакции на Ñторонних ÑервиÑах</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
- <translation type="unfinished">Показывать ли параметры ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð½ÐµÑ‚Ð°Ð¼Ð¸.</translation>
+ <translation type="unfinished">Показывать параметры ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð½ÐµÑ‚Ð°Ð¼Ð¸.</translation>
</message>
<message>
<source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
- <translation type="unfinished">ПодключатьÑÑ Ðº Ñети биткоина через отдельный прокÑи SOCKS5 Ð´Ð»Ñ Ñкрытых ÑервиÑов Tor.</translation>
+ <translation type="unfinished">ПодключатьÑÑ Ðº Ñети Bitcoin через отдельный SOCKS5 прокÑи Ð´Ð»Ñ Ñкрытых ÑервиÑов Tor.</translation>
</message>
<message>
<source>Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
- <translation type="unfinished">ИÑпользовать отдельный прокÑи SOCKS&amp;5 Ð´Ð»Ñ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ ÑƒÐ·Ð»Ð°Ð¼Ð¸ через Ñкрытые ÑервиÑÑ‹ Tor:</translation>
+ <translation type="unfinished">ИÑпользовать &amp;отдельный прокÑи SOCKS5 Ð´Ð»Ñ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ ÑƒÐ·Ð»Ð°Ð¼Ð¸ через Ñкрытые ÑервиÑÑ‹ Tor:</translation>
</message>
<message>
<source>Monospaced font in the Overview tab:</source>
@@ -2187,11 +2632,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>closest matching "%1"</source>
- <translation type="unfinished">ближайшее Ñовпадение "%1"</translation>
- </message>
- <message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Параметры, уÑтановленные в Ñтом диалоговом окне, были переопределены командной Ñтрокой или в файле конфигурации:</translation>
+ <translation type="unfinished">Ñамый похожий ÑиÑтемный "%1"</translation>
</message>
<message>
<source>&amp;OK</source>
@@ -2202,23 +2643,36 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">О&amp;тмена</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Скомпилирован без поддержки внешней подпиÑи (требуетÑÑ Ð´Ð»Ñ Ð²Ð½ÐµÑˆÐ½ÐµÐ¹ подпиÑи)</translation>
+ </message>
+ <message>
<source>default</source>
<translation type="unfinished">по умолчанию</translation>
</message>
<message>
<source>none</source>
- <translation type="unfinished">ни один</translation>
+ <translation type="unfinished">ни одного</translation>
</message>
<message>
<source>Confirm options reset</source>
- <translation type="unfinished">Подтвердить ÑÐ±Ñ€Ð¾Ñ Ð¾Ð¿Ñ†Ð¸Ð¹</translation>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
+ <translation type="unfinished">Подтверждение ÑброÑа наÑтроек</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Ð”Ð»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ð¸Ð¸ изменений необходим перезапуÑк клиента.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Ð ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ… наÑтроек будет Ñохранена в "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Клиент будет закрыт. Продолжить?</translation>
</message>
<message>
@@ -2257,6 +2711,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Ðе удалоÑÑŒ прочитать наÑтройку "%1", %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2264,11 +2725,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">ÐŸÐ¾ÐºÐ°Ð·Ð°Ð½Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ быть уÑтаревшей. Ваш кошелёк автоматичеÑки ÑинхронизируетÑÑ Ñ Ñетью биткоина поÑле подключениÑ, но Ñтот процеÑÑ Ð¿Ð¾ÐºÐ° не завершён.</translation>
+ <translation type="unfinished">ÐžÑ‚Ð¾Ð±Ñ€Ð°Ð¶Ð°ÐµÐ¼Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ быть уÑтаревшей. Ваш кошелёк автоматичеÑки ÑинхронизируетÑÑ Ñ Ñетью Bitcoin поÑле подключениÑ, и Ñтот процеÑÑ Ð¿Ð¾ÐºÐ° не завершён.</translation>
</message>
<message>
<source>Watch-only:</source>
- <translation type="unfinished">Только наблюдение:</translation>
+ <translation type="unfinished">Только проÑмотр:</translation>
</message>
<message>
<source>Available:</source>
@@ -2284,7 +2745,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
- <translation type="unfinished">ÐžÐ±Ñ‰Ð°Ñ Ñумма вÑех транзакций, которые ещё не подтверждены и не учитываютÑÑ Ð² баланÑе, который можно раÑходовать</translation>
+ <translation type="unfinished">Сумма по неподтверждённым транзакциÑм. Они не учитываютÑÑ Ð² баланÑе, который можно раÑходовать</translation>
</message>
<message>
<source>Immature:</source>
@@ -2296,7 +2757,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Balances</source>
- <translation type="unfinished">БаланÑÑ‹</translation>
+ <translation type="unfinished">БаланÑ</translation>
</message>
<message>
<source>Total:</source>
@@ -2332,7 +2793,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
- <translation type="unfinished">Включён режим приватноÑти Ð´Ð»Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ¸ обзора. Чтобы показать данные, отключите пункт ÐаÑтройки -&gt; Скрыть значениÑ.</translation>
+ <translation type="unfinished">Включён режим приватноÑти Ð´Ð»Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ¸ Обзор. Чтобы показать данные, Ñнимите отметку Ñ Ð¿ÑƒÐ½ÐºÑ‚Ð° ÐаÑтройки -&gt; Скрыть значениÑ.</translation>
</message>
</context>
<context>
@@ -2355,7 +2816,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Save…</source>
- <translation type="unfinished">Сохранить...</translation>
+ <translation type="unfinished">Сохранить…</translation>
</message>
<message>
<source>Close</source>
@@ -2447,6 +2908,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Транзакции требуетÑÑ Ð¿Ð¾ крайней мере ещё одна подпиÑÑŒ.</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Ðо ни один кошелек не загружен.)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Ðо Ñтот кошелёк не может подпиÑывать транзакции.)</translation>
</message>
@@ -2456,7 +2921,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Transaction is fully signed and ready for broadcast.</source>
- <translation type="unfinished">Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ Ð¿Ð¾Ð»Ð½Ð¾Ñтью подпиÑана, и готова к отправке.</translation>
+ <translation type="unfinished">Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ Ð¿Ð¾Ð»Ð½Ð¾Ñтью подпиÑана и готова к отправке.</translation>
</message>
<message>
<source>Transaction status is unknown.</source>
@@ -2479,19 +2944,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
- <translation type="unfinished">«bitcoin://» — Ñто неверный URI. ИÑпользуйте вмеÑто него «bitcoin:».</translation>
+ <translation type="unfinished">"bitcoin://" — Ñто неверный URI. ИÑпользуйте вмеÑто него "bitcoin:".</translation>
</message>
<message>
<source>Cannot process payment request because BIP70 is not supported.
Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
<translation type="unfinished">Ðе удалоÑÑŒ обработать транзакцию, потому что BIP70 не поддерживаетÑÑ.
-Из-за широко раÑпроÑтранённых уÑзвимоÑтей в BIP70 наÑтоÑтельно рекомендуетÑÑ Ð¸Ð³Ð½Ð¾Ñ€Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ любые инÑтрукции продавцов Ñменить кошелёк.
+Из-за широко раÑпроÑтранённых уÑзвимоÑтей в BIP70, наÑтоÑтельно рекомендуетÑÑ Ð¸Ð³Ð½Ð¾Ñ€Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ любые инÑтрукции продавцов Ñменить кошелёк.
ЕÑли вы получили Ñту ошибку, вам Ñледует попроÑить у продавца URI, ÑовмеÑтимый Ñ BIP21.</translation>
</message>
<message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
- <translation type="unfinished">Ðе удалоÑÑŒ обработать URI! Это может быть вызвано тем, что биткоин-Ð°Ð´Ñ€ÐµÑ Ð½ÐµÐ²ÐµÑ€ÐµÐ½ или параметры URI неправильно Ñформированы.</translation>
+ <translation type="unfinished">Ðе удалоÑÑŒ обработать URI! Это может быть вызвано тем, что биткоин-Ð°Ð´Ñ€ÐµÑ Ð½ÐµÐ²ÐµÑ€ÐµÐ½ или параметры URI Ñформированы неправильно.</translation>
</message>
<message>
<source>Payment request file handling</source>
@@ -2508,7 +2973,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<message>
<source>Ping</source>
<extracomment>Title of Peers Table column which indicates the current latency of the connection with the peer.</extracomment>
- <translation type="unfinished">Отклик</translation>
+ <translation type="unfinished">Пинг</translation>
</message>
<message>
<source>Peer</source>
@@ -2516,6 +2981,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">Узел</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">ВозраÑÑ‚</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Ðаправление</translation>
@@ -2560,7 +3030,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<name>QRImageWidget</name>
<message>
<source>&amp;Save Image…</source>
- <translation type="unfinished">&amp;Сохранить изображение...</translation>
+ <translation type="unfinished">&amp;Сохранить изображение…</translation>
</message>
<message>
<source>&amp;Copy Image</source>
@@ -2568,7 +3038,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Resulting URI too long, try to reduce the text for label / message.</source>
- <translation type="unfinished">ПолучившийÑÑ URI Ñлишком длинный, попробуйте Ñократить текÑÑ‚ метки / ÑообщениÑ.</translation>
+ <translation type="unfinished">ПолучившийÑÑ URI Ñлишком длинный, попробуйте Ñократить текÑÑ‚ метки или ÑообщениÑ.</translation>
</message>
<message>
<source>Error encoding URI into QR Code.</source>
@@ -2576,7 +3046,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>QR code support not available.</source>
- <translation type="unfinished">Поддержка QR кодов недоÑтупна.</translation>
+ <translation type="unfinished">Поддержка QR-кодов недоÑтупна.</translation>
</message>
<message>
<source>Save QR Code</source>
@@ -2604,7 +3074,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>General</source>
- <translation type="unfinished">Общий</translation>
+ <translation type="unfinished">Общие</translation>
</message>
<message>
<source>Datadir</source>
@@ -2612,7 +3082,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>To specify a non-default location of the data directory use the '%1' option.</source>
- <translation type="unfinished">Чтобы указать неÑтандартное раÑположение директории Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ…, иÑпользуйте параметр '%1'.</translation>
+ <translation type="unfinished">Чтобы указать неÑтандартное раÑположение каталога данных, иÑпользуйте параметр "%1".</translation>
</message>
<message>
<source>Blocksdir</source>
@@ -2620,7 +3090,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>To specify a non-default location of the blocks directory use the '%1' option.</source>
- <translation type="unfinished">Чтобы указать неÑтандартное раÑположение директории Ð´Ð»Ñ Ð±Ð»Ð¾ÐºÐ¾Ð², иÑпользуйте параметр '%1'.</translation>
+ <translation type="unfinished">Чтобы указать неÑтандартное раÑположение каталога блоков, иÑпользуйте параметр "%1".</translation>
</message>
<message>
<source>Startup time</source>
@@ -2664,7 +3134,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>&amp;Reset</source>
- <translation type="unfinished">&amp;СброÑить</translation>
+ <translation type="unfinished">&amp;СброÑ</translation>
</message>
<message>
<source>Received</source>
@@ -2684,7 +3154,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Select a peer to view detailed information.</source>
- <translation type="unfinished">Выберите узел Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра детальной информации.</translation>
+ <translation type="unfinished">Выберите узел Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра подробноÑтей.</translation>
</message>
<message>
<source>Version</source>
@@ -2703,6 +3173,10 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">Синхронизировано блоков</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">ПоÑледнÑÑ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">ÐŸÐ¾Ð´ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ð°Ñ Ð°Ð²Ñ‚Ð¾Ð½Ð¾Ð¼Ð½Ð°Ñ ÑиÑтема, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÐµÐ¼Ð°Ñ Ð´Ð»Ñ Ð´Ð¸Ð²ÐµÑ€Ñификации узлов, к которым производитÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ðµ.</translation>
</message>
@@ -2711,12 +3185,42 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">ÐŸÐ¾Ð´ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ð°Ñ ÐС</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Передаем ли мы адреÑа Ñтому узлу.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">РетранÑлÑтор адреÑов</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">КоличеÑтво адреÑов, полученных от Ñтого узла, которые были обработаны (за иÑключением адреÑов, отброшенных из-за ограничений по чаÑтоте).</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">КоличеÑтво адреÑов, полученных от Ñтого узла, которые были отброшены (не обработаны) из-за ограничений по чаÑтоте.</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Обработанные адреÑа</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Отброшенные адреÑа</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">ПользовательÑкий агент</translation>
</message>
<message>
<source>Node window</source>
- <translation type="unfinished">Окно ноды</translation>
+ <translation type="unfinished">Окно узла</translation>
</message>
<message>
<source>Current block height</source>
@@ -2724,7 +3228,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</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 type="unfinished">Открыть файл журнала отладки %1 из текущей директории данных. Ð”Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… файлов журнала Ñто может занÑÑ‚ÑŒ неÑколько Ñекунд.</translation>
+ <translation type="unfinished">Открыть файл журнала отладки %1 из текущего каталога данных. Ð”Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… файлов журнала Ñто может занÑÑ‚ÑŒ неÑколько Ñекунд.</translation>
</message>
<message>
<source>Decrease font size</source>
@@ -2752,7 +3256,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Services</source>
- <translation type="unfinished">СервиÑÑ‹</translation>
+ <translation type="unfinished">Службы</translation>
</message>
<message>
<source>Whether the peer requested us to relay transactions.</source>
@@ -2776,7 +3280,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
- <translation type="unfinished">Ð’Ñ€ÐµÐ¼Ñ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ блока, прошедшего базовую проверку, от Ñтого узла</translation>
+ <translation type="unfinished">Ð’Ñ€ÐµÐ¼Ñ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ блока, прошедшего базовую проверку, от Ñтого узла.</translation>
</message>
<message>
<source>Last Block</source>
@@ -2785,15 +3289,15 @@ If you are receiving this error you should request the merchant provide a BIP21
<message>
<source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
<extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
- <translation type="unfinished">Ð’Ñ€ÐµÐ¼Ñ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° принÑÑ‚Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð¹ транзакции в наш мемпул от Ñтого узла.</translation>
+ <translation type="unfinished">Ð’Ñ€ÐµÐ¼Ñ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° принÑÑ‚Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð¹ транзакции в наш mempool от Ñтого узла.</translation>
</message>
<message>
<source>Last Send</source>
- <translation type="unfinished">ПоÑл. Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸</translation>
+ <translation type="unfinished">ПоÑледнее Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸</translation>
</message>
<message>
<source>Last Receive</source>
- <translation type="unfinished">ПоÑл. Ð²Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ</translation>
+ <translation type="unfinished">ПоÑледнее Ð²Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ</translation>
</message>
<message>
<source>Ping Time</source>
@@ -2801,7 +3305,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>The duration of a currently outstanding ping.</source>
- <translation type="unfinished">ПродолжительноÑÑ‚ÑŒ текущего времени отклика.</translation>
+ <translation type="unfinished">Задержка между запроÑом к узлу и ответом от него.</translation>
</message>
<message>
<source>Ping Wait</source>
@@ -2809,7 +3313,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Min Ping</source>
- <translation type="unfinished">Мин. Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ‚ÐºÐ»Ð¸ÐºÐ°</translation>
+ <translation type="unfinished">Минимальное Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ‚ÐºÐ»Ð¸ÐºÐ°</translation>
</message>
<message>
<source>Time Offset</source>
@@ -2894,6 +3398,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">широкополоÑный передатчик не выбран</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Копировать адреÑ</translation>
+ </message>
+ <message>
<source>&amp;Disconnect</source>
<translation type="unfinished">О&amp;тключитьÑÑ</translation>
</message>
@@ -2902,6 +3411,10 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">1 &amp;чаÑ</translation>
</message>
<message>
+ <source>1 d&amp;ay</source>
+ <translation type="unfinished">1 &amp;день</translation>
+ </message>
+ <message>
<source>1 &amp;week</source>
<translation type="unfinished">1 &amp;неделÑ</translation>
</message>
@@ -2910,6 +3423,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">1 &amp;год</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Копировать IP или маÑку подÑети</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Разбанить</translation>
</message>
@@ -2935,17 +3453,17 @@ For more information on using this console, type %6.
%7WARNING: 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.%8</source>
<extracomment>RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</extracomment>
<translation type="unfinished">Добро пожаловать в RPC-конÑоль %1.
-ИÑпользуйте Ñтрелки вверх и вниз, чтобы перемещатьÑÑ Ð¿Ð¾ иÑтории и %2, чтобы очиÑтить Ñкране.
+ИÑпользуйте Ñтрелки вверх и вниз, чтобы перемещатьÑÑ Ð¿Ð¾ иÑтории и %2, чтобы очиÑтить Ñкран.
Чтобы увеличить или уменьшить размер шрифта, нажмите %3 или %4.
Ðаберите %5, чтобы получить ÑпиÑок доÑтупных команд.
Чтобы получить больше информации об Ñтой конÑоли, наберите %6.
-%7Ð’ÐИМÐÐИЕ: мошенники очень чаÑто проÑÑÑ‚ пользователей вводить здеÑÑŒ различные команды и таким образом крадут Ñодержимое кошельков. Ðе иÑпользуйте Ñту конÑоль, еÑли не полноÑтью понимаете поÑледÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ команды.%8</translation>
+%7Ð’ÐИМÐÐИЕ: Мошенники очень чаÑто проÑÑÑ‚ пользователей вводить здеÑÑŒ различные команды и таким образом крадут Ñодержимое кошельков. Ðе иÑпользуйте Ñту конÑоль, еÑли не полноÑтью понимаете поÑледÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ команды.%8</translation>
</message>
<message>
<source>Executing…</source>
<extracomment>A console message indicating an entered command is currently being executed.</extracomment>
- <translation type="unfinished">ВыполнÑетÑÑ...</translation>
+ <translation type="unfinished">ВыполнÑетÑÑ…</translation>
</message>
<message>
<source>(peer: %1)</source>
@@ -2953,7 +3471,7 @@ For more information on using this console, type %6.
</message>
<message>
<source>via %1</source>
- <translation type="unfinished">Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ %1</translation>
+ <translation type="unfinished">через %1</translation>
</message>
<message>
<source>Yes</source>
@@ -2965,11 +3483,11 @@ For more information on using this console, type %6.
</message>
<message>
<source>To</source>
- <translation type="unfinished">Кому</translation>
+ <translation type="unfinished">От наÑ</translation>
</message>
<message>
<source>From</source>
- <translation type="unfinished">От</translation>
+ <translation type="unfinished">К нам</translation>
</message>
<message>
<source>Ban for</source>
@@ -3000,11 +3518,11 @@ For more information on using this console, type %6.
</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 type="unfinished">ÐеобÑзательное Ñообщение Ð´Ð»Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа платежа, которое будет показано при открытии запроÑа. Внимание: Ñто Ñообщение не будет отправлено вмеÑте Ñ Ð¿Ð»Ð°Ñ‚ÐµÐ¶Ð¾Ð¼ через Ñеть биткоина.</translation>
+ <translation type="unfinished">ÐеобÑзательное Ñообщение Ð´Ð»Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа платежа, которое будет показано при открытии запроÑа. Внимание: Ñто Ñообщение не будет отправлено вмеÑте Ñ Ð¿Ð»Ð°Ñ‚ÐµÐ¶Ð¾Ð¼ через Ñеть Bitcoin.</translation>
</message>
<message>
<source>An optional label to associate with the new receiving address.</source>
- <translation type="unfinished">Ð”Ð»Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ адреÑа Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ добавить метку.</translation>
+ <translation type="unfinished">ÐеобÑÐ·Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¼ÐµÑ‚ÐºÐ° Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ адреÑа получениÑ.</translation>
</message>
<message>
<source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
@@ -3012,11 +3530,11 @@ For more information on using this console, type %6.
</message>
<message>
<source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
- <translation type="unfinished">Можно указать Ñумму, платёж на которую вы запрашиваете. ОÑтавьте пуÑтой или введите ноль, чтобы не запрашивать определённую Ñумму.</translation>
+ <translation type="unfinished">Можно указать Ñумму, которую вы хотите запроÑить. ОÑтавьте поле пуÑтым или введите ноль, еÑли не хотите запрашивать конкретную Ñумму.</translation>
</message>
<message>
<source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
- <translation type="unfinished">Можно указать метку, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±ÑƒÐ´ÐµÑ‚ приÑвоена новому адреÑу Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ (чтобы вы могли идентифицировать выÑтавленный Ñчёт). Также она приÑоединÑетÑÑ Ðº запроÑу платежа.</translation>
+ <translation type="unfinished">Можно указать метку, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±ÑƒÐ´ÐµÑ‚ приÑвоена новому адреÑу Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ (чтобы вы могли идентифицировать выÑтавленный Ñчёт). Она приÑоединÑетÑÑ Ðº запроÑу платежа.</translation>
</message>
<message>
<source>An optional message that is attached to the payment request and may be displayed to the sender.</source>
@@ -3028,7 +3546,7 @@ For more information on using this console, type %6.
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation type="unfinished">Очищает вÑе Ð¿Ð¾Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ñ‹.</translation>
+ <translation type="unfinished">ОчиÑтить вÑе Ð¿Ð¾Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ñ‹.</translation>
</message>
<message>
<source>Clear</source>
@@ -3040,7 +3558,7 @@ For more information on using this console, type %6.
</message>
<message>
<source>Show the selected request (does the same as double clicking an entry)</source>
- <translation type="unfinished">Показывает выбранный Ð·Ð°Ð¿Ñ€Ð¾Ñ (двойное нажатие на запиÑи делает то же Ñамое)</translation>
+ <translation type="unfinished">Показать выбранный Ð·Ð°Ð¿Ñ€Ð¾Ñ (двойное нажатие на запиÑи Ñделает то же Ñамое)</translation>
</message>
<message>
<source>Show</source>
@@ -3048,7 +3566,7 @@ For more information on using this console, type %6.
</message>
<message>
<source>Remove the selected entries from the list</source>
- <translation type="unfinished">УдалÑет выбранные запиÑи из ÑпиÑка</translation>
+ <translation type="unfinished">Удалить выбранные запиÑи из ÑпиÑка</translation>
</message>
<message>
<source>Remove</source>
@@ -3059,6 +3577,22 @@ For more information on using this console, type %6.
<translation type="unfinished">Копировать &amp;URI</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Копировать адреÑ</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Копировать &amp;метку</translation>
+ </message>
+ <message>
+ <source>Copy &amp;message</source>
+ <translation type="unfinished">Копировать &amp;Ñообщение</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Копировать Ñ&amp;умму</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">Ðевозможно разблокировать кошелёк.</translation>
</message>
@@ -3071,7 +3605,7 @@ For more information on using this console, type %6.
<name>ReceiveRequestDialog</name>
<message>
<source>Request payment to …</source>
- <translation type="unfinished">ЗапроÑить платёж на ...</translation>
+ <translation type="unfinished">ЗапроÑить платёж на …</translation>
</message>
<message>
<source>Address:</source>
@@ -3102,8 +3636,16 @@ For more information on using this console, type %6.
<translation type="unfinished">Копировать &amp;адреÑ</translation>
</message>
<message>
+ <source>&amp;Verify</source>
+ <translation type="unfinished">&amp;Проверить</translation>
+ </message>
+ <message>
+ <source>Verify this address on e.g. a hardware wallet screen</source>
+ <translation type="unfinished">Проверьте Ð°Ð´Ñ€ÐµÑ Ð½Ð°, к примеру, Ñкране аппаратного кошелька</translation>
+ </message>
+ <message>
<source>&amp;Save Image…</source>
- <translation type="unfinished">&amp;Сохранить изображение...</translation>
+ <translation type="unfinished">&amp;Сохранить изображение…</translation>
</message>
<message>
<source>Payment information</source>
@@ -3189,7 +3731,7 @@ For more information on using this console, type %6.
</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 type="unfinished">ЕÑли Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ñдачи пуÑтой или неверный, Ñдача будет отправлена на вновь Ñгенерированный адреÑ.</translation>
+ <translation type="unfinished">ЕÑли Ñто выбрано, но Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ñдачи пуÑтой или неверный, Ñдача будет отправлена на новый Ñгенерированный адреÑ.</translation>
</message>
<message>
<source>Custom change address</source>
@@ -3233,11 +3775,11 @@ For more information on using this console, type %6.
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation type="unfinished">Очищает вÑе Ð¿Ð¾Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ñ‹.</translation>
+ <translation type="unfinished">ОчиÑтить вÑе Ð¿Ð¾Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ñ‹.</translation>
</message>
<message>
<source>Inputs…</source>
- <translation type="unfinished">Входы...</translation>
+ <translation type="unfinished">Входы…</translation>
</message>
<message>
<source>Dust:</source>
@@ -3245,7 +3787,7 @@ For more information on using this console, type %6.
</message>
<message>
<source>Choose…</source>
- <translation type="unfinished">Выбрать...</translation>
+ <translation type="unfinished">Выбрать…</translation>
</message>
<message>
<source>Hide transaction fee settings</source>
@@ -3257,11 +3799,11 @@ For more information on using this console, type %6.
Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
<translation type="unfinished">Укажите пользовательÑкую комиÑÑию за КБ (1000 байт) виртуального размера транзакции.
-Примечание: так как комиÑÑÐ¸Ñ Ñ€Ð°ÑÑчитываетÑÑ Ð¿Ñ€Ð¾Ð¿Ð¾Ñ€Ñ†Ð¸Ð¾Ð½Ð°Ð»ÑŒÐ½Ð¾ размеру в байтах, комиÑÑÐ¸Ñ Â«100 Ñатоши за ВКБ» Ð´Ð»Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¸ размером 500 виртуальных байт (половина 1 ВКБ) приведет к Ñбору в размере вÑего 50 Ñатоши.</translation>
+Примечание: комиÑÑÐ¸Ñ Ñ€Ð°ÑÑчитываетÑÑ Ð¿Ñ€Ð¾Ð¿Ð¾Ñ€Ñ†Ð¸Ð¾Ð½Ð°Ð»ÑŒÐ½Ð¾ размеру в байтах. Так при комиÑÑии "100 Ñатоши за kvB (виртуальный КБ)" Ð´Ð»Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¸ размером 500 виртуальных байт (половина 1 kvB) комиÑÑÐ¸Ñ Ð±ÑƒÐ´ÐµÑ‚ вÑего 50 Ñатоши.</translation>
</message>
<message>
<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>
+ <translation type="unfinished">Когда объём транзакций меньше, чем проÑтранÑтво в блоках, майнеры и ретранÑлирующие узлы могут уÑтанавливать минимальную комиÑÑию. Платить только Ñту минимальную комиÑÑию вполне допуÑтимо, но примите во внимание, что ваша Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ никогда не подтвердитьÑÑ, еÑли транзакций окажетÑÑ Ð±Ð¾Ð»ÑŒÑˆÐµ, чем может обработать Ñеть.</translation>
</message>
<message>
<source>A too low fee might result in a never confirming transaction (read the tooltip)</source>
@@ -3269,11 +3811,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>(Smart fee not initialized yet. This usually takes a few blocks…)</source>
- <translation type="unfinished">(Ð£Ð¼Ð½Ð°Ñ ÐºÐ¾Ð¼Ð¸ÑÑÐ¸Ñ Ð¿Ð¾ÐºÐ° не инициализирована. Обычно Ð´Ð»Ñ Ñтого требуетÑÑ Ð½ÐµÑколько блоков...)</translation>
+ <translation type="unfinished">(Ð£Ð¼Ð½Ð°Ñ ÐºÐ¾Ð¼Ð¸ÑÑÐ¸Ñ Ð¿Ð¾ÐºÐ° не инициализирована. Обычно Ð´Ð»Ñ Ñтого требуетÑÑ Ð½ÐµÑколько блоков…)</translation>
</message>
<message>
<source>Confirmation time target:</source>
- <translation type="unfinished">Целевое Ð²Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ</translation>
+ <translation type="unfinished">Целевое Ð²Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ:</translation>
</message>
<message>
<source>Enable Replace-By-Fee</source>
@@ -3281,7 +3823,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</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 type="unfinished">С помощью Replace-By-Fee (BIP-125) вы можете увеличить комиÑÑию поÑле отправки транзакции. ЕÑли Ñта Ð¾Ð¿Ñ†Ð¸Ñ Ð²Ñ‹ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°, Ñ€ÐµÐºÐ¾Ð¼ÐµÐ½Ð´ÑƒÐµÐ¼Ð°Ñ ÐºÐ¾Ð¼Ð¸ÑÑÐ¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ увеличитьÑÑ, чтобы компенÑировать риÑк задержки транзакции.</translation>
+ <translation type="unfinished">С помощью Replace-By-Fee (BIP-125) вы можете увеличить комиÑÑию поÑле отправки транзакции. ЕÑли вы выключите Ñту опцию, рекомендуетÑÑ ÑƒÐ²ÐµÐ»Ð¸Ñ‡Ð¸Ñ‚ÑŒ комиÑÑию перед отправкой, чтобы Ñнизить риÑк задержки транзакции.</translation>
</message>
<message>
<source>Clear &amp;All</source>
@@ -3293,7 +3835,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Confirm the send action</source>
- <translation type="unfinished">Подтвердите отправку</translation>
+ <translation type="unfinished">Подтвердить отправку</translation>
</message>
<message>
<source>S&amp;end</source>
@@ -3313,7 +3855,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Copy after fee</source>
- <translation type="unfinished">Копировать поÑле комиÑÑии</translation>
+ <translation type="unfinished">Копировать Ñумму поÑле комиÑÑии</translation>
</message>
<message>
<source>Copy bytes</source>
@@ -3332,6 +3874,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">%1 (%2 блоков)</translation>
</message>
<message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">Подтвердите на уÑтройÑтве</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">Сначала подключите ваш аппаратный кошелёк.</translation>
+ </message>
+ <message>
+ <source>Set external signer script path in Options -&gt; Wallet</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Укажите внешний Ñкрипт подпиÑи в ÐаÑтройки -&gt; Кошелек</translation>
+ </message>
+ <message>
<source>Cr&amp;eate Unsigned</source>
<translation type="unfinished">Создать &amp;без подпиÑи</translation>
</message>
@@ -3341,23 +3897,33 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source> from wallet '%1'</source>
- <translation type="unfinished">Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ° '%1'</translation>
+ <translation type="unfinished">Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ° "%1"</translation>
</message>
<message>
<source>%1 to '%2'</source>
- <translation type="unfinished">%1 на '%2'</translation>
+ <translation type="unfinished">%1 на "%2"</translation>
</message>
<message>
<source>%1 to %2</source>
- <translation type="unfinished">С %1 на %2</translation>
+ <translation type="unfinished">%1 на %2</translation>
</message>
<message>
<source>To review recipient list click "Show Details…"</source>
- <translation type="unfinished">Чтобы проÑмотреть ÑпиÑок получателей, нажмите «Показать подробноÑти...»</translation>
+ <translation type="unfinished">Чтобы проÑмотреть ÑпиÑок получателей, нажмите "Показать подробноÑти…"</translation>
</message>
<message>
<source>Sign failed</source>
- <translation type="unfinished">ПодпиÑание не удалоÑÑŒ.</translation>
+ <translation type="unfinished">Ðе удалоÑÑŒ подпиÑать</translation>
+ </message>
+ <message>
+ <source>External signer not found</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Внешний Ñкрипт подпиÑи не найден</translation>
+ </message>
+ <message>
+ <source>External signer failure</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Внешний Ñкрипта подпиÑи вернул ошибку</translation>
</message>
<message>
<source>Save Transaction Data</source>
@@ -3373,22 +3939,36 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">PSBT Ñохранена</translation>
</message>
<message>
+ <source>External balance:</source>
+ <translation type="unfinished">Внешний баланÑ:</translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">или</translation>
</message>
<message>
<source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
- <translation type="unfinished">Ð’Ñ‹ можете увеличить комиÑÑию позже (указан Replace-By-Fee, BIP-125).</translation>
+ <translation type="unfinished">Ð’Ñ‹ можете увеличить комиÑÑию позже (иÑпользуетÑÑ Replace-By-Fee, BIP-125).</translation>
</message>
<message>
<source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment>
- <translation type="unfinished">ПожалуйÑта, ещё раз проÑмотрите черновик вашей транзакции. Будет Ñоздана чаÑтично подпиÑÐ°Ð½Ð½Ð°Ñ Ð±Ð¸Ñ‚ÐºÐ¾Ð¸Ð½-Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ (PSBT), которую можно Ñохранить или Ñкопировать, поÑле чего подпиÑать, например, офлайновым кошельком %1 или PSBT-ÑовмеÑтимым аппаратным кошельком.</translation>
+ <translation type="unfinished">ПожалуйÑта, проверьте черновик вашей транзакции. Будет Ñоздана чаÑтично подпиÑÐ°Ð½Ð½Ð°Ñ Ð±Ð¸Ñ‚ÐºÐ¾Ð¸Ð½-Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ (PSBT), которую можно Ñохранить или Ñкопировать, поÑле чего подпиÑать, например, офлайновым кошельком %1 или PSBT-ÑовмеÑтимым аппаратным кошельком.</translation>
+ </message>
+ <message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Ð’Ñ‹ хотите Ñоздать Ñту транзакцию?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">ПожалуйÑта, проверьте вашу транзакцию. Ð’Ñ‹ можете Ñоздать и отправить Ñту транзакцию, либо Ñоздать чаÑтично подпиÑанную биткоин-транзакцию (PSBT), которую можно Ñохранить или Ñкопировать, поÑле чего подпиÑать, например, офлайновым кошельком %1 или PSBT-ÑовмеÑтимым аппаратным кошельком.</translation>
</message>
<message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
- <translation type="unfinished">ПожалуйÑта, ещё раз проÑмотрите вашу транзакцию.</translation>
+ <translation type="unfinished">ПожалуйÑта, проверьте вашу транзакцию.</translation>
</message>
<message>
<source>Transaction fee</source>
@@ -3396,7 +3976,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Not signalling Replace-By-Fee, BIP-125.</source>
- <translation type="unfinished">Ðе указан Replace-By-Fee, BIP-125.</translation>
+ <translation type="unfinished">Ðе иÑпользуетÑÑ Replace-By-Fee, BIP-125.</translation>
</message>
<message>
<source>Total Amount</source>
@@ -3404,11 +3984,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Confirm send coins</source>
- <translation type="unfinished">Подтвердите отправку монет</translation>
+ <translation type="unfinished">Подтвердить отправку монет</translation>
</message>
<message>
<source>Watch-only balance:</source>
- <translation type="unfinished">Ðаблюдаемый баланÑ:</translation>
+ <translation type="unfinished">Ð‘Ð°Ð»Ð°Ð½Ñ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра:</translation>
</message>
<message>
<source>The recipient address is not valid. Please recheck.</source>
@@ -3436,27 +4016,23 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
- <translation type="unfinished">КомиÑÑÐ¸Ñ Ð±Ð¾Ð»ÐµÐµ чем в %1 ÑчитаетÑÑ Ð°Ð±Ñурдно выÑокой.</translation>
- </message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">ИÑтекло Ð²Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа платежа</translation>
+ <translation type="unfinished">КомиÑÑÐ¸Ñ Ð±Ð¾Ð»ÐµÐµ %1 ÑчитаетÑÑ Ð°Ð±Ñурдно выÑокой.</translation>
</message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Подтверждение ожидаетÑÑ Ñ‡ÐµÑ€ÐµÐ· %n блок.</numerusform>
+ <numerusform>Подтверждение ожидаетÑÑ Ñ‡ÐµÑ€ÐµÐ· %n блока.</numerusform>
+ <numerusform>Подтверждение ожидаетÑÑ Ñ‡ÐµÑ€ÐµÐ· %n блоков.</numerusform>
</translation>
</message>
<message>
<source>Warning: Invalid Bitcoin address</source>
- <translation type="unfinished">Предупреждение: неверный биткоин-адреÑ</translation>
+ <translation type="unfinished">Внимание: неверный биткоин-адреÑ</translation>
</message>
<message>
<source>Warning: Unknown change address</source>
- <translation type="unfinished">Предупреждение: неизвеÑтный Ð°Ð´Ñ€ÐµÑ Ñдачи</translation>
+ <translation type="unfinished">Внимание: неизвеÑтный Ð°Ð´Ñ€ÐµÑ Ñдачи</translation>
</message>
<message>
<source>Confirm custom change address</source>
@@ -3464,7 +4040,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</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 type="unfinished">Выбранный вами Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ñдачи не принадлежит Ñтому кошельку. ЧаÑÑ‚ÑŒ или вÑе ÑредÑтва в вашем кошельке могут быть отправлены на Ñтот адреÑ. Ð’Ñ‹ уверены?</translation>
+ <translation type="unfinished">Выбранный вами Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ñдачи не принадлежит Ñтому кошельку. ЧаÑÑ‚ÑŒ ÑредÑтв, а то и вÑÑ‘ Ñодержимое вашего кошелька будет отправлено на Ñтот адреÑ. Ð’Ñ‹ уверены в Ñвоих дейÑтвиÑÑ…?</translation>
</message>
<message>
<source>(no label)</source>
@@ -3507,7 +4083,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</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 type="unfinished">КомиÑÑÐ¸Ñ Ð±ÑƒÐ´ÐµÑ‚ вычтена из отправлÑемой Ñуммы. Получателю придёт меньше биткоинов, чем вы ввели в поле «Сумма». ЕÑли выбрано неÑколько получателей, комиÑÑÐ¸Ñ Ñ€Ð°ÑпределÑетÑÑ Ð¿Ð¾Ñ€Ð¾Ð²Ð½Ñƒ.</translation>
+ <translation type="unfinished">КомиÑÑÐ¸Ñ Ð±ÑƒÐ´ÐµÑ‚ вычтена из отправлÑемой Ñуммы. Получателю придёт меньше биткоинов, чем вы ввели в поле "Сумма". ЕÑли выбрано неÑколько получателей, комиÑÑÐ¸Ñ Ñ€Ð°ÑпределитÑÑ Ð¿Ð¾Ñ€Ð¾Ð²Ð½Ñƒ.</translation>
</message>
<message>
<source>S&amp;ubtract fee from amount</source>
@@ -3522,28 +4098,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">Сообщение:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Это непроверенный Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° оплату.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Это проверенный Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° оплату.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Введите метку Ð´Ð»Ñ Ñтого адреÑа, чтобы добавить его в ÑпиÑок иÑпользованных адреÑов</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 type="unfinished">Сообщение, которое было прикреплено к URI и которое будет Ñохранено вмеÑте Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸ÐµÐ¹ Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ ÑведениÑ. Обратите внимание: Ñообщение не будет отправлено через Ñеть биткоина.</translation>
- </message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Отправить на:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Примечание:</translation>
+ <translation type="unfinished">Сообщение, которое было прикреплено к URI. Оно будет Ñохранено вмеÑте Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸ÐµÐ¹ Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ удобÑтва. Обратите внимание: Ñто Ñообщение не будет отправлено в Ñеть Bitcoin.</translation>
</message>
</context>
<context>
@@ -3617,7 +4177,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</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 type="unfinished">Введите ниже Ð°Ð´Ñ€ÐµÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð°Ñ‚ÐµÐ»Ñ, Ñообщение (убедитеÑÑŒ, что переводы Ñтрок, пробелы, знаки табулÑции и Ñ‚. п. Ñкопированы в точноÑти) и подпиÑÑŒ, чтобы проверить Ñообщение. УбедитеÑÑŒ, что вы не придаёте Ñообщению большего ÑмыÑла, чем оно на Ñамом деле неÑÑ‘Ñ‚, чтобы не Ñтать жертвой атаки "человек поÑередине". Обратите внимание, что подпиÑÑŒ доказывает лишь то, что подпиÑавший может получать биткоины на Ñтот адреÑ, но никак не то, что он отправил какую-либо транзакцию!</translation>
+ <translation type="unfinished">Введите ниже Ð°Ð´Ñ€ÐµÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð°Ñ‚ÐµÐ»Ñ, Ñообщение (убедитеÑÑŒ, что переводы Ñтрок, пробелы, знаки табулÑции и Ñ‚.п. Ñкопированы в точноÑти) и подпиÑÑŒ, чтобы проверить Ñообщение. Ðе придавайте Ñообщению большего ÑмыÑла, чем в нём ÑодержитÑÑ, чтобы не Ñтать жертвой атаки "человек поÑередине". Обратите внимание, что подпиÑÑŒ доказывает лишь то, что подпиÑавший может получать биткоины на Ñтот адреÑ, но никак не то, что он отправил какую-либо транзакцию!</translation>
</message>
<message>
<source>The Bitcoin address the message was signed with</source>
@@ -3665,11 +4225,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>No error</source>
- <translation type="unfinished">Ðет ошибок</translation>
+ <translation type="unfinished">Без ошибок</translation>
</message>
<message>
<source>Private key for the entered address is not available.</source>
- <translation type="unfinished">ÐедоÑтупен Ñекретный ключ Ð´Ð»Ñ Ð²Ð²ÐµÐ´Ñ‘Ð½Ð½Ð¾Ð³Ð¾ адреÑа.</translation>
+ <translation type="unfinished">Приватный ключ Ð´Ð»Ñ Ð²Ð²ÐµÐ´Ñ‘Ð½Ð½Ð¾Ð³Ð¾ адреÑа недоÑтупен.</translation>
</message>
<message>
<source>Message signing failed.</source>
@@ -3689,7 +4249,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>The signature did not match the message digest.</source>
- <translation type="unfinished">ПодпиÑÑŒ не ÑоответÑтвует отпечатку ÑообщениÑ.</translation>
+ <translation type="unfinished">ПодпиÑÑŒ не ÑоответÑтвует Ñ…Ñшу ÑообщениÑ.</translation>
</message>
<message>
<source>Message verification failed.</source>
@@ -3706,7 +4266,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>(press q to shutdown and continue later)</source>
<translation type="unfinished">(нажмите q, чтобы завершить работу и продолжить позже)</translation>
</message>
- </context>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">нажмите q Ð´Ð»Ñ Ð²Ñ‹ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ</translation>
+ </message>
+</context>
<context>
<name>TrafficGraphWidget</name>
<message>
@@ -3718,30 +4282,32 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">конфликтует Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸ÐµÐ¹ Ñ %1 подтверждениÑми</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0 / не подтверждено, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">в пуле памÑти</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/нет подтверждений, в пуле памÑти</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">не в пуле памÑти</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/нет подтверждений, не в пуле памÑти</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">отброшена</translation>
</message>
<message>
<source>%1/unconfirmed</source>
- <translation type="unfinished">%1 / не подтверждено</translation>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
+ <translation type="unfinished">%1/нет подтверждений</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 подтверждений</translation>
</message>
<message>
@@ -3762,7 +4328,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>From</source>
- <translation type="unfinished">От</translation>
+ <translation type="unfinished">От кого</translation>
</message>
<message>
<source>unknown</source>
@@ -3791,9 +4357,9 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Ñозреет через %n блок</numerusform>
+ <numerusform>Ñозреет через %n блока</numerusform>
+ <numerusform>Ñозреет через %n блоков</numerusform>
</translation>
</message>
<message>
@@ -3818,7 +4384,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Net amount</source>
- <translation type="unfinished">Сумма нетто</translation>
+ <translation type="unfinished">ЧиÑÑ‚Ð°Ñ Ñумма</translation>
</message>
<message>
<source>Message</source>
@@ -3932,7 +4498,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Generated but not accepted</source>
- <translation type="unfinished">Сгенерирована, но не принÑта</translation>
+ <translation type="unfinished">Сгенерирован, но не принÑÑ‚</translation>
</message>
<message>
<source>Received with</source>
@@ -3952,7 +4518,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Mined</source>
- <translation type="unfinished">Добыта</translation>
+ <translation type="unfinished">Добыто</translation>
</message>
<message>
<source>watch-only</source>
@@ -4003,19 +4569,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>This week</source>
- <translation type="unfinished">Эта неделÑ</translation>
+ <translation type="unfinished">Ðа Ñтой неделе</translation>
</message>
<message>
<source>This month</source>
- <translation type="unfinished">Этот меÑÑц</translation>
+ <translation type="unfinished">Ð’ Ñтом меÑÑце</translation>
</message>
<message>
<source>Last month</source>
- <translation type="unfinished">ПоÑледний меÑÑц</translation>
+ <translation type="unfinished">Ð’ прошлом меÑÑце</translation>
</message>
<message>
<source>This year</source>
- <translation type="unfinished">Этот год</translation>
+ <translation type="unfinished">Ð’ Ñтом году</translation>
</message>
<message>
<source>Received with</source>
@@ -4031,7 +4597,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Mined</source>
- <translation type="unfinished">Добыта</translation>
+ <translation type="unfinished">Добыто</translation>
</message>
<message>
<source>Other</source>
@@ -4039,17 +4605,62 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Enter address, transaction id, or label to search</source>
- <translation type="unfinished">Введите адреÑ, идентификатор транзакции или метку Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка</translation>
+ <translation type="unfinished">Введите адреÑ, идентификатор транзакции, или метку Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка</translation>
</message>
<message>
<source>Min amount</source>
- <translation type="unfinished">Мин. Ñумма</translation>
+ <translation type="unfinished">ÐœÐ¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ñумма</translation>
</message>
<message>
<source>Range…</source>
<translation type="unfinished">Диапазон...</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Копировать адреÑ</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Копировать &amp;метку</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Копировать Ñ&amp;умму</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">Копировать ID &amp;транзакции</translation>
+ </message>
+ <message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">Копировать &amp;иÑходный код транзакции</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">Копировать &amp;вÑе подробноÑти транзакции</translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">&amp;Показать подробноÑти транзакции</translation>
+ </message>
+ <message>
+ <source>Increase transaction &amp;fee</source>
+ <translation type="unfinished">Увеличить комиÑÑию</translation>
+ </message>
+ <message>
+ <source>A&amp;bandon transaction</source>
+ <translation type="unfinished">&amp;Отказ от транзакции</translation>
+ </message>
+ <message>
+ <source>&amp;Edit address label</source>
+ <translation type="unfinished">&amp;Изменить метку адреÑа</translation>
+ </message>
+ <message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Показать в %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">ЭкÑпортировать иÑторию транзакций</translation>
</message>
@@ -4084,7 +4695,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>ID</source>
- <translation type="unfinished">Идентификатр</translation>
+ <translation type="unfinished">Идентификатор</translation>
</message>
<message>
<source>Exporting Failed</source>
@@ -4108,7 +4719,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>to</source>
- <translation type="unfinished">длÑ</translation>
+ <translation type="unfinished">до</translation>
</message>
</context>
<context>
@@ -4175,7 +4786,7 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Increase:</source>
- <translation type="unfinished">Увеличение:</translation>
+ <translation type="unfinished">Увеличить на:</translation>
</message>
<message>
<source>New fee:</source>
@@ -4183,15 +4794,15 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
- <translation type="unfinished">Внимание: комиÑÑÐ¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ быть увеличена путём ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ð²Ñ‹Ð²Ð¾Ð´Ð¾Ð² Ð´Ð»Ñ Ñдачи или Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð²Ñ…Ð¾Ð´Ð¾Ð² (по необходимоÑти). Может быть добавлен новый вывод Ð´Ð»Ñ Ñдачи, еÑли он не ÑущеÑтвует. Эти Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ привеÑти к ухудшению вашей конфиденциальноÑти.Ñ‘</translation>
+ <translation type="unfinished">Внимание: комиÑÑÐ¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ быть увеличена путём ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð¾Ð² Ð´Ð»Ñ Ñдачи или Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð²Ñ…Ð¾Ð´Ð¾Ð² (по необходимоÑти). Может быть добавлен новый вывод Ð´Ð»Ñ Ñдачи, еÑли он не ÑущеÑтвует. Эти Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ привеÑти к ухудшению вашей конфиденциальноÑти.</translation>
</message>
<message>
<source>Confirm fee bump</source>
- <translation type="unfinished">Подтвердите увеличение комиÑÑии</translation>
+ <translation type="unfinished">Подтвердить увеличение комиÑÑии</translation>
</message>
<message>
<source>Can't draft transaction.</source>
- <translation type="unfinished">Ðевозможно подготовить черновик транзакции.</translation>
+ <translation type="unfinished">Ðе удалоÑÑŒ подготовить черновик транзакции.</translation>
</message>
<message>
<source>PSBT copied</source>
@@ -4206,6 +4817,10 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished">Ðе удалоÑÑŒ отправить транзакцию</translation>
</message>
<message>
+ <source>Can't display address</source>
+ <translation type="unfinished">Ðе удалоÑÑŒ отобразить адреÑ</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">кошелёк по умолчанию</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sc.ts b/src/qt/locale/bitcoin_sc.ts
index 1527753c8e..69bcdfb2d7 100644
--- a/src/qt/locale/bitcoin_sc.ts
+++ b/src/qt/locale/bitcoin_sc.ts
@@ -116,6 +116,24 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_si.ts b/src/qt/locale/bitcoin_si.ts
index c9367ad9d2..6ab5f270b8 100644
--- a/src/qt/locale/bitcoin_si.ts
+++ b/src/qt/locale/bitcoin_si.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">ලිපිනය හ෠ලේබලය සංස්කරණය කිරීමට දකුණු මූසික බොත්තම ක්ලික් කරන්න</translation>
+ <translation type="unfinished">ලිපිනය හ෠නම්පත සංà·à·à¶°à¶±à¶ºà¶§ දකුණු බොත්තම ඔබන්න</translation>
</message>
<message>
<source>Create a new address</source>
@@ -15,11 +15,11 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation type="unfinished">දà·à¶±à¶§ තà·à¶»à·à¶œà·™à¶± ඇති ලිපිනය පද්ධති පසුරු පුවරුවට (clipboard) පිටපත් කරන්න</translation>
+ <translation type="unfinished">තà·à¶»à·à¶œà·™à¶± ඇති ලිපිනය පද්ධතියේ පසුරු පුවරුවට පිටපත් කරන්න</translation>
</message>
<message>
<source>&amp;Copy</source>
- <translation type="unfinished">&amp;පිටපත් කරන්න</translation>
+ <translation type="unfinished">&amp;පිටපත්</translation>
</message>
<message>
<source>C&amp;lose</source>
@@ -27,15 +27,23 @@
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation type="unfinished">දà·à¶±à¶§ තà·à¶»à·à¶œà¶­à·Š ලිපිනය ලà·à¶ºà·’ස්තුවෙන් ඉවත් කරන්න</translation>
+ <translation type="unfinished">තේරූ ලිපිනය ලේඛනයෙන් මකන්න</translation>
</message>
<message>
<source>Enter address or label to search</source>
- <translation type="unfinished">සෙවීමට ලිපිනය හ෠ලේබලය ඇතුළත් කරන්න</translation>
+ <translation type="unfinished">සෙවීමට ලිපිනය හ෠නම්පත යොදන්න</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">වත්මන් පටියෙයි දත්ත ගොනුවකට නිර්යà·à¶­ කරන්න</translation>
</message>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">&amp;නිර්යà·à¶­ කරන්න</translation>
+ <translation type="unfinished">&amp;නිර්යà·à¶­à¶º</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation type="unfinished">&amp;මකන්න</translation>
</message>
<message>
<source>Choose the address to send coins to</source>
@@ -47,7 +55,7 @@
</message>
<message>
<source>C&amp;hoose</source>
- <translation type="unfinished">තà·à¶»à¶±à·Šà¶±</translation>
+ <translation type="unfinished">තà·&amp;රන්න</translation>
</message>
<message>
<source>Sending addresses</source>
@@ -59,11 +67,15 @@
</message>
<message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
- <translation type="unfinished">මේව෠ඔබගේ ගෙවීම් යà·à·€à·“ම සඳහ෠වන බිට්කොයින් ලිපින වේ. කà·à·ƒà·’ යà·à·€à·“මට පෙර සෑම විටම මුදල සහ ලà·à¶¶à·“මේ ලිපිනය පරීක්ෂ෠කරන්න.</translation>
+ <translation type="unfinished">මේ ඔබගේ ගෙවීම් යà·à·€à·“ම සඳහ෠වන බිට්කොයින් ලිපින වේ. කà·à·ƒà·’ යà·à·€à·“මට පෙර සෑම විටම මුදල සහ ලà·à¶¶à·“මේ ලිපිනය පරීක්â€à·‚෠කරන්න.</translation>
</message>
<message>
<source>&amp;Copy Address</source>
- <translation type="unfinished">&amp;ලිපිනය පිටපත්</translation>
+ <translation type="unfinished">&amp;ලිපිනයෙහි පිටපතක්</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">නම්පතෙහි &amp;පිටපතක්</translation>
</message>
<message>
<source>&amp;Edit</source>
@@ -72,7 +84,7 @@
<message>
<source>Comma separated file</source>
<extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
- <translation type="unfinished">අල්පවිරà·à¶¸ වලින් වෙන්වූ ගොනුව</translation>
+ <translation type="unfinished">අල්පවිරà·à¶¸ යෙදූ ගොනුව</translation>
</message>
<message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
@@ -81,14 +93,14 @@
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished">නිර්යà·à¶­ වීමට අසමත් විය</translation>
+ <translation type="unfinished">නිර්යà·à¶­à¶ºà¶§ අසමත් විය</translation>
</message>
</context>
<context>
<name>AddressTableModel</name>
<message>
<source>Label</source>
- <translation type="unfinished">ලේබලය</translation>
+ <translation type="unfinished">නම්පත</translation>
</message>
<message>
<source>Address</source>
@@ -96,7 +108,7 @@
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(ලේබලයක් නà·à¶­)</translation>
+ <translation type="unfinished">(නම්පතක් නà·à¶­)</translation>
</message>
</context>
<context>
@@ -123,7 +135,7 @@
</message>
<message>
<source>Encrypt wallet</source>
- <translation type="unfinished">පසුම්බිය සංකේතනය කරන්න</translation>
+ <translation type="unfinished">පසුම්බිය සංකේතනය</translation>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
@@ -151,7 +163,7 @@
</message>
<message>
<source>Wallet encrypted</source>
- <translation type="unfinished">පසුම්බිය සංකේතනය කර ඇත</translation>
+ <translation type="unfinished">පසුම්බිය සංකේතිතයි</translation>
</message>
<message>
<source>Enter the new passphrase for 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>
@@ -171,11 +183,11 @@
</message>
<message>
<source>Your wallet is about to be encrypted. </source>
- <translation type="unfinished">ඔබේ මුදල් පසුම්බිය සංකේතනය කිරීමට ආසන්නයි.</translation>
+ <translation type="unfinished">පසුම්බිය සංකේතනය කිරීමට ආසන්නයි.</translation>
</message>
<message>
<source>Your wallet is now encrypted. </source>
- <translation type="unfinished">ඔබගේ මුදල් පසුම්බිය දà·à¶±à·Š සංකේතනය කර ඇත.</translation>
+ <translation type="unfinished">ඔබගේ මුදල් පසුම්බිය දà·à¶±à·Š සංකේතිතයි.</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>
@@ -183,7 +195,7 @@
</message>
<message>
<source>Wallet encryption failed</source>
- <translation type="unfinished">පසුම්බි සංකේතනය අසà·à¶»à·Šà¶®à¶š විය</translation>
+ <translation type="unfinished">පසුම්බිය සංකේතනයට අසමත්!</translation>
</message>
<message>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
@@ -216,14 +228,27 @@
<source>Internal error</source>
<translation type="unfinished">අභ්â€à¶ºà¶±à·Šà¶­à¶» දà·à·‚යකි</translation>
</message>
- </context>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">අභ්â€à¶ºà¶±à·Šà¶­à¶» දà·à·‚යක් සිදු විය. %1 ආරක්ෂිතව ඉදිරියට යà·à¶¸à¶§ උත්සà·à·„ කරනු ඇත. මෙය පහත විස්තර කර ඇති පරිදි à·€à·à¶»à·Šà¶­à· කළ à·„à·à¶šà·’ අනපේක්ෂිත දà·à·‚යකි.</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">ඔබට à·ƒà·à¶šà·ƒà·“ම් පෙරනිමි අගයන් වෙත යළි පිහිටුවීමට අවà·à·Šâ€à¶ºà¶¯, නà·à¶­à·„ොත් වෙනස්කම් සිදු නොකර නවත෠දà·à¶¸à·“මටද?</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">දෝෂය: %1</translation>
</message>
<message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 තවමත් ආරක්ෂිතව පිටව ගොස් නà·à¶­ ...</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">නොදනී</translation>
</message>
@@ -234,49 +259,53 @@
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n second(s)</numerusform>
+ <numerusform>%n second(s)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minute(s)</numerusform>
+ <numerusform>%n minute(s)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n hour(s)</numerusform>
+ <numerusform>%n hour(s)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n day(s)</numerusform>
+ <numerusform>%n day(s)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n week(s)</numerusform>
+ <numerusform>%n week(s)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n year(s)</numerusform>
+ <numerusform>%n year(s)</numerusform>
</translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">à·ƒà·à¶šà·ƒà·“ම් ගොනුව කියවිය නොහà·à¶š</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">%s සංවර්ධකයින්</translation>
</message>
@@ -289,6 +318,10 @@
<translation type="unfinished">%s පූරණය වීමේ දà·à·‚යකි</translation>
</message>
<message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">දà·à·‚ය: ඔබගේ පසුම්බිය ප්â€à¶»à¶­à·’ස්ථà·à¶´à¶±à¶º කල නොහà·à¶šà·’ විය.</translation>
+ </message>
+ <message>
<source>Importing…</source>
<translation type="unfinished">ආයà·à¶­ වෙමින්…</translation>
</message>
@@ -316,6 +349,14 @@
<translation type="unfinished">&amp;දළ විà·à·Šà¶½à·™à·Šà·‚ණය</translation>
</message>
<message>
+ <source>Show general overview of wallet</source>
+ <translation type="unfinished">පසුම්බිය පිළිබඳ à·ƒà·à¶¸à·à¶±à·Šâ€à¶º දළ විà·à·Šà¶½à·šà·‚ණය පෙන්වන්න</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation type="unfinished">&amp;ගනුදෙනු</translation>
+ </message>
+ <message>
<source>Browse transaction history</source>
<translation type="unfinished">ගනුදෙනු ඉතිහà·à·ƒà¶º පිරික්සන්න</translation>
</message>
@@ -325,7 +366,7 @@
</message>
<message>
<source>Quit application</source>
- <translation type="unfinished">යෙදුමෙන් පිටවන්න</translation>
+ <translation type="unfinished">යෙදුම වසන්න</translation>
</message>
<message>
<source>&amp;About %1</source>
@@ -333,7 +374,7 @@
</message>
<message>
<source>Show information about %1</source>
- <translation type="unfinished">%1 පිළිබඳව තෙà·à¶»à¶­à·”රු පෙන්වන්න</translation>
+ <translation type="unfinished">%1 ගà·à¶± තෙà·à¶»à¶­à·”රු පෙන්වන්න</translation>
</message>
<message>
<source>About &amp;Qt</source>
@@ -341,13 +382,17 @@
</message>
<message>
<source>Show information about Qt</source>
- <translation type="unfinished">කියුටී පිළිබඳව තෙà·à¶»à¶­à·”රු පෙන්වන්න</translation>
+ <translation type="unfinished">කියුටී ගà·à¶± තෙà·à¶»à¶­à·”රු පෙන්වන්න</translation>
</message>
<message>
<source>Create a new wallet</source>
<translation type="unfinished">නව පසුම්බියක් à·ƒà·à¶¯à¶±à·Šà¶±</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;හකුළන්න</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">පසුම්බිය:</translation>
</message>
@@ -358,7 +403,7 @@
</message>
<message>
<source>Send coins to a Bitcoin address</source>
- <translation type="unfinished">බිට්කෙà·à¶ºà·’න් ලිපිනයට කà·à·ƒà·’ යවන්න</translation>
+ <translation type="unfinished">බිට්කෙà·à¶ºà·’න් ලිපිනයකට කà·à·ƒà·’ යවන්න</translation>
</message>
<message>
<source>Backup wallet to another location</source>
@@ -378,7 +423,7 @@
</message>
<message>
<source>&amp;Backup Wallet…</source>
- <translation type="unfinished">&amp;පසුම්බිය උපස්ථකරන්න…</translation>
+ <translation type="unfinished">&amp;පසුම්බිය උපස්ථය…</translation>
</message>
<message>
<source>Close Wallet…</source>
@@ -406,7 +451,7 @@
</message>
<message>
<source>Syncing Headers (%1%)…</source>
- <translation type="unfinished">(%1%) à·à·“ර්ෂ සමමුහූර්ත වෙමින්…</translation>
+ <translation type="unfinished">(%1%) à·à·Šâ€à¶»à·“ර්ෂ සමමුහූර්ත වෙමින්…</translation>
</message>
<message>
<source>Synchronizing with network…</source>
@@ -415,8 +460,8 @@
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Processed %n block(s) of transaction history.</numerusform>
+ <numerusform>Processed %n block(s) of transaction history.</numerusform>
</translation>
</message>
<message>
@@ -432,6 +477,10 @@
<translation type="unfinished">තොරතුර</translation>
</message>
<message>
+ <source>Up to date</source>
+ <translation type="unfinished">යà·à·€à¶­à·Šà¶šà·à¶½à·“නයි</translation>
+ </message>
+ <message>
<source>&amp;Sending addresses</source>
<translation type="unfinished">&amp;යවන ලිපින</translation>
</message>
@@ -452,6 +501,11 @@
<translation type="unfinished">පසුම්බිය වසන්න</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">පසුම්බිය ප්â€à¶»à¶­à·’ස්ථà·à¶´à¶±à¶º කිරීම</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">සියළු පසුම්බි වසන්න</translation>
</message>
@@ -460,12 +514,27 @@
<translation type="unfinished">පෙරනිමි පසුම්බිය</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">පසුම්බියේ දත්ත</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">පසුම්බිය ප්â€à¶»à¶­à·’ස්ථà·à¶´à¶±à¶º කිරීම</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">පසුම්බියේ නම</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;කවුළුව</translation>
</message>
<message>
<source>Zoom</source>
- <translation type="unfinished">විà·à·à¶½ කරන්න</translation>
+ <translation type="unfinished">විà·à·à¶½à¶±à¶º</translation>
</message>
<message>
<source>Main Window</source>
@@ -475,12 +544,20 @@
<source>%1 client</source>
<translation type="unfinished">%1 අනුග්â€à¶»à·à·„කය</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;සඟවන්න</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">පෙ&amp;න්වන්න</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
</translation>
</message>
<message>
@@ -513,6 +590,12 @@
</translation>
</message>
<message>
+ <source>Amount: %1
+</source>
+ <translation type="unfinished">ගණන: %1
+</translation>
+ </message>
+ <message>
<source>Wallet: %1
</source>
<translation type="unfinished">පසුම්බිය: %1
@@ -525,6 +608,12 @@
</translation>
</message>
<message>
+ <source>Label: %1
+</source>
+ <translation type="unfinished">නම්පත: %1
+</translation>
+ </message>
+ <message>
<source>Address: %1
</source>
<translation type="unfinished">ලිපිනය: %1
@@ -575,7 +664,7 @@
</message>
<message>
<source>&amp;Copy address</source>
- <translation type="unfinished">&amp;ලිපිනය පිටපත්</translation>
+ <translation type="unfinished">&amp;ලිපිනයෙහි පිටපතක්</translation>
</message>
<message>
<source>Copy bytes</source>
@@ -591,7 +680,7 @@
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(ලේබලයක් නà·à¶­)</translation>
+ <translation type="unfinished">(නම්පතක් නà·à¶­)</translation>
</message>
<message>
<source>(change)</source>
@@ -619,6 +708,24 @@
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">පසුම්බිය ප්â€à¶»à¶­à·’ස්ථà·à¶´à¶±à¶º කිරීම</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">පසුම්බිය ප්â€à¶»à¶­à·’ස්ථà·à¶´à¶±à¶º කිරීම අසà·à¶»à·Šà¶®à¶šà¶ºà·’</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">පසුම්බිය ප්â€à¶»à¶­à·’ස්ථà·à¶´à¶±à¶º කිරීමේ පණිවිඩය </translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -697,13 +804,34 @@
<translation type="unfinished">බිට්කෙà·à¶ºà·’න්</translation>
</message>
<message numerus="yes">
- <source>(sufficient to restore backups %n day(s) old)</source>
- <extracomment>Explanatory text on the capability of the current prune target.</extracomment>
+ <source>%n GB of space available</source>
<translation type="unfinished">
<numerusform />
<numerusform />
</translation>
</message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(sufficient to restore backups %n day(s) old)</source>
+ <extracomment>Explanatory text on the capability of the current prune target.</extracomment>
+ <translation type="unfinished">
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
+ </translation>
+ </message>
<message>
<source>Error</source>
<translation type="unfinished">දෝෂයකි</translation>
@@ -855,6 +983,11 @@
<context>
<name>PeerTableModel</name>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">වයස</translation>
+ </message>
+ <message>
<source>Address</source>
<extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
<translation type="unfinished">ලිපිනය</translation>
@@ -870,7 +1003,7 @@
<message>
<source>&amp;Copy address</source>
<extracomment>Context menu action to copy the address of a peer.</extracomment>
- <translation type="unfinished">&amp;ලිපිනය පිටපත්</translation>
+ <translation type="unfinished">&amp;ලිපිනයෙහි පිටපතක්</translation>
</message>
<message>
<source>To</source>
@@ -885,7 +1018,7 @@
<name>ReceiveCoinsDialog</name>
<message>
<source>&amp;Copy address</source>
- <translation type="unfinished">&amp;ලිපිනය පිටපත්</translation>
+ <translation type="unfinished">&amp;ලිපිනයෙහි පිටපතක්</translation>
</message>
</context>
<context>
@@ -907,7 +1040,7 @@
</message>
<message>
<source>Label</source>
- <translation type="unfinished">ලේබලය</translation>
+ <translation type="unfinished">නම්පත</translation>
</message>
<message>
<source>Message</source>
@@ -915,7 +1048,7 @@
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(ලේබලයක් නà·à¶­)</translation>
+ <translation type="unfinished">(නම්පතක් නà·à¶­)</translation>
</message>
</context>
<context>
@@ -971,13 +1104,13 @@
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
</translation>
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(ලේබලයක් නà·à¶­)</translation>
+ <translation type="unfinished">(නම්පතක් නà·à¶­)</translation>
</message>
</context>
<context>
@@ -1023,8 +1156,8 @@
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>matures in %n more block(s)</numerusform>
+ <numerusform>matures in %n more block(s)</numerusform>
</translation>
</message>
<message>
@@ -1060,7 +1193,7 @@
</message>
<message>
<source>Label</source>
- <translation type="unfinished">ලේබලය</translation>
+ <translation type="unfinished">නම්පත</translation>
</message>
<message>
<source>(n/a)</source>
@@ -1068,7 +1201,7 @@
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(ලේබලයක් නà·à¶­)</translation>
+ <translation type="unfinished">(නම්පතක් නà·à¶­)</translation>
</message>
<message>
<source>Type of transaction.</source>
@@ -1103,7 +1236,7 @@
</message>
<message>
<source>&amp;Copy address</source>
- <translation type="unfinished">&amp;ලිපිනය පිටපත්</translation>
+ <translation type="unfinished">&amp;ලිපිනයෙහි පිටපතක්</translation>
</message>
<message>
<source>Copy transaction &amp;ID</source>
@@ -1112,7 +1245,7 @@
<message>
<source>Comma separated file</source>
<extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
- <translation type="unfinished">අල්පවිරà·à¶¸ වලින් වෙන්වූ ගොනුව</translation>
+ <translation type="unfinished">අල්පවිරà·à¶¸ යෙදූ ගොනුව</translation>
</message>
<message>
<source>Date</source>
@@ -1124,7 +1257,7 @@
</message>
<message>
<source>Label</source>
- <translation type="unfinished">ලේබලය</translation>
+ <translation type="unfinished">නම්පත</translation>
</message>
<message>
<source>Address</source>
@@ -1136,7 +1269,7 @@
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished">නිර්යà·à¶­ වීමට අසමත් විය</translation>
+ <translation type="unfinished">නිර්යà·à¶­à¶ºà¶§ අසමත් විය</translation>
</message>
<message>
<source>Exporting Successful</source>
@@ -1173,7 +1306,11 @@
<name>WalletView</name>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">&amp;නිර්යà·à¶­ කරන්න</translation>
+ <translation type="unfinished">&amp;නිර්යà·à¶­à¶º</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">වත්මන් පටියෙයි දත්ත ගොනුවකට නිර්යà·à¶­ කරන්න</translation>
</message>
<message>
<source>Backup Wallet</source>
diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts
index fb03b0beb6..760e43d329 100644
--- a/src/qt/locale/bitcoin_sk.ts
+++ b/src/qt/locale/bitcoin_sk.ts
@@ -264,6 +264,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Chcete vrátiÅ¥ nastavenia na predvolené hodnoty alebo ukonÄiÅ¥ bez vykonania zmien?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Nastala kritická chyba. Skontrolujte, že je možné zapisovať do súboru nastavení alebo skúste spustiť s parametrom -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Chyba: Zadaný adresár pre dáta „%1“ neexistuje.</translation>
</message>
@@ -340,41 +350,41 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n sekunda</numerusform>
+ <numerusform>%n sekundy</numerusform>
+ <numerusform>%n sekúnd</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n minúta</numerusform>
+ <numerusform>%n minúty</numerusform>
+ <numerusform>%n minút</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n hodina</numerusform>
+ <numerusform>%n hodiny</numerusform>
+ <numerusform>%n hodín</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n deň</numerusform>
+ <numerusform>%n dni</numerusform>
+ <numerusform>%n dní</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n týždeň</numerusform>
+ <numerusform>%n týždne</numerusform>
+ <numerusform>%n týždňov</numerusform>
</translation>
</message>
<message>
@@ -384,15 +394,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n rok</numerusform>
+ <numerusform>%n roky</numerusform>
+ <numerusform>%n rokov</numerusform>
</translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Súbor nastavení nemohol byÅ¥ preÄítaný</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Súbor nastavení nemohol byť zapísaný</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">Vývojári %s</translation>
</message>
@@ -425,6 +443,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">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>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">Chyba pri Äítaní %s! TransakÄné údaje môžu chýbaÅ¥ alebo sú chybné. Znovu preÄítam peňaženku.</translation>
+ </message>
+ <message>
<source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
<translation type="unfinished">Chyba: Formát záznamu v súbore dumpu je nesprávny. Obdržaný "%s", oÄakávaný "format".</translation>
</message>
@@ -441,10 +463,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Chyba: Staršie peňaženky podporujú len adresy typu "legacy", "p2sh-segwit", a "bech32"</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Chyba: PoÄúvanie prichádzajúcich spojení zlyhalo (vrátená chyba je %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Odhad poplatku sa nepodaril. Fallbackfee je zakázaný. PoÄkajte niekoľko blokov alebo povoľte -fallbackfee.</translation>
</message>
@@ -457,6 +475,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Neplatná suma pre -maxtxfee=&lt;amount&gt;: '%s' (aby sa transakcia nezasekla, minimálny prenosový poplatok musí byť aspoň %s)</translation>
</message>
<message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">Chybný alebo poÅ¡kodený súbor peers.dat (%s). Ak si myslíte, že ide o chybu, prosím nahláste to na %s. Ako doÄasné rieÅ¡enie môžete súbor odsunúť (%s) z umiestnenia (premenovaÅ¥, presunúť, vymazaÅ¥), aby sa pri ÄalÅ¡om spustení vytvoril nový.</translation>
+ </message>
+ <message>
<source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
<translation type="unfinished">K dispozícii je viac ako jedna adresa onion. Použitie %s pre automaticky vytvorenú službu Tor.</translation>
</message>
@@ -497,6 +519,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Databáza blokov obsahuje blok, ktorý vyzerá byÅ¥ z budúcnosti. Toto môže byÅ¥ spôsobené nesprávnym systémovým Äasom vášho poÄítaÄa. Obnovujte databázu blokov len keÄ ste si istý, že systémový Äas je nastavený správne.</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">Databáza indexov blokov obsahuje 'txindex' staršieho typu. Pre uvoľnenie obsadeného miesta spustite s parametrom -reindex, inak môžete ignorovať túto chybu. Táto správa sa už nabudúce nezobrazí.</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished">Suma je príliš malá pre odoslanie transakcie</translation>
</message>
@@ -569,6 +595,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nedá preložiť -%s adresu: '%s'</translation>
</message>
<message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">Nie je možné zapnúť -forcednsseed keÄ je -dnsseed vypnuté.</translation>
+ </message>
+ <message>
<source>Cannot set -peerblockfilters without -blockfilterindex.</source>
<translation type="unfinished">Nepodarilo sa urÄiÅ¥ -peerblockfilters bez -blockfilterindex.</translation>
</message>
@@ -577,6 +607,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nie je možné zapísať do adresára ' %s'. Skontrolujte povolenia.</translation>
</message>
<message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">Upgrade -txindex spustený predchádzajúcou verziou nemôže byÅ¥ dokonÄený. ReÅ¡tartujte s prechdádzajúcou verziou programu alebo spustite s parametrom -reindex.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">Požiadavka %s na poÄúvanie na porte %u. Tento port je považovaný za "zlý" preto je nepravdepodobné, že sa naň pripojí nejaký Bitcoin Core partner. Pozrite doc/p2p-bad-ports.md pre detaily a celý zoznam.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Nie je možné zadať špecifické spojenia a zároveň nechať addrman hľadať odchádzajúce spojenia.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Chyba pri naÄítaní %s: NaÄíta sa peňaženka s externým podpisovaním, ale podpora pre externé podpisovanie nebola zaÄlenená do programu</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Nepodarilo sa premenovať chybný súbor peers.dat. Prosím presuňte ho alebo vymažte a skúste znovu.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">Nastavenie konfigurácie pre %s platí iba v sieti %s a v sekcii [%s].</translation>
</message>
@@ -653,10 +703,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Chyba pri Äítaní ÄalÅ¡ieho záznamu z databázy peňaženky</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Chyba pri vylepšení databáze reťzcov blokov</translation>
- </message>
- <message>
<source>Error: Couldn't create cursor into database</source>
<translation type="unfinished">Chyba: Nepodarilo sa vytvoriť kurzor do databázy</translation>
</message>
@@ -729,6 +775,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kontrola Äistoty pri inicializácií zlyhala. %s sa vypína.</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Vstup nenájdený alebo už minutý</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">Nedostatok prostriedkov</translation>
</message>
@@ -785,12 +835,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">NaÄítavam peňaženku…</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Chýba suma</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">Chýbajú údaje pre odhad veľkosti transakcie</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">Je potrebné zadať port s -whitebind: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Nie je špecifikovaný proxy server. Použite -proxy=&lt;ip&gt; alebo -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Nie sú dostupné žiadne adresy</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -801,10 +859,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Redukovanie nemôže byť nastavené na zápornú hodnotu.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Režim redukovania je nekompatibilný s -coinstatsindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">Režim redukovania je nekompatibilný s -txindex.</translation>
</message>
@@ -905,6 +959,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Sumy transakcií nesmú byť záporné</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">Výstupný index transakcie zmeny je mimo rozsahu</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">Transakcia má v transakÄnom zásobníku príliÅ¡ dlhý reÅ¥azec</translation>
</message>
@@ -913,6 +971,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transakcia musí mať aspoň jedného príjemcu</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">Transakcia potrebuje adresu na zmenu, ale nemôžeme ju vygenerovať.</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">Transakcia príliš veľká</translation>
</message>
@@ -941,6 +1003,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nepodarilo sa otvoriť %s pre zapisovanie</translation>
</message>
<message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">Nepodarilo sa preÄítaÅ¥ -maxuploadtarget: '%s'</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">Nepodarilo sa spustiť HTTP server. Pre viac detailov zobrazte debug log.</translation>
</message>
@@ -969,10 +1035,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nepodporovaná logovacia kategória %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Vylepšuje sa databáza neminutých výstupov (UTXO)</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Komentár u typu klienta (%s) obsahuje riskantné znaky.</translation>
</message>
@@ -1040,6 +1102,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Vytvoriť novú peňaženku</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimalizovať</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Peňaženka:</translation>
</message>
@@ -1187,9 +1253,9 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Spracovaný %n blok transakÄnej histórie.</numerusform>
+ <numerusform>Spracované %n bloky transakÄnej histórie.</numerusform>
+ <numerusform>Spracovaných %n blokov transakÄnej histórie.</numerusform>
</translation>
</message>
<message>
@@ -1229,6 +1295,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">NaÄítaÅ¥ sÄasti podpísanú Bitcoin transakciu</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">NaÄítaÅ¥ PSBT zo s&amp;chránky…</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">NaÄítaÅ¥ ÄiastoÄne podpísanú Bitcoin transakciu, ktorú ste skopírovali</translation>
</message>
@@ -1289,6 +1359,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nie je dostupná žiadna peňaženka</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Dáta peňaženky</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Názov peňaženky</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Okno</translation>
</message>
@@ -1304,13 +1384,21 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 klient</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Skryť</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">Z&amp;obraziť</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n aktívne pripojenie do siete Bitcoin</numerusform>
+ <numerusform>%n aktívne pripojenia do siete Bitcoin</numerusform>
+ <numerusform>%n aktívnych pripojení do siete Bitcoin</numerusform>
</translation>
</message>
<message>
@@ -1504,6 +1592,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kopírovať &amp;sumu</translation>
</message>
<message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Skopírovať &amp;ID transakcie a výstupný index</translation>
+ </message>
+ <message>
<source>L&amp;ock unspent</source>
<translation type="unfinished">U&amp;zamknúť neminuté</translation>
</message>
@@ -1592,6 +1684,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">Nemôžem zobraziť podpisovateľov</translation>
</message>
+ </context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">NaÄítaÅ¥ peňaženky</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">NaÄítavam peňaženky…</translation>
+ </message>
</context>
<context>
<name>OpenWalletActivity</name>
@@ -1793,13 +1898,29 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(z %1 GB potrebných)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 GB potrebných pre plný reťazec)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(z %n GB potrebného)</numerusform>
+ <numerusform>(z %n GB potrebných)</numerusform>
+ <numerusform>(z %n GB potrebných)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB potrebný pre plný reťazec)</numerusform>
+ <numerusform>(%n GB potrebné pre plný reťazec)</numerusform>
+ <numerusform>(%n GB potrebných pre plný reťazec)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1813,9 +1934,9 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>(dostatoÄné pre obnovenie záloh %n deň starých)</numerusform>
+ <numerusform>(dostatoÄné pre obnovenie záloh %n dni starých)</numerusform>
+ <numerusform>(dostatoÄné pre obnovenie záloh %n dní starých)</numerusform>
</translation>
</message>
<message>
@@ -1847,10 +1968,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">KeÄže toto je prvé spustenie programu, môžete si vybraÅ¥, kam %1 bude ukladaÅ¥ vaÅ¡e údaje.</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 type="unfinished">HneÄ po stlaÄení OK, zaÄne %1 sÅ¥ahovaÅ¥ a spracovávaÅ¥ celý %4 blockchain (%2G B), zaÄínajúc najaktuálnejšími transakciami z roku %3, kedy bol %4 spustený.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Obmedziť veľkosť reťazca blokov na</translation>
</message>
@@ -1959,7 +2076,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Neznámy. Synchronizujú sa hlaviÄky (%1, %2%)…</translation>
</message>
-</context>
+ </context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -2043,14 +2160,44 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Obnovenie tohto nastavenia vyžaduje opätovné stiahnutie celého blockchainu.</translation>
</message>
<message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">Maximálna veľkosÅ¥ vyrovnávacej pamäte databázy. VäÄÅ¡ia pamäť môže urýchliÅ¥ synchronizáciu, ale pri ÄalÅ¡om používaní už nemá efekt. ZmenÅ¡enie vyrovnávacej pamäte zníži použitie pamäte. Nevyužitá pamäť mempool je zdieľaná pre túto vyrovnávaciu pamäť.</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Nastaví poÄet vlákien na overenie skriptov. Záporné hodnoty zodpovedajú poÄtu jadier procesora, ktoré chcete nechaÅ¥ voľné pre systém.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = auto, &lt;0 = toľko jadier nechať voľných)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Toto umožňuje vám alebo nástroju tretej strany komunikovať s uzlom pomocou príkazov z príkazového riadka alebo JSON-RPC.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Povoliť server R&amp;PC</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">&amp;Peňaženka</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">NastaviÅ¥ predvolenie odpoÄítavania poplatku zo sumy.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Predvolene odpoÄítavaÅ¥ &amp;poplatok zo sumy</translation>
+ </message>
+ <message>
<source>Enable coin &amp;control features</source>
<translation type="unfinished">Povoliť možnosti &amp;kontroly mincí</translation>
</message>
@@ -2063,6 +2210,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Minúť nepotvrdený výdavok</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Povoliť ovládanie &amp;PSBT</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Zobrazenie ovládania PSBT.</translation>
+ </message>
+ <message>
<source>External Signer (e.g. hardware wallet)</source>
<translation type="unfinished">Externý podpisovateľ (napr. hardvérová peňaženka)</translation>
</message>
@@ -2159,6 +2316,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Zvoľte ako deliť bitcoin pri zobrazovaní pri platbách a užívateľskom rozhraní.</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 type="unfinished">URL tretích strán (napr. prehliadaÄ blokov), ktoré sa zobrazujú v záložke transakcií ako položky kontextového menu. %s v URL je nahradené hash-om transakcie. Viaceré URL sú oddelené zvislou Äiarou |.</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">URL &amp;transakcií tretích strán</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">Či zobrazovať možnosti kontroly mincí alebo nie.</translation>
</message>
@@ -2183,10 +2348,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">najbližší zodpovedajúci "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Voľby nastavené v tomto dialógovom okne sú prepísané príkazovým riadkom alebo konfiguraÄným súborom:</translation>
- </message>
- <message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Zrušiť</translation>
</message>
@@ -2205,14 +2366,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Potvrdiť obnovenie možností</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Reštart klienta potrebný pre aktivovanie zmien.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Klient bude vypnutý, chcete pokraÄovaÅ¥?</translation>
</message>
<message>
@@ -2226,6 +2390,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">KonfiguraÄný súbor slúži k nastavovaniu užívateľsky pokroÄilých možností, ktoré majú prednosÅ¥ pred konfiguráciou z grafického rozhrania. Parametre z príkazového riadka vÅ¡ak majú pred konfiguraÄným súborom prednosÅ¥.</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">PokraÄovaÅ¥</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">Zrušiť</translation>
</message>
@@ -2360,6 +2528,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Nepodarilo sa podpísať transakciu: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">Nemôžem podpísať vstupy kým je peňaženka zamknutá.</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">Nie je možné podpísaÅ¥ žiadne ÄalÅ¡ie vstupy.</translation>
</message>
@@ -2433,6 +2605,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transakcii stále chýbajú podpis(y).</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Ale nie je naÄítaná žiadna peňaženka.)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Ale táto peňaženka nemôže podpisovať transakcie)</translation>
</message>
@@ -2502,6 +2678,11 @@ Ak ste dostali túto chybu mali by ste požiadaÅ¥ obchodníka o URI kompatibilnÃ
<translation type="unfinished">Partneri</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Vek</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Smer</translation>
@@ -2689,6 +2870,10 @@ Ak ste dostali túto chybu mali by ste požiadaÅ¥ obchodníka o URI kompatibilnÃ
<translation type="unfinished">Zosynchronizované bloky</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Posledná transakcia</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">Mapovaný nezávislý - Autonómny Systém používaný na rozšírenie vzájomného výberu peerov.</translation>
</message>
@@ -2697,12 +2882,32 @@ Ak ste dostali túto chybu mali by ste požiadaÅ¥ obchodníka o URI kompatibilnÃ
<translation type="unfinished">Mapovaný AS</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Postupovanie adries tomuto partnerovi.</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Postupovanie adries</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Spracované adresy</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Obmedzené adresy</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">Aplikácia</translation>
</message>
<message>
<source>Node window</source>
- <translation type="unfinished">Okno uzlov</translation>
+ <translation type="unfinished">Uzlové okno</translation>
</message>
<message>
<source>Current block height</source>
@@ -2905,6 +3110,11 @@ Ak ste dostali túto chybu mali by ste požiadaÅ¥ obchodníka o URI kompatibilnÃ
<translation type="unfinished">1 &amp;rok</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Kopírovať IP/Masku siete</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Zrušiť zákaz</translation>
</message>
@@ -3433,6 +3643,16 @@ Poznámka: KeÄže poplatok je poÄítaný za bajt, poplatok pri sadzbe "100 sat
<translation type="unfinished">PreÄítajte si prosím svoj návrh transakcie. Výsledkom bude ÄiastoÄne podpísaná bitcoinová transakcia (PSBT), ktorú môžete uložiÅ¥ alebo skopírovaÅ¥ a potom podpísaÅ¥ napr. cez offline peňaženku %1 alebo hardvérovú peňaženku kompatibilnú s PSBT.</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Chcete vytvoriť túto transakciu?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Skontrolujte prosím svoj návrh transakcie. Môžete vytvoriÅ¥ a odoslaÅ¥ túto transakciu alebo vytvoriÅ¥ ÄiastoÄne podpísanú bitcoinovú transakciu (PSBT), ktorú môžete uložiÅ¥ alebo skopírovaÅ¥ a potom podpísaÅ¥ napr. cez offline peňaženku %1 alebo hardvérovú peňaženku kompatibilnú s PSBT.</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Prosím, skontrolujte Vašu transakciu.</translation>
@@ -3485,16 +3705,12 @@ Poznámka: KeÄže poplatok je poÄítaný za bajt, poplatok pri sadzbe "100 sat
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Poplatok vyšší ako %1 sa považuje za neprimerane vysoký.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Vypršala platnosť požiadavky na platbu.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>Odhadované potvrdenie o %n blok.</numerusform>
+ <numerusform>Odhadované potvrdenie o %n bloky.</numerusform>
+ <numerusform>Odhadované potvrdenie o %n blokov.</numerusform>
</translation>
</message>
<message>
@@ -3569,14 +3785,6 @@ Poznámka: KeÄže poplatok je poÄítaný za bajt, poplatok pri sadzbe "100 sat
<translation type="unfinished">Správa:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Toto je neoverená výzva k platbe.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Toto je overená výzva k platbe.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Vložte popis pre túto adresu aby sa uložila do zoznamu použitých adries</translation>
</message>
@@ -3584,14 +3792,6 @@ Poznámka: KeÄže poplatok je poÄítaný za bajt, poplatok pri sadzbe "100 sat
<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 type="unfinished">Správa ktorá bola pripojená k bitcoin: URI a ktorá bude uložená s transakcou pre Vaše potreby. Poznámka: Táto správa nebude poslaná cez sieť Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Platba pre:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Poznámka:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3753,35 +3953,31 @@ Poznámka: KeÄže poplatok je poÄítaný za bajt, poplatok pri sadzbe "100 sat
<source>(press q to shutdown and continue later)</source>
<translation type="unfinished">(stlaÄte Q pre ukonÄenie a pokraÄovanie neskôr)</translation>
</message>
- </context>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">stlaÄte q pre ukonÄenie</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">koliduje s transakciou s %1 potvrdeniami</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/nepotvrdené, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">v transakÄnom zásobníku</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">nie je v transakÄnom zásobníku</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">zanechaná</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/nepotvrdené</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 potvrdení</translation>
</message>
<message>
@@ -3831,9 +4027,9 @@ Poznámka: KeÄže poplatok je poÄítaný za bajt, poplatok pri sadzbe "100 sat
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>dozrie o Äalší %n blok</numerusform>
+ <numerusform>dozrie o ÄalÅ¡ie %n bloky</numerusform>
+ <numerusform>dozrie o Äalších %n blokov</numerusform>
</translation>
</message>
<message>
@@ -4126,6 +4322,11 @@ Poznámka: KeÄže poplatok je poÄítaný za bajt, poplatok pri sadzbe "100 sat
<translation type="unfinished">&amp;Upraviť popis transakcie</translation>
</message>
<message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Zobraziť v %1</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Exportovať históriu transakcií</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sl.ts b/src/qt/locale/bitcoin_sl.ts
index bf7e3c4dd1..cac051f95b 100644
--- a/src/qt/locale/bitcoin_sl.ts
+++ b/src/qt/locale/bitcoin_sl.ts
@@ -242,22 +242,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<context>
<name>BitcoinApplication</name>
<message>
- <source>Runaway exception</source>
- <translation type="unfinished">Pobegla izjema</translation>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Datoteka z nastavitvami %1 je morda ovkarjena ali neveljavna.</translation>
</message>
- <message>
- <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <translation type="unfinished">PriÅ¡lo je do usodne napake. %1 ne more veÄ varno nadaljevati s tekom in se bo ustavil.</translation>
- </message>
- <message>
- <source>Internal error</source>
- <translation type="unfinished">Interna napaka</translation>
- </message>
- <message>
- <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
- <translation type="unfinished">PriÅ¡lo je do interne napake. %1 bo skuÅ¡al varno nadaljevati. To je nepriÄakovana napaka, ki jo lahko prijavite, kot je opisano spodaj.</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -464,10 +452,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Napaka: podedovane denarnice podpirajo le naslove vrst "legacy", "p2sh-segwit" in "bech32".</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Napaka: ni mogoÄe biti odprt za dohodne povezave (vrnjena napaka: %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Ocena provizije ni uspela. Uporaba nadomestne provizije (fallback fee) je onemogoÄena. PoÄakajte nekaj blokov ali omogoÄite -fallbackfee.</translation>
</message>
@@ -512,6 +496,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Obrezovanje ne sme biti nastavljeno pod %d miB. Prosimo, uporabite veÄjo Å¡tevilko.</translation>
</message>
<message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">NaÄin obrezovanja ni združljiv z možnostjo -reindex-chainstate. Namesto tega uporabite polni -reindex.</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 type="unfinished">Obrezovanje: zadnja sinhronizacija denarnice je izven obrezanih podatkov. Izvesti morate -reindex (v primeru obrezanega naÄina delovanja bo potrebno znova prenesti celotno verigo blokov).</translation>
</message>
@@ -564,6 +552,14 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Nastavljena je neznana oblika datoteke denarnice "%s". Prosimo, uporabite "bdb" ali "sqlite".</translation>
</message>
<message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">Podatkovna baza stanja verige (chainstate) je v formatu, ki ni podprt. Prosimo, ponovno zaženite program z možnostjo -reindex-chainstate. S tem bo baza stanja verige zgrajena ponovno.</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Denarnica uspeÅ¡no ustvarjena. Podedovani tip denarnice je zastarel in v opuÅ¡Äanju. Podpora za tvorbo in odpiranje denarnic podedovanega tipa bo v prihodnosti odstranjena.</translation>
+ </message>
+ <message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
<translation type="unfinished">Opozorilo: oblika izvozne (dump) datoteke "%s" ne ustreza obliki "%s", izbrani v ukazni vrstici.</translation>
</message>
@@ -612,6 +608,22 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Nadgradnja -txindex je bila zaÄeta s prejÅ¡njo razliÄico programske opreme in je ni mogoÄe dokonÄati. Poskusite ponovno s prejÅ¡njo razliÄico ali pa zaženite poln -reindex.</translation>
</message>
<message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Možnost -reindex-chainstate ni združljiva z -blockfilterindex. Prosimo, ali zaÄasno onemogoÄite blockfilterindex in uporabite -reindex-chainstate ali pa namesto reindex-chainstate uporabite -reindex za popolno ponovno tvorbo vseh kazal.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Možnost -reindex-chainstate option ni združljiva z -coinstatsindex. Prosimo, ali zaÄasno onemogoÄite coinstatsindex in uporabite -reindex-chainstate ali pa namesto reindex-chainstate uporabite -reindex za popolno ponovno tvorbo vseh kazal.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Možnost -reindex-chainstate option ni združljiva s -txindex. Prosimo, ali zaÄasno onemogoÄite txindex in uporabite -reindex-chainstate ali pa namesto reindex-chainstate uporabite -reindex za popolno ponovno tvorbo vseh kazal.</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">Zadnja sinhronizacija denarnice pade izven obdobja blokov, katerih podatki so na voljo. Potrebno je poÄakati, da preverjanje v ozadju prenese potrebne bloke.</translation>
+ </message>
+ <message>
<source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
<translation type="unfinished">Nezdružljivi nastavitvi: navedene so specifiÄne povezave in hkrati se uporablja addrman za iskanje izhodnih povezav.</translation>
</message>
@@ -620,6 +632,22 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Napaka pri nalaganu %s: Denarnica za zunanje podpisovanje naložena, podpora za zunanje podpisovanje pa ni prevedena</translation>
</message>
<message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Preimenovanje neveljavne datoteke peers.dat je spodletelo. Prosimo, premaknite ali izbrišite jo in poskusite znova.</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+ÄŒiÅ¡Äenje po spodleteli migraciji je spodletelo.</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Obnovitev varnostne kopije denarnice ni bila mogoÄa.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">Konfiguracijske nastavitve za %s se na omrežju %s upoÅ¡tevajo le, Äe so zapisane v odseku [%s].</translation>
</message>
@@ -696,10 +724,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Napaka pri branju naslednjega zapisa v podatkovni bazi denarnice.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Napaka pri nadgradnji baze podatkov stanja verige.</translation>
- </message>
- <message>
<source>Error: Couldn't create cursor into database</source>
<translation type="unfinished">Napaka: ne morem ustvariti kurzorja v bazo</translation>
</message>
@@ -848,10 +872,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Noben naslov ni na voljo</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Posredniški strežnik (proxy) ni nastavljen. Uporabite -proxy=&lt;ip&gt; ali -proxy=&lt;ip:port&gt;.</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">Na voljo ni dovolj deskriptorjev datotek.</translation>
</message>
@@ -860,10 +880,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Negativne vrednosti parametra funkcije obrezovanja niso sprejemljive.</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Funkcija obrezovanja ni združljiva z opcijo -coinstatsindex.</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">Funkcija obrezovanja ni združljiva z opcijo -txindex.</translation>
</message>
@@ -984,6 +1000,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Transkacija je prevelika</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">Spodletelo je dodeljevanje pomnilnika za -maxsigcachesize: '%s' MiB</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation type="unfinished">Na tem raÄunalniku ni bilo mogoÄe vezati naslova %s (vrnjena napaka: %s)</translation>
</message>
@@ -996,6 +1016,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Ne morem ustvariti PID-datoteke '%s': %s</translation>
</message>
<message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">Ne najdem UTXO-ja za zunanji vhod</translation>
+ </message>
+ <message>
<source>Unable to generate initial keys</source>
<translation type="unfinished">Ne morem ustvariti zaÄetnih kljuÄev</translation>
</message>
@@ -1040,10 +1064,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Nepodprta kategorija beleženja %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Nadgrajujem podatkovno bazo UTXO (nepotrošenih kovancev)</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Komentar uporabniškega agenta (%s) vsebuje nevarne znake.</translation>
</message>
@@ -1187,16 +1207,32 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<source>&amp;Load PSBT from file…</source>
<translation type="unfinished">&amp;Naloži DPBT iz datoteke...</translation>
</message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Sinhroniziram zaglavja (%1 %)…</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Sinhroniziram z omrežjem...</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation type="unfinished">&amp;Možnosti iz ukazne vrstice</translation>
+ </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform>Obdelan je %n blok zgodovine transakcij.</numerusform>
- <numerusform>Obdelana sta %n bloka zgodovine transakcij.</numerusform>
- <numerusform>Obdelani so %n bloki zgodovine transakcij.</numerusform>
- <numerusform>Obdelanih je %n blokov zgodovine transakcij.</numerusform>
+ <numerusform>Obdelan %n blok zgodovine transakcij.</numerusform>
+ <numerusform>Obdelana %n bloka zgodovine transakcij.</numerusform>
+ <numerusform>Obdelani %n bloki zgodovine transakcij.</numerusform>
+ <numerusform>Obdelanih %n blokov zgodovine transakcij.</numerusform>
</translation>
</message>
<message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">Naloži delno podpisano bitcoin-transakcijo</translation>
+ </message>
+ <message>
<source>Load PSBT from &amp;clipboard…</source>
<translation type="unfinished">Naloži DPBT z &amp;odložiÅ¡Äa...</translation>
</message>
@@ -1237,6 +1273,16 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Zapri denarnico</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Obnovi denarnico...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Obnovi denarnico iz datoteke z varnostno kopijo</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Zapri vse denarnice</translation>
</message>
@@ -1261,6 +1307,26 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Ni denarnic na voljo</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Podatki o denarnici</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Naloži varnostno kopijo denarnice</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Obnovi denarnico</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Ime denarnice</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">O&amp;kno</translation>
</message>
@@ -1276,10 +1342,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform>%n aktivna povezava v omrežje bitcoin</numerusform>
- <numerusform>%n aktivni povezavi v omrežje bitcoin</numerusform>
- <numerusform>%n aktivne povezave v omrežje bitcoin</numerusform>
- <numerusform>%n aktivnih povezav v omrežje bitcoin</numerusform>
+ <numerusform>%n aktivna povezava v omrežje bitcoin. </numerusform>
+ <numerusform>%n aktivni povezavi v omrežje bitcoin.</numerusform>
+ <numerusform>%n aktivne povezave v omrežje bitcoin.</numerusform>
+ <numerusform>%n aktivnih povezav v omrežje bitcoin.</numerusform>
</translation>
</message>
<message>
@@ -1303,6 +1369,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">OmogoÄi omrežno aktivnost</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Predsinhronizacija zaglavij (%1 %)...</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Napaka: %1</translation>
</message>
@@ -1557,6 +1627,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<source>Can't list signers</source>
<translation type="unfinished">Ne morem našteti podpisnikov</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Zunanjih podpisnikov je preveÄ</translation>
+ </message>
</context>
<context>
<name>LoadWalletsActivity</name>
@@ -1597,6 +1671,34 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Obnovi denarnico</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Obnavljanje denarnice &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Obnova denarnice je spodletela</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Obnova denarnice - opozorilo</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Obnova denarnice - sporoÄilo</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1771,13 +1873,32 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
</context>
<context>
<name>Intro</name>
- <message>
- <source>%1 GB of space available</source>
- <translation type="unfinished">Na voljo je %1 GB prostora.</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB prostora na voljo</numerusform>
+ <numerusform>%n GB prostora na voljo</numerusform>
+ <numerusform>%n GB prostora na voljo</numerusform>
+ <numerusform>%n GB prostora na voljo</numerusform>
+ </translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(od potrebnih %1 GB)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(od potrebnih %n GiB)</numerusform>
+ <numerusform>(od potrebnih %n GiB)</numerusform>
+ <numerusform>(od potrebnih %n GiB)</numerusform>
+ <numerusform>(od potrebnih %n GB)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB potreben za celotno verigo blokov)</numerusform>
+ <numerusform>(%n GB potrebna za celotno verigo blokov)</numerusform>
+ <numerusform>(%n GB potrebni za celotno verigo blokov)</numerusform>
+ <numerusform>(%n GB potrebnih za celotno verigo blokov)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1810,10 +1931,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Napaka: Ni mogoÄe ustvariti mape "%1".</translation>
</message>
<message>
- <source>Error</source>
- <translation type="unfinished">Napaka</translation>
- </message>
- <message>
<source>Welcome</source>
<translation type="unfinished">Dobrodošli</translation>
</message>
@@ -1826,10 +1943,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Ker ste program zagnali prviÄ, lahko izberete, kje bo %1 shranil 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 type="unfinished">Ko kliknete OK, bo %1 zaÄel prenaÅ¡ati podatke in procesirati celotno verigo blokov %4 (%2 GB), zaÄenÅ¡i z najstarejÅ¡o transakcijo iz %3 ob prvotnem zaÄetku %4.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Omeji velikost shrambe verige blokov na </translation>
</message>
@@ -1842,6 +1955,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">ZaÄetna sinhronizacija je zelo zahtevna in lahko odkrije probleme s strojno opremo v vaÅ¡em raÄunalniku, ki so prej bili neopaženi. VsakiÄ, ko zaženete %1, bo le-ta nadaljeval s prenosom, kjer je prejÅ¡njiÄ ostal.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">Ko kliknete OK, bo %1 priÄel prenaÅ¡ati in obdelovati celotno verigo blokov %4 (%2 GB), zaÄenÅ¡i s prvimi transakcijami iz %3, ko je bil %4 zagnan.</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 type="unfinished">ÄŒe ste se odloÄili omejiti shranjevanje blokovnih verig (obrezovanje), je treba zgodovinske podatke Å¡e vedno prenesti in obdelati, vendar bodo kasneje izbrisani, da bo poraba prostora nizka.</translation>
</message>
@@ -1934,6 +2051,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">Neznano. Sinhroniziram zaglavja (%1, %2%)...</translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Neznano. Predsinhronizacija zaglavij (%1, %2 %)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -1990,6 +2111,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">Ko zaprete glavno okno programa, bo program tekel Å¡e naprej, okno pa bo zgolj minimirano. Program v tem primeru ustavite tako, da v meniju izberete ukaz Izhod.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Možnosti, nastavljene v tem oknu, preglasi ukazna vrstica:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Odpri %1 konfiguracijsko datoteko iz delovne podatkovne mape.</translation>
</message>
@@ -2218,10 +2343,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">najboljše ujemanje "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Možnosti, nastavljene v tem pogovornem oknu, ki so bile preglašene v ukazni vrstici ali konfiguracijski datoteki:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">&amp;V redu</translation>
</message>
@@ -2244,14 +2365,22 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Potrdi ponastavitev</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Za udejanjenje sprememb je potreben ponoven zagon programa.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Trenutne nastavitve bodo varnostno shranjene na mesto "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Program bo zaustavljen. Želite nadaljevati z izhodom?</translation>
</message>
<message>
@@ -2273,10 +2402,6 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
<translation type="unfinished">PrekliÄi</translation>
</message>
<message>
- <source>Error</source>
- <translation type="unfinished">Napaka</translation>
- </message>
- <message>
<source>The configuration file could not be opened.</source>
<translation type="unfinished">Konfiguracijske datoteke ni bilo moÄ odpreti.</translation>
</message>
@@ -2290,6 +2415,13 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Branje nastavitve "%1" je spodletelo, %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2553,6 +2685,11 @@ Svetujemo, da prodajalca prosite, naj vam priskrbi URI na podlagi BIP21.</transl
<translation type="unfinished">Soležnik</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Starost</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Smer povezave</translation>
@@ -2753,29 +2890,32 @@ Svetujemo, da prodajalca prosite, naj vam priskrbi URI na podlagi BIP21.</transl
</message>
<message>
<source>Whether we relay addresses to this peer.</source>
- <extracomment>Tooltip text for the Address Relay field in the peer details area.</extracomment>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Ali temu soležniku posredujemo naslove</translation>
</message>
<message>
<source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Posrednik naslovov</translation>
</message>
<message>
- <source>Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Processed field in the peer details area.</extracomment>
- <translation type="unfinished">Skupno Å¡tevilo obdelanih naslovov, razen opuÅ¡Äenih zaradi omejitev hitrosti</translation>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Skupno število obdelanih naslovov, prejetih od tega soležnika (naslovi, ki niso bili sprejeti zaradi omejevanja gostote komunikacije, niso šteti).</translation>
</message>
<message>
- <source>Addresses Processed</source>
- <translation type="unfinished">Obdelanih naslovov</translation>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Skupno število naslovov, prejetih od tega soležnika, ki so bili zavrnjeni (niso bili obdelani) zaradi omejevanja gostote komunikacije.</translation>
</message>
<message>
- <source>Total number of addresses dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area.</extracomment>
- <translation type="unfinished">Skupno Å¡tevilo naslovov, opuÅ¡Äenih zaradi omejitev hitrosti</translation>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Obdelanih naslovov</translation>
</message>
<message>
<source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
<translation type="unfinished">Omejenih naslovov</translation>
</message>
<message>
@@ -3389,10 +3529,6 @@ Opomba: Ker se provizija izraÄuna na bajt, bi provizija "100 satoshijev na kvB"
<translation type="unfinished">Kopiraj koliÄino</translation>
</message>
<message>
- <source>Copy amount</source>
- <translation type="unfinished">Kopiraj znesek</translation>
- </message>
- <message>
<source>Copy fee</source>
<translation type="unfinished">Kopiraj provizijo</translation>
</message>
@@ -3561,10 +3697,6 @@ Opomba: Ker se provizija izraÄuna na bajt, bi provizija "100 satoshijev na kvB"
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Provizija, ki je veÄja od %1, velja za nesmiselno veliko.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Zahtevek za plaÄilo je potekel.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -3646,14 +3778,6 @@ Opomba: Ker se provizija izraÄuna na bajt, bi provizija "100 satoshijev na kvB"
<translation type="unfinished">SporoÄilo:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Ta zahtevek za plaÄilo je neoverjen.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Ta zahtevek za plaÄilo je overjen.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Če vnesete oznako za zgornji naslov, se bo skupaj z naslovom shranila v imenik že uporabljenih naslovov</translation>
</message>
@@ -3661,14 +3785,6 @@ Opomba: Ker se provizija izraÄuna na bajt, bi provizija "100 satoshijev na kvB"
<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 type="unfinished">SporoÄilo, ki je bilo pripeto na URI tipa bitcoin: in bo shranjeno skupaj s podatki o transakciji. Opomba: SporoÄilo ne bo poslano preko omrežja Bitcoin.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Prejemnik:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Opomba:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3835,30 +3951,32 @@ Opomba: Ker se provizija izraÄuna na bajt, bi provizija "100 satoshijev na kvB"
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">v sporu s transakcijo z %1 potrditvami</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/nepotrjeno, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">v Äakalni vrsti</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0 / nepotrjena, v Äakalni vrsti</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">ni v Äakalni vrsti</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0 / nepotrjena, ni v Äakalni vrsti</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">opuÅ¡Äena</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/nepotrjena</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 potrditev</translation>
</message>
<message>
@@ -4219,7 +4337,7 @@ Opomba: Ker se provizija izraÄuna na bajt, bi provizija "100 satoshijev na kvB"
<message>
<source>Comma separated file</source>
<extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
- <translation type="unfinished">Datoteka CSV (podatki loÄeni z vejicami)</translation>
+ <translation type="unfinished">Vrednosti loÄene z vejicami</translation>
</message>
<message>
<source>Confirmed</source>
@@ -4285,10 +4403,6 @@ Za odpiranje denarnice kliknite Datoteka &gt; Odpri denarnico
<translation type="unfinished">Ustvari novo denarnico</translation>
</message>
<message>
- <source>Error</source>
- <translation type="unfinished">Napaka</translation>
- </message>
- <message>
<source>Unable to decode PSBT from clipboard (invalid base64)</source>
<translation type="unfinished">Ne morem dekodirati DPBT z odložiÅ¡Äa (neveljaven format base64)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sn.ts b/src/qt/locale/bitcoin_sn.ts
index ca55e7429f..40abe38b4e 100644
--- a/src/qt/locale/bitcoin_sn.ts
+++ b/src/qt/locale/bitcoin_sn.ts
@@ -212,6 +212,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_sq.ts b/src/qt/locale/bitcoin_sq.ts
index 0dd48a1cae..21d7dbd335 100644
--- a/src/qt/locale/bitcoin_sq.ts
+++ b/src/qt/locale/bitcoin_sq.ts
@@ -207,6 +207,21 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Skedari i cilësimeve %1 mund të jetë i korruptuar ose i pavlefshëm.</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">Ndodhi një gabim fatal. %1 nuk mund të vazhdojë më i sigurt dhe do të heqë dorë.</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Ndodhi një gabim i brendshëm. %1 do të përpiqet të vazhdojë në mënyrë të sigurt. Ky është një gabim i papritur që mund të raportohet siç përshkruhet më poshtë.</translation>
+ </message>
+</context>
+<context>
<name>QObject</name>
<message>
<source>unknown</source>
@@ -455,6 +470,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -652,10 +688,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Paste address from clipboard</source>
<translation type="unfinished">Ngjit nga memorja e sistemit</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Paguaj drejt:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -668,10 +700,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/I pakonfirmuar</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 konfirmimet</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts
index 1b3763d0ae..6a5d95a8cb 100644
--- a/src/qt/locale/bitcoin_sr.ts
+++ b/src/qt/locale/bitcoin_sr.ts
@@ -92,6 +92,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Извези ЛиÑту ÐдреÑа</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">CSV фајл</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">ДеÑила Ñе грешка приликом покушаја да Ñе лиÑта адреÑа упамти на %1. Молимо покушајте поново.</translation>
@@ -241,10 +246,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">Изузетак покретања</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">Дошло је до фаталне грешке. 1%1 даље не може безбедно да наÑтави, те ће Ñе угаÑити.</translation>
+ </message>
+ <message>
<source>Internal error</source>
<translation type="unfinished">Интерна грешка</translation>
</message>
- </context>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Догодила Ñе интерна грешка. %1 ће покушати да наÑтави безбедно. Ово је неочекивана грешка која може да Ñе пријави као што је објашњено иÑпод.</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -256,6 +273,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Грешка: %1</translation>
</message>
<message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">1%1 још увек није изашао безбедно…</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">непознато</translation>
</message>
@@ -268,6 +289,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">УнеÑи Биткоин адреÑу, (нпр %1)</translation>
</message>
<message>
+ <source>Unroutable</source>
+ <translation type="unfinished">Ðемогуће преуÑмерити</translation>
+ </message>
+ <message>
+ <source>Internal</source>
+ <translation type="unfinished">Унутрашње</translation>
+ </message>
+ <message>
<source>Inbound</source>
<extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
<translation type="unfinished">Долазеће</translation>
@@ -278,6 +307,31 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Одлазеће</translation>
</message>
<message>
+ <source>Full Relay</source>
+ <extracomment>Peer connection type that relays all network information.</extracomment>
+ <translation type="unfinished">Потпуна предаја</translation>
+ </message>
+ <message>
+ <source>Block Relay</source>
+ <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Блокирана предаја</translation>
+ </message>
+ <message>
+ <source>Manual</source>
+ <extracomment>Peer connection type established manually through one of several methods.</extracomment>
+ <translation type="unfinished">УпутÑтво</translation>
+ </message>
+ <message>
+ <source>Feeler</source>
+ <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Сензор</translation>
+ </message>
+ <message>
+ <source>Address Fetch</source>
+ <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
+ <translation type="unfinished">Преузимање адреÑе</translation>
+ </message>
+ <message>
<source>None</source>
<translation type="unfinished">Nijedan</translation>
</message>
@@ -337,10 +391,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<numerusform />
</translation>
</message>
+ <message>
+ <source>%1 kB</source>
+ <translation type="unfinished">%1 килобајта</translation>
+ </message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Фајл Ñа подешавањима Ñе не може прочитати</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Фајл Ñа подешавањима Ñе не може запиÑати</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">%s девелопери</translation>
</message>
@@ -361,10 +427,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Грешка у читању %s! Сви кључеви Ñу прочитани коректно, али подаци о транÑакцији или уноÑи у адреÑар могу недоÑтајати или бити нетачни.</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Грешка: Претрага за долазним конекцијама није уÑпела (претрага враћа грешку %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Процена провизије није уÑпела. Промена провизије током транÑакције је онемогућена. Сачекајте неколико блокова или омогућите -fallbackfee.</translation>
</message>
@@ -513,10 +575,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Грешка приликом читања из базе података, иÑкључивање у току.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Грешка приликом надоградње базе података Ñтања ланца</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Грешка: ПроÑтор на диÑку је мали за %s</translation>
</message>
@@ -705,10 +763,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Категорија запиÑа није подржана %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Ðадоградња UTXO базе података</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Коментар агента кориÑника (%s) Ñадржи небезбедне знакове.</translation>
</message>
@@ -768,6 +822,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðаправи нови ночаник</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimalizuj</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Ðовчаник:</translation>
</message>
@@ -837,6 +895,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Верификуј поруке и утврди да ли Ñу потпиÑане од Ñтране Ñпецификованих Биткоин адреÑа</translation>
</message>
<message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;Учитава â€PSBT†из датотеке…</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">Отвори &amp;URI</translation>
+ </message>
+ <message>
<source>Close Wallet…</source>
<translation type="unfinished">Затвори новчаник...</translation>
</message>
@@ -869,6 +935,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Синхронизација Ñа мрежом...</translation>
</message>
<message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">ИндекÑирање блокова на диÑку…</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">ПроцеÑуирање блокова на диÑку</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">РеиндекÑирање блокова на диÑку…</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Повезивање Ñа клијентима...</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">Затражи плаћање (генерише QR кодове и биткоин: URI-е)</translation>
</message>
@@ -897,6 +979,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1 уназад</translation>
</message>
<message>
+ <source>Catching up…</source>
+ <translation type="unfinished">Ðжурирање у току...</translation>
+ </message>
+ <message>
<source>Last received block was generated %1 ago.</source>
<translation type="unfinished">ПоÑледњи примљени блок је направљен пре %1.</translation>
</message>
@@ -921,6 +1007,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðжурирано</translation>
</message>
<message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">Учитај делимично потпиÑану Bitcoin транÑакцију</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">Учитај делимично потпиÑану Bitcoin транÑакцију из clipboard-a</translation>
+ </message>
+ <message>
<source>Node window</source>
<translation type="unfinished">Ðоде прозор</translation>
</message>
@@ -961,6 +1055,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Прикажи поруку помоћи %1 за лиÑту Ñа могућим опцијама Биткоин командне линије</translation>
</message>
<message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">&amp;МаÑкирај вредноÑти</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">Филтрирај вредноÑти у картици за преглед</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation type="unfinished">подразумевани новчаник</translation>
</message>
@@ -969,6 +1071,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðема доÑтупних новчаника</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Име Ðовчаника</translation>
+ </message>
+ <message>
<source>Zoom</source>
<translation type="unfinished">Увећај</translation>
</message>
@@ -980,16 +1087,44 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 клијент</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Sakrij</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">&amp;Прикажи</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>%n активних конекција Ñа Биткоин мрежом</numerusform>
+ <numerusform>%n активних конекција Ñа Биткоин мрежом</numerusform>
+ <numerusform>%n активних конекција Ñа Биткоин мрежом</numerusform>
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Клик за више акција</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Прикажи картицу Ñа â€ÐšÐ»Ð¸Ñ˜ÐµÐ½Ñ‚имаâ€</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">Онемогући мрежне активноÑти</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">Омогући мрежне активноÑти</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Грешка: %1</translation>
</message>
@@ -1148,6 +1283,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Копирај изноÑ</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Копирај адреÑу</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Копирај &amp;означи</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Копирај &amp;изноÑ</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">Закључај непотрошено</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">Откључај непотрошено</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">Копирај количину</translation>
</message>
@@ -1219,8 +1374,25 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Create wallet warning</source>
<translation type="unfinished">Ðаправи упозорење за новчаник</translation>
</message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Ðе могу да излиÑтам потпиÑнике</translation>
+ </message>
</context>
<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">UÄitaj NovÄanik</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">UÄitavanje NovÄanika</translation>
+ </message>
+</context>
+<context>
<name>OpenWalletActivity</name>
<message>
<source>Open wallet failed</source>
@@ -1239,7 +1411,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">Отвори новчаник</translation>
</message>
- </context>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">Отвањаре новчаника &lt;b&gt;%1&lt;/b&gt;</translation>
+ </message>
+</context>
<context>
<name>WalletController</name>
<message>
@@ -1286,6 +1463,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Шифрирај новчаник</translation>
</message>
<message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">Ðапредне опције</translation>
+ </message>
+ <message>
<source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
<translation type="unfinished">Онемогући приватни кључ за овај новчаник. Ðовчаници Ñа онемогућеним приватним кључем неће имати приватни кључ и не могу имати HD Ñеме или увезени приватни кључ. Ова опција идеална је за новчанике који Ñу иÑкључиво за поÑматрање.</translation>
</message>
@@ -1302,10 +1483,36 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðаправи Празан Ðовчаник</translation>
</message>
<message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">КориÑтите деÑкрипторе за управљање ÑцриптПубКеи-ом</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">ДеÑкриптор Ðовчаник</translation>
+ </message>
+ <message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">КориÑтите Ñпољни уређај за потпиÑивање као што је хардверÑки новчаник. Прво конфигуришите Ñкрипту Ñпољног потпиÑника у подешавањима новчаника.
+</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">ЕкÑтерни потпиÑник</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">Ðаправи</translation>
</message>
- </context>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished">СаÑтављено без Ñклите подршке (потребно за новчанике деÑкриптора)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">СаÑтављено без подршке за Ñпољно потпиÑивање (потребно за Ñпољно потпиÑивање)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -1390,6 +1597,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Bitcoin</source>
<translation type="unfinished">Биткоин</translation>
</message>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(од потребних %n GB)</numerusform>
+ <numerusform>(од потребних %n GB)</numerusform>
+ <numerusform>(од потребних %n GB)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB потребно за цео ланац)</numerusform>
+ <numerusform>(%n GB потребно за цео ланац)</numerusform>
+ <numerusform>(%n GB потребно за цео ланац)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Ðајмање %1 GB подататака биће Ñкладиштен у овај директорјиум који ће временом пораÑти.</translation>
@@ -1402,9 +1633,9 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
- <numerusform />
+ <numerusform>(довољно за враћање резервних копија Ñтарих %n дана)</numerusform>
+ <numerusform>(довољно за враћање резервних копија Ñтарих %n дана)</numerusform>
+ <numerusform>(довољно за враћање резервних копија Ñтарих %n дана)</numerusform>
</translation>
</message>
<message>
@@ -1436,14 +1667,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Пошто је ово први пут да је програм покренут, можете изабрати где ће %1 чувати Ñвоје податке.</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 type="unfinished">Када кликнете на ОК, %1 ће почети Ñ Ð¿Ñ€ÐµÑƒÐ·Ð¸Ð¼Ð°ÑšÐµÐ¼ и процеÑуирањем целокупног ланца блокова %4 (%2GB), почевши од најранијих транÑакција у %3 када је %4 покренут.</translation>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">Ограничите Ñкладиштење блок ланца на</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">Враћање ове опције захтева поновно преузимање целокупног блокчејна - ланца блокова. Брже је преузети цели ланац и каÑније га Ñкратити. Онемогућава неке напредне опције.</translation>
</message>
<message>
+ <source> GB</source>
+ <translation type="unfinished">Гигабајт</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 type="unfinished">Првобитна Ñинхронизација веома је захтевна и може изложити ваш рачунар хардверÑким проблемима који раније ниÑу били примећени. Сваки пут када покренете %1, преузимање ће Ñе наÑтавити тамо где је било прекинуто.</translation>
</message>
@@ -1540,6 +1775,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
<translation type="unfinished">%1 Ñе Ñинхронузује. Преузеће заглавља и блокове од клијената и потврдити их док не Ñтигне на крај ланца блокова.</translation>
</message>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Ðепознато. Синхронизација заглавља (%1, %2%)...</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -1572,6 +1811,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Покрени %1 приликом пријаве на ÑиÑтем</translation>
</message>
<message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Омогућавање Ñмањења значајно Ñмањује проÑтор на диÑку потребан за Ñкладиштење транÑакција. Сви блокови Ñу још увек у потпуноÑти валидирани. Враћање ове поÑтавке захтева поновно преузимање целог блоцкцхаина.</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation type="unfinished">Величина кеша базе података</translation>
</message>
@@ -1624,6 +1867,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">(0 = аутоматÑки одреди, &lt;0 = оÑтави Ñлободно толико језгара)</translation>
</message>
<message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Omogući R&amp;PC server</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">Ð&amp;овчаник</translation>
</message>
@@ -1644,6 +1892,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Троши непотврђени куÑур</translation>
</message>
<message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">ЕкÑтерни потпиÑник (нпр. хардверÑки новчаник)</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;Путања Ñкрипте Ñпољног потпиÑника</translation>
+ </message>
+ <message>
+ <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished">Пуна путања до Ñкрипте компатибилне Ñа Битцоин Цоре (нпр. Ц:\ДовнлоадÑ\хви.еке или /УÑерÑ/иоу/ДовнлоадÑ/хви.пи). Пазите: злонамерни Ñофтвер може украÑти ваше новчиће</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 type="unfinished">ÐутоматÑки отвори Биткоин клијент порт на рутеру. Ова опција ради Ñамо уколико твој рутер подржава и има омогућен UPnP.</translation>
</message>
@@ -1652,6 +1912,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Мапирај порт кориÑтећи &amp;UPnP</translation>
</message>
<message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
+ <translation type="unfinished">ÐутоматÑки отворите порт за Битцоин клијент на рутеру. Ово функционише Ñамо када ваш рутер подржава ÐÐТ-ПМП и када је омогућен. Спољни порт би могао бити наÑумичан.</translation>
+ </message>
+ <message>
+ <source>Map port using NA&amp;T-PMP</source>
+ <translation type="unfinished">Мапирајте порт кориÑтећи ÐÐ&amp;Т-ПМП</translation>
+ </message>
+ <message>
<source>Accept connections from outside.</source>
<translation type="unfinished">Прихвати Ñпољашње концекције.</translation>
</message>
@@ -1688,6 +1956,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Тор</translation>
</message>
<message>
+ <source>Show the icon in the system tray.</source>
+ <translation type="unfinished">Прикажите икону у ÑиÑтемÑкој палети.</translation>
+ </message>
+ <message>
+ <source>&amp;Show tray icon</source>
+ <translation type="unfinished">&amp;Прикажи икону у траци</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation type="unfinished">Покажи Ñамо иконицу у панелу након минимизирања прозора</translation>
</message>
@@ -1724,8 +2000,24 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Да ли да Ñе прикажу опције контроле новчића или не.</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Опције поÑтављене у овом диалогу Ñу поништене командном линијом или у конфигурационој датотеци:</translation>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
+ <translation type="unfinished">Повежите Ñе на Битцоин мрежу преко заÑебног СОЦКС5 прокÑија за Тор онион уÑлуге.</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
+ <translation type="unfinished">КориÑтите поÑебан СОЦКС&amp;5 прокÑи да биÑте дошли до вршњака преко уÑлуга Тор онион:</translation>
+ </message>
+ <message>
+ <source>Monospaced font in the Overview tab:</source>
+ <translation type="unfinished">Једноразредни фонт на картици Преглед:</translation>
+ </message>
+ <message>
+ <source>embedded "%1"</source>
+ <translation type="unfinished">уграђено â€%1â€</translation>
+ </message>
+ <message>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">Ðајближа ÑличноÑÑ‚ â€%1â€</translation>
</message>
<message>
<source>&amp;OK</source>
@@ -1736,6 +2028,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;Откажи</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">СаÑтављено без подршке за Ñпољно потпиÑивање (потребно за Ñпољно потпиÑивање)</translation>
+ </message>
+ <message>
<source>default</source>
<translation type="unfinished">подразумевано</translation>
</message>
@@ -1745,14 +2042,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Потврди реÑет опција</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">РеÑтарт клијента захтеван како би Ñе промене активирале.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Клијент ће Ñе иÑкључити. Да ли желите да наÑтавите?</translation>
</message>
<message>
@@ -1766,6 +2066,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Конфигурациона датотека Ñе кориÑти да одреди напредне кориÑничке опције које поништају подешавања у графичком кориÑничком интерфејÑу.</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">Nastavi</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">Откажи</translation>
</message>
@@ -1860,7 +2164,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Current total balance in watch-only addresses</source>
<translation type="unfinished">Тренутни укупни Ñалдо у адреÑама у опцији Ñамо-гледај</translation>
</message>
- </context>
+ <message>
+ <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
+ <translation type="unfinished">Режим приватноÑти је активиран за картицу Преглед. Да биÑте демаÑкирали вредноÑти, поништите избор Подешавања-&gt;МаÑк вредноÑти.</translation>
+ </message>
+</context>
<context>
<name>PSBTOperationsDialog</name>
<message>
@@ -1888,10 +2196,67 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Затвори</translation>
</message>
<message>
+ <source>Failed to load transaction: %1</source>
+ <translation type="unfinished">ÐеуÑпело учитавање транÑакције: %1</translation>
+ </message>
+ <message>
+ <source>Failed to sign transaction: %1</source>
+ <translation type="unfinished">ÐеуÑпело потпиÑивање транÑакције: %1</translation>
+ </message>
+ <message>
+ <source>Could not sign any more inputs.</source>
+ <translation type="unfinished">Ðије могуће потпиÑати више уноÑа.</translation>
+ </message>
+ <message>
+ <source>Signed %1 inputs, but more signatures are still required.</source>
+ <translation type="unfinished">ПотпиÑано %1 поље, али је потребно још потпиÑа.</translation>
+ </message>
+ <message>
+ <source>Signed transaction successfully. Transaction is ready to broadcast.</source>
+ <translation type="unfinished">ПотпиÑана транÑакција је уÑпешно. ТранÑакција је Ñпремна за емитовање.</translation>
+ </message>
+ <message>
+ <source>Unknown error processing transaction.</source>
+ <translation type="unfinished">Ðепозната грешка у обради транÑакције.</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast successfully! Transaction ID: %1</source>
+ <translation type="unfinished">ТранÑакција је уÑпешно емитована! Идентификација транÑакције (ID): %1</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast failed: %1</source>
+ <translation type="unfinished">ÐеуÑпело емитовање транÑакције: %1</translation>
+ </message>
+ <message>
+ <source>PSBT copied to clipboard.</source>
+ <translation type="unfinished">ПСБТ је копиран у међуÑпремник.</translation>
+ </message>
+ <message>
<source>Save Transaction Data</source>
<translation type="unfinished">Сачувај Податке ТранÑакције</translation>
</message>
<message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">Делимично потпиÑана транÑакција (бинарна)</translation>
+ </message>
+ <message>
+ <source>PSBT saved to disk.</source>
+ <translation type="unfinished">ПСБТ је Ñачуван на диÑку.</translation>
+ </message>
+ <message>
+ <source> * Sends %1 to %2</source>
+ <translation type="unfinished">*Шаље %1 до %2</translation>
+ </message>
+ <message>
+ <source>Unable to calculate transaction fee or total transaction amount.</source>
+ <translation type="unfinished">Ðије могуће израчунати накнаду за транÑакцију или укупан Ð¸Ð·Ð½Ð¾Ñ Ñ‚Ñ€Ð°Ð½Ñакције.</translation>
+ </message>
+ <message>
+ <source>Pays transaction fee: </source>
+ <translation type="unfinished">Плаћа накнаду за транÑакцију:</translation>
+ </message>
+ <message>
<source>Total Amount</source>
<translation type="unfinished">Укупан изноÑ</translation>
</message>
@@ -1900,6 +2265,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">или</translation>
</message>
<message>
+ <source>Transaction has %1 unsigned inputs.</source>
+ <translation type="unfinished">ТранÑакција има %1 непотпиÑана поља.</translation>
+ </message>
+ <message>
+ <source>Transaction is missing some information about inputs.</source>
+ <translation type="unfinished">ТранÑакцији недоÑтају неке информације о улазима.</translation>
+ </message>
+ <message>
+ <source>Transaction still needs signature(s).</source>
+ <translation type="unfinished">ТранÑакција и даље треба потпиÑ(е).</translation>
+ </message>
+ <message>
+ <source>(But this wallet cannot sign transactions.)</source>
+ <translation type="unfinished">(Ðли овај новчаник не може да потпиÑује транÑакције.)</translation>
+ </message>
+ <message>
+ <source>(But this wallet does not have the right keys.)</source>
+ <translation type="unfinished">(Ðли овај новчаник нема праве кључеве.)</translation>
+ </message>
+ <message>
+ <source>Transaction is fully signed and ready for broadcast.</source>
+ <translation type="unfinished">ТранÑакција је у потпуноÑти потпиÑана и Ñпремна за емитовање.</translation>
+ </message>
+ <message>
<source>Transaction status is unknown.</source>
<translation type="unfinished">Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ñ‚Ñ€Ð°Ð½Ñакције је непознат.</translation>
</message>
@@ -1923,6 +2312,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">'bitcoin://' није важећи URI. УмеÑто тога кориÑтити 'bitcoin:'.</translation>
</message>
<message>
+ <source>Cannot process payment request because BIP70 is not supported.
+Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
+If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
+ <translation type="unfinished">Ðије могуће обрадити захтев за плаћање јер БИП70 није подржан.
+Због широко раÑпроÑтрањених безбедноÑних пропуÑта у БИП70, топло Ñе препоручује да Ñе игноришу Ñва упутÑтва трговца за промену новчаника.
+Ðко добијете ову грешку, требало би да затражите од трговца да доÑтави УРИ компатибилан Ñа БИП21.</translation>
+ </message>
+ <message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<translation type="unfinished">URI Ñе не може рашчланити! Ово може бити проузроковано неважећом Биткоин адреÑом или погрешно форматираним URI параметрима.</translation>
</message>
@@ -1944,6 +2341,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Пинг</translation>
</message>
<message>
+ <source>Peer</source>
+ <extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
+ <translation type="unfinished">Пеер</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Правац</translation>
@@ -1987,6 +2389,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>QRImageWidget</name>
<message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Сачували Ñлику…</translation>
+ </message>
+ <message>
<source>&amp;Copy Image</source>
<translation type="unfinished">&amp;Копирај Слику</translation>
</message>
@@ -2006,7 +2412,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Save QR Code</source>
<translation type="unfinished">Упамти QR Код</translation>
</message>
- </context>
+ <message>
+ <source>PNG Image</source>
+ <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment>
+ <translation type="unfinished">ПÐГ Ñлика</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -2130,6 +2541,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðоде прозор</translation>
</message>
<message>
+ <source>Current block height</source>
+ <translation type="unfinished">Тренутна виÑина блока</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 type="unfinished">Отворите %1 датотеку Ñа запиÑима о отклоњеним грешкама из тренутног директоријума датотека. Ово може потрајати неколико Ñекунди за велике датотеке запиÑа.</translation>
</message>
@@ -2142,14 +2557,59 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Увећај величину фонта</translation>
</message>
<message>
+ <source>Permissions</source>
+ <translation type="unfinished">Дозволе</translation>
+ </message>
+ <message>
+ <source>The direction and type of peer connection: %1</source>
+ <translation type="unfinished">Смер и тип конекције клијената: %1</translation>
+ </message>
+ <message>
+ <source>Direction/Type</source>
+ <translation type="unfinished">Смер/Тип</translation>
+ </message>
+ <message>
+ <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
+ <translation type="unfinished">Мрежни протокол који је овај пеер повезан преко: ИПв4, ИПв6, Онион, И2П или ЦЈДÐС.</translation>
+ </message>
+ <message>
<source>Services</source>
<translation type="unfinished">УÑлуге</translation>
</message>
<message>
+ <source>Whether the peer requested us to relay transactions.</source>
+ <translation type="unfinished">Да ли је колега тражио од Ð½Ð°Ñ Ð´Ð° пренеÑемо транÑакције</translation>
+ </message>
+ <message>
+ <source>Wants Tx Relay</source>
+ <translation type="unfinished">Жели Тк Релаciju</translation>
+ </message>
+ <message>
+ <source>High bandwidth BIP152 compact block relay: %1</source>
+ <translation type="unfinished">ВиÑок проток â€BIP152†преноÑа компактних блокова: %1</translation>
+ </message>
+ <message>
+ <source>High Bandwidth</source>
+ <translation type="unfinished">ВиÑок проток</translation>
+ </message>
+ <message>
<source>Connection Time</source>
<translation type="unfinished">Време конекције</translation>
</message>
<message>
+ <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
+ <translation type="unfinished">Прошло је време од када је нови блок који је прошао почетне провере валидноÑти примљен од овог равноправног кориÑника.</translation>
+ </message>
+ <message>
+ <source>Last Block</source>
+ <translation type="unfinished">ПоÑледњи блок</translation>
+ </message>
+ <message>
+ <source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
+ <extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
+ <translation type="unfinished">Прошло је време од када је нова транÑакција прихваћена у наш мемпул примљена од овог партнера</translation>
+ </message>
+ <message>
<source>Last Send</source>
<translation type="unfinished">ПоÑледње поÑлато</translation>
</message>
@@ -2214,6 +2674,53 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Одлазно:</translation>
</message>
<message>
+ <source>Inbound: initiated by peer</source>
+ <extracomment>Explanatory text for an inbound peer connection.</extracomment>
+ <translation type="unfinished">Долазни: покренут од Ñтране вршњака</translation>
+ </message>
+ <message>
+ <source>Outbound Full Relay: default</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment>
+ <translation type="unfinished">Одлазни пуни релеј: подразумевано</translation>
+ </message>
+ <message>
+ <source>Outbound Block Relay: does not relay transactions or addresses</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">Оутбоунд Блоцк Релаи: не преноÑи транÑакције или адреÑе</translation>
+ </message>
+ <message>
+ <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
+ <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment>
+ <translation type="unfinished">Изворно упутÑтво: додато је коришћење â€RPC†%1 или %2 / %3 конфигурационих опција</translation>
+ </message>
+ <message>
+ <source>Outbound Feeler: short-lived, for testing addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">Оутбоунд Феелер: краткотрајан, за теÑтирање адреÑа</translation>
+ </message>
+ <message>
+ <source>Outbound Address Fetch: short-lived, for soliciting addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment>
+ <translation type="unfinished">Дохваћање излазне адреÑе: краткотрајно, за тражење адреÑа</translation>
+ </message>
+ <message>
+ <source>we selected the peer for high bandwidth relay</source>
+ <translation type="unfinished">одабрали Ñмо клијента за виÑок Ð¿Ñ€ÐµÐ½Ð¾Ñ Ð¿Ð¾Ð´Ð°Ñ‚Ð°ÐºÐ°</translation>
+ </message>
+ <message>
+ <source>the peer selected us for high bandwidth relay</source>
+ <translation type="unfinished">клијент Ð½Ð°Ñ Ñ˜Ðµ одабрао за виÑок Ð¿Ñ€ÐµÐ½Ð¾Ñ Ð¿Ð¾Ð´Ð°Ñ‚Ð°ÐºÐ°</translation>
+ </message>
+ <message>
+ <source>no high bandwidth relay selected</source>
+ <translation type="unfinished">није одабран проток за виÑок Ð¿Ñ€ÐµÐ½Ð¾Ñ Ð¿Ð¾Ð´Ð°Ñ‚Ð°ÐºÐ°</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Копирај адреÑу</translation>
+ </message>
+ <message>
<source>&amp;Disconnect</source>
<translation type="unfinished">&amp;Прекини везу</translation>
</message>
@@ -2222,6 +2729,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">1 &amp;Сат</translation>
</message>
<message>
+ <source>1 d&amp;ay</source>
+ <translation type="unfinished">1 дан</translation>
+ </message>
+ <message>
<source>1 &amp;week</source>
<translation type="unfinished">1 &amp;недеља</translation>
</message>
@@ -2230,6 +2741,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">1 &amp;година</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Kopiraj IP/Netmask</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">&amp;Уклони забрану</translation>
</message>
@@ -2246,6 +2762,31 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Извршење команде коришћењем "%1" новчаника</translation>
</message>
<message>
+ <source>Welcome to the %1 RPC console.
+Use up and down arrows to navigate history, and %2 to clear screen.
+Use %3 and %4 to increase or decrease the font size.
+Type %5 for an overview of available commands.
+For more information on using this console, type %6.
+
+%7WARNING: 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.%8</source>
+ <extracomment>RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</extracomment>
+ <translation type="unfinished">Добродошли у %1 "RPC†конзолу.
+КориÑти таÑтере за горе и доле да наводиш иÑторију, и %2 да очиÑтиш екран.
+КориÑти %3 и %4 да увећаш и Ñмањиш величину фонта.
+УнеÑи %5 за преглед доÑтупних комади.
+За више информација о коришћењу конзоле, притиÑни %6
+%7 УПОЗОРЕЊЕ: Преваранти Ñу Ñе активирали, говорећи кориÑницима да уноÑе команде овде, и тако краду Ñадржај новчаника. Ðе кориÑти ову конзолу без потпуног Ñхватања комплекÑноÑти ове команде. %8</translation>
+ </message>
+ <message>
+ <source>Executing…</source>
+ <extracomment>A console message indicating an entered command is currently being executed.</extracomment>
+ <translation type="unfinished">Обрада...</translation>
+ </message>
+ <message>
+ <source>(peer: %1)</source>
+ <translation type="unfinished">(клијент: %1)</translation>
+ </message>
+ <message>
<source>via %1</source>
<translation type="unfinished">преко %1</translation>
</message>
@@ -2270,6 +2811,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Забрани за</translation>
</message>
<message>
+ <source>Never</source>
+ <translation type="unfinished">Ðикада</translation>
+ </message>
+ <message>
<source>Unknown</source>
<translation type="unfinished">Ðепознато</translation>
</message>
@@ -2349,13 +2894,37 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Копирај &amp;URI</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Копирај адреÑу</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Копирај &amp;означи</translation>
+ </message>
+ <message>
+ <source>Copy &amp;message</source>
+ <translation type="unfinished">Копирај &amp;поруку</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Копирај &amp;изноÑ</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">Ðовчаник није могуће откључати.</translation>
</message>
- </context>
+ <message>
+ <source>Could not generate new %1 address</source>
+ <translation type="unfinished">Ðемогуће је генериÑати нову %1 адреÑу</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>Request payment to …</source>
+ <translation type="unfinished">Захтевај уплату ка ...</translation>
+ </message>
+ <message>
<source>Address:</source>
<translation type="unfinished">ÐдреÑа:</translation>
</message>
@@ -2384,6 +2953,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Копирај &amp;ÐдреÑу</translation>
</message>
<message>
+ <source>&amp;Verify</source>
+ <translation type="unfinished">&amp;Верификуј</translation>
+ </message>
+ <message>
+ <source>Verify this address on e.g. a hardware wallet screen</source>
+ <translation type="unfinished">Верификуј ову адреÑу на пример на екрану хардвер новчаника</translation>
+ </message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;Сачували Ñлику…</translation>
+ </message>
+ <message>
<source>Payment information</source>
<translation type="unfinished">Информације о плаћању</translation>
</message>
@@ -2514,14 +3095,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ОчиÑти Ñва поља форме.</translation>
</message>
<message>
+ <source>Inputs…</source>
+ <translation type="unfinished">Поља...</translation>
+ </message>
+ <message>
<source>Dust:</source>
<translation type="unfinished">Прашина:</translation>
</message>
<message>
+ <source>Choose…</source>
+ <translation type="unfinished">Одабери...</translation>
+ </message>
+ <message>
<source>Hide transaction fee settings</source>
<translation type="unfinished">Сакријте Ð¸Ð·Ð½Ð¾Ñ Ð½Ð°ÐºÐ½Ð°Ð´Ðµ за транÑакцију</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 rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation type="unfinished">Одредити прилагођену провизију по kB (1,000 битова) виртуелне величине транÑакције.
+
+Ðапомена: С обзиром да Ñе провизија рачуна на оÑнову броја бајтова, провизија за "100 Ñатошија по kB" за величину транÑакције од 500 бајтова (пола од 1 kB) ће аутоматÑки изноÑити Ñамо 50 Ñатошија.</translation>
+ </message>
+ <message>
<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>
@@ -2530,6 +3127,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Сувише ниÑка провизија може резултовати да транÑакција никада не буде потврђена (прочитајте опиÑ)</translation>
</message>
<message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source>
+ <translation type="unfinished">(Паметна провизија још није покренута. Ово уобичајено траје неколико блокова...)</translation>
+ </message>
+ <message>
<source>Confirmation time target:</source>
<translation type="unfinished">Циљно време потврде:</translation>
</message>
@@ -2590,6 +3191,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1 (%2 блокова)</translation>
</message>
<message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">Потпиши на уређају</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">Повежи прво Ñвој хардвер новчаник.</translation>
+ </message>
+ <message>
+ <source>Set external signer script path in Options -&gt; Wallet</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">ПодÑи екÑтерну Ñкрипту за потпиÑивање у : Options -&gt; Wallet</translation>
+ </message>
+ <message>
<source>Cr&amp;eate Unsigned</source>
<translation type="unfinished">Креирај непотпиÑано</translation>
</message>
@@ -2610,14 +3225,41 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1 до %2</translation>
</message>
<message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">Да би Ñте прегледали лиÑту примаоца кликните на "Прикажи детаље..."</translation>
+ </message>
+ <message>
+ <source>Sign failed</source>
+ <translation type="unfinished">ПотпиÑивање је неуÑпело</translation>
+ </message>
+ <message>
+ <source>External signer not found</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">ЕкÑтерни потпиÑник није пронађен</translation>
+ </message>
+ <message>
+ <source>External signer failure</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Грешка при екÑтерном потпиÑивању</translation>
+ </message>
+ <message>
<source>Save Transaction Data</source>
<translation type="unfinished">Сачувај Податке ТранÑакције</translation>
</message>
<message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">Делимично потпиÑана транÑакција (бинарна)</translation>
+ </message>
+ <message>
<source>PSBT saved</source>
<translation type="unfinished">PSBT Ñачуван</translation>
</message>
<message>
+ <source>External balance:</source>
+ <translation type="unfinished">ЕкÑтерни Ð±Ð°Ð»Ð°Ð½Ñ (Ñтање):</translation>
+ </message>
+ <message>
<source>or</source>
<translation type="unfinished">или</translation>
</message>
@@ -2626,6 +3268,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Можете повећати провизију каÑније (Ñигнали Замени-Ñа-Провизијом, BIP-125).</translation>
</message>
<message>
+ <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment>
+ <translation type="unfinished">Молимо, проверите ваш предлог транÑакције. Ово ће произвеÑти делимично потпиÑану Биткоин транÑакцију (PSBT) коју можете копирати и онда потпиÑати Ñа нпр. офлајн %1 новчаником, или PSBT компатибилним хардверÑким новчаником.</translation>
+ </message>
+ <message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Da li želite da napravite ovu transakciju?</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Молим, размотрите вашу транÑакцију.</translation>
@@ -2678,10 +3330,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">Провизија већа од %1 Ñе Ñматра апÑурдно виÑоком провизијом.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Захтев за плаћање је иÑтекао.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2762,14 +3410,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Порука:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Ово је неовлашћени захтев за плаћање.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Ово је овлашћени захтев за плаћање.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">УнеÑите ознаку за ову адреÑу да биÑте је додали на лиÑту коришћених адреÑа</translation>
</message>
@@ -2777,14 +3417,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<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 type="unfinished">Порука која је приложена биткоину: URI која ће бити Ñачувана уз транÑакцију ради референце. Ðапомена: Ова порука Ñе шаље преко Биткоин мреже.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Плати ка:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Мемо:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -2792,7 +3424,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Send</source>
<translation type="unfinished">Пошаљи</translation>
</message>
- </context>
+ <message>
+ <source>Create Unsigned</source>
+ <translation type="unfinished">Креирај непотпиÑано</translation>
+ </message>
+</context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
@@ -2933,29 +3569,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
- <name>TransactionDesc</name>
- <message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/непотврђено, %1</translation>
- </message>
+ <name>SplashScreen</name>
<message>
- <source>in memory pool</source>
- <translation type="unfinished">у удруженој меморији</translation>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">pritisni q za gašenje</translation>
</message>
+</context>
+<context>
+ <name>TrafficGraphWidget</name>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">није у удруженој меморији</translation>
+ <source>kB/s</source>
+ <translation type="unfinished">KB/s</translation>
</message>
+</context>
+<context>
+ <name>TransactionDesc</name>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">напуштено</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/непотврђено</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 порврде</translation>
</message>
<message>
@@ -3256,10 +3897,55 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Минимални изноÑ</translation>
</message>
<message>
+ <source>Range…</source>
+ <translation type="unfinished">ОпÑег:</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Копирај адреÑу</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">Копирај &amp;означи</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Копирај &amp;изноÑ</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">Копирај транÑакцију &amp;ID</translation>
+ </message>
+ <message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">Копирајте &amp;необрађену транÑакцију</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">Копирајте Ñве детаље транÑакције</translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">&amp;Прикажи детаље транакције</translation>
+ </message>
+ <message>
+ <source>Increase transaction &amp;fee</source>
+ <translation type="unfinished">Повећај провизију транÑакције</translation>
+ </message>
+ <message>
+ <source>&amp;Edit address label</source>
+ <translation type="unfinished">&amp;Promeni adresu etikete</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">Извези Детаље ТранÑакције</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">CSV фајл</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">Потврђено</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sr@latin.ts b/src/qt/locale/bitcoin_sr@latin.ts
index e57a5cbfab..a6c5122cf5 100644
--- a/src/qt/locale/bitcoin_sr@latin.ts
+++ b/src/qt/locale/bitcoin_sr@latin.ts
@@ -533,6 +533,30 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -646,10 +670,12 @@
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/nepotvrdjeno</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 potvrdjeno/ih</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts
index fe707c7cec..64776b956f 100644
--- a/src/qt/locale/bitcoin_sv.ts
+++ b/src/qt/locale/bitcoin_sv.ts
@@ -70,6 +70,11 @@
<translation type="unfinished">Detta är dina Bitcoin-adresser för att skicka betalningar. Kontrollera alltid belopp och mottagaradress innan du skickar bitcoin.</translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Detta är dina Bitcoinadresser för att ta emot betalningar. Använd knappen 'Skapa ny mottagaradress' i mottagsfliken för att skapa nya adresser. Signering är bara tillgänglig för adresser av typen 'legacy'</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">&amp;Kopiera adress</translation>
</message>
@@ -244,10 +249,19 @@ Försök igen.</translation>
<source>Internal error</source>
<translation type="unfinished">Internt fel</translation>
</message>
- </context>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Ett internt fel har uppstått. %1 kommer försöka att fortsätta. Detta är en oväntad bugg som kan rapporteras enligt nedan beskrivning.</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Ett allvarligt fel skedde. Se att filen för inställningar är möjlig att skriva, eller försök köra med "-nosettings"</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Fel: Angiven datakatalog "%1" finns inte.</translation>
</message>
@@ -260,6 +274,10 @@ Försök igen.</translation>
<translation type="unfinished">Fel: %1</translation>
</message>
<message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 har inte avslutats korrekt än...</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">okänd</translation>
</message>
@@ -348,6 +366,14 @@ Försök igen.</translation>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Filen för inställningar kunde inte läsas</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Filen för inställningar kunde inte skapas</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">%s-utvecklarna</translation>
</message>
@@ -372,10 +398,6 @@ Försök igen.</translation>
<translation type="unfinished">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>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Fel: Avlyssning av inkommande anslutningar misslyckades (Avlyssningen returnerade felkod %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Avgiftsuppskattning misslyckades. Fallbackfee är inaktiverat. Vänta några block eller aktivera -fallbackfee.</translation>
</message>
@@ -540,10 +562,6 @@ Försök igen.</translation>
<translation type="unfinished">Fel vid läsning från databas, avslutar.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Fel vid uppgradering av blockdatabasen</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">Fel: Diskutrymme är lågt för %s</translation>
</message>
@@ -624,16 +642,28 @@ Försök igen.</translation>
<translation type="unfinished">Laddar P2P-adresser…</translation>
</message>
<message>
+ <source>Loading banlist…</source>
+ <translation type="unfinished">Läser in listan över bannlysningar …</translation>
+ </message>
+ <message>
+ <source>Loading block index…</source>
+ <translation type="unfinished">Läser in blockindex...</translation>
+ </message>
+ <message>
<source>Loading wallet…</source>
<translation type="unfinished">Laddar plånboken…</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">Saknat belopp</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">Port måste anges med -whitelist: '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Ingen proxy-server vald. Använd -proxy=&lt;ip&gt; eller -proxy=&lt;ip:port&gt;.</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Inga adresser tillgängliga</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -648,6 +678,10 @@ Försök igen.</translation>
<translation type="unfinished">Gallringsläge är inkompatibelt med -txindex.</translation>
</message>
<message>
+ <source>Pruning blockstore…</source>
+ <translation type="unfinished">Rensar blockstore...</translation>
+ </message>
+ <message>
<source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
<translation type="unfinished">Minskar -maxconnections från %d till %d, på grund av systembegränsningar.</translation>
</message>
@@ -764,6 +798,10 @@ Försök igen.</translation>
<translation type="unfinished">Det gick inte att skapa nycklar</translation>
</message>
<message>
+ <source>Unable to open %s for writing</source>
+ <translation type="unfinished">Det går inte att öppna %s för skrivning</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">Kunde inte starta HTTP-server. Se felsökningsloggen för detaljer.</translation>
</message>
@@ -788,10 +826,6 @@ Försök igen.</translation>
<translation type="unfinished">Saknar stöd för loggningskategori %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">Uppgraderar UTXO-databasen</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Kommentaren i användaragent (%s) innehåller osäkra tecken.</translation>
</message>
@@ -859,6 +893,10 @@ Försök igen.</translation>
<translation type="unfinished">Skapa ny plånbok</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Minimera</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">Plånbok:</translation>
</message>
@@ -904,6 +942,10 @@ Försök igen.</translation>
<translation type="unfinished">Kryptera de privata nycklar som tillhör din plånbok</translation>
</message>
<message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;Säkerhetskopiera plånbok...</translation>
+ </message>
+ <message>
<source>&amp;Change Passphrase…</source>
<translation type="unfinished">&amp;Ändra lösenordsfras…</translation>
</message>
@@ -960,10 +1002,30 @@ Försök igen.</translation>
<translation type="unfinished">Verktygsfält för flikar</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Synkar huvuden (%1%)...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Synkroniserar med nätverket...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Indexerar block på disken...</translation>
+ </message>
+ <message>
<source>Processing blocks on disk…</source>
<translation type="unfinished">Behandlar block på disken…</translation>
</message>
<message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Indexerar om block på disken...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Ansluter till noder...</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">Begär betalningar (skapar QR-koder och bitcoin: -URIer)</translation>
</message>
@@ -982,8 +1044,8 @@ Försök igen.</translation>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>Bearbetade %n block av transaktionshistoriken.</numerusform>
+ <numerusform>Bearbetade %n block av transaktionshistoriken.</numerusform>
</translation>
</message>
<message>
@@ -1019,6 +1081,10 @@ Försök igen.</translation>
<translation type="unfinished">Läs in Delvis signerad Bitcoin transaktion (PSBT)</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">Ladda PSBT från &amp;urklipp...</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">Läs in Delvis signerad Bitcoin transaktion (PSBT) från urklipp</translation>
</message>
@@ -1055,6 +1121,16 @@ Försök igen.</translation>
<translation type="unfinished">Stäng plånboken</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Återställ Plånboken...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Återställt en plånbok från en backup-fil</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Stäng alla plånböcker</translation>
</message>
@@ -1079,6 +1155,21 @@ Försök igen.</translation>
<translation type="unfinished">Inga plånböcker tillgängliga</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Plånboksdata</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Återställ Plånbok</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Namn på plånboken</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Fönster</translation>
</message>
@@ -1094,20 +1185,34 @@ Försök igen.</translation>
<source>%1 client</source>
<translation type="unfinished">%1-klient</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">och göm</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n aktiva anslutningar till Bitcoin-nätverket.</numerusform>
+ <numerusform>%n aktiva anslutningar till Bitcoin-nätverket.</numerusform>
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Klicka för fler alternativ</translation>
+ </message>
+ <message>
<source>Disable network activity</source>
<extracomment>A context menu item.</extracomment>
<translation type="unfinished">Stäng av nätverksaktivitet</translation>
</message>
<message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">Aktivera nätverksaktivitet</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Fel: %1</translation>
</message>
@@ -1358,6 +1463,19 @@ Försök igen.</translation>
<source>Can't list signers</source>
<translation type="unfinished">Kan inte lista signerare</translation>
</message>
+ </context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">Ladda plånböcker</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">Laddar plånböcker…</translation>
+ </message>
</context>
<context>
<name>OpenWalletActivity</name>
@@ -1378,6 +1496,29 @@ Försök igen.</translation>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">Öppna plånbok</translation>
</message>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">Öppnar Plånboken &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Återställ Plånbok</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Återskapar Plånboken &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Det gick inte att återställa plånboken</translation>
+ </message>
</context>
<context>
<name>WalletController</name>
@@ -1529,9 +1670,26 @@ Försök igen.</translation>
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(av %1 GB krävs)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(av %n GB behövs)</numerusform>
+ <numerusform>(av de %n GB som behövs)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB behövs för hela kedjan)</numerusform>
+ <numerusform>(%n GB behövs för hela kedjan)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1578,8 +1736,8 @@ Försök igen.</translation>
<translation type="unfinished">Eftersom detta är första gången som programmet startas får du välja var %1 skall lagra sina data.</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 type="unfinished">När du trycker OK kommer %1 att börja ladda ner och bearbeta den fullständiga %4-blockkedjan (%2 GB), med början vid de första transaktionerna %3 när %4 först lanserades.</translation>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">Begränsa lagringsplats för blockkedjan till </translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
@@ -1758,10 +1916,20 @@ Försök igen.</translation>
<translation type="unfinished">(0 = auto, &lt;0 = lämna så många kärnor lediga)</translation>
</message>
<message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Aktivera R&amp;PC-server</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">&amp;Plånbok</translation>
</message>
<message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Ta bort avgift från summa som standard</translation>
+ </message>
+ <message>
<source>Enable coin &amp;control features</source>
<translation type="unfinished">Aktivera mynt&amp;kontrollfunktioner</translation>
</message>
@@ -1774,6 +1942,11 @@ Försök igen.</translation>
<translation type="unfinished">&amp;Spendera obekräftad växel</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Aktivera &amp;PSBT-kontroll</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 type="unfinished">Öppna automatiskt Bitcoin-klientens port på routern. Detta fungerar endast om din router stödjer UPnP och det är är aktiverat.</translation>
</message>
@@ -1782,6 +1955,10 @@ Försök igen.</translation>
<translation type="unfinished">Tilldela port med hjälp av &amp;UPnP</translation>
</message>
<message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
+ <translation type="unfinished">Öppna automatiskt Bitcoin-klientens port på routern. Detta fungerar endast om din router stödjer NAT-PMP och det är är aktiverat. Den externa porten kan vara slumpmässig.</translation>
+ </message>
+ <message>
<source>Accept connections from outside.</source>
<translation type="unfinished">Acceptera anslutningar utifrån.</translation>
</message>
@@ -1818,6 +1995,10 @@ Försök igen.</translation>
<translation type="unfinished">Visa ikonen i systemfältet.</translation>
</message>
<message>
+ <source>&amp;Show tray icon</source>
+ <translation type="unfinished">&amp;Visa ikon i systemfältet</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation type="unfinished">Visa endast en systemfältsikon vid minimering.</translation>
</message>
@@ -1858,10 +2039,6 @@ Försök igen.</translation>
<translation type="unfinished">Anslut till Bitcoin-nätverket genom en separat SOCKS5-proxy för onion-tjänster genom Tor.</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Alternativ som anges i denna dialog åsidosätts av kommandoraden eller i konfigurationsfilen:</translation>
- </message>
- <message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Avbryt</translation>
</message>
@@ -1875,14 +2052,17 @@ Försök igen.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Bekräfta att alternativen ska återställs</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Klientomstart är nödvändig för att aktivera ändringarna.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Programmet kommer att stängas. Vill du fortsätta?</translation>
</message>
<message>
@@ -1896,6 +2076,10 @@ Försök igen.</translation>
<translation type="unfinished">Konfigurationsfilen används för att ange avancerade användaralternativ som åsidosätter inställningar i GUI. Dessutom kommer alla kommandoradsalternativ att åsidosätta denna konfigurationsfil.</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">Fortsätt</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">Avbryt</translation>
</message>
@@ -2034,6 +2218,10 @@ Försök igen.</translation>
<translation type="unfinished">Ett fel uppstod när transaktionen behandlades.</translation>
</message>
<message>
+ <source>PSBT copied to clipboard.</source>
+ <translation type="unfinished">PSBT kopierad till urklipp.</translation>
+ </message>
+ <message>
<source>Save Transaction Data</source>
<translation type="unfinished">Spara transaktionsdetaljer</translation>
</message>
@@ -2121,6 +2309,11 @@ Försök igen.</translation>
<translation type="unfinished">Användaragent</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Ã…lder</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Riktning</translation>
@@ -2300,6 +2493,10 @@ Försök igen.</translation>
<translation type="unfinished">Synkade block</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Senaste Transaktion</translation>
+ </message>
+ <message>
<source>Mapped AS</source>
<translation type="unfinished">Kartlagd AS</translation>
</message>
@@ -2572,6 +2769,10 @@ Försök igen.</translation>
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>Request payment to …</source>
+ <translation type="unfinished">Begär betalning till ...</translation>
+ </message>
+ <message>
<source>Address:</source>
<translation type="unfinished">Adress</translation>
</message>
@@ -2911,10 +3112,6 @@ Försök igen.</translation>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">En avgift högre än %1 anses vara en absurd hög avgift.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Betalningsbegäran löpte ut.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2994,14 +3191,6 @@ Försök igen.</translation>
<translation type="unfinished">Meddelande:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Detta är en oautentiserad betalningsbegäran.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Detta är en autentiserad betalningsbegäran.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Ange en etikett för denna adress för att lägga till den i listan med använda adresser</translation>
</message>
@@ -3009,14 +3198,6 @@ Försök igen.</translation>
<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 type="unfinished">Ett meddelande som bifogades bitcoin: -URIn och som sparas med transaktionen som referens. Obs: Meddelandet sänds inte över Bitcoin-nätverket.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Betala till:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">PM:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3183,30 +3364,22 @@ Försök igen.</translation>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">konflikt med en transaktion med %1 bekräftelser</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/obekräftade, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">i minnespoolen</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">ej i minnespoolen</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">övergiven</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/obekräftade</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 bekräftelser</translation>
</message>
<message>
@@ -3689,6 +3862,11 @@ Gå till Fil &gt; Öppna plånbok för att läsa in en plånbok.
<translation type="unfinished">Säkerhetskopiera Plånbok</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Plånboksdata</translation>
+ </message>
+ <message>
<source>Backup Failed</source>
<translation type="unfinished">Säkerhetskopiering misslyckades</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sw.ts b/src/qt/locale/bitcoin_sw.ts
index e0adc1e10d..d4e26bb765 100644
--- a/src/qt/locale/bitcoin_sw.ts
+++ b/src/qt/locale/bitcoin_sw.ts
@@ -115,6 +115,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_szl.ts b/src/qt/locale/bitcoin_szl.ts
index b3375bb9b4..83057cce2c 100644
--- a/src/qt/locale/bitcoin_szl.ts
+++ b/src/qt/locale/bitcoin_szl.ts
@@ -802,6 +802,24 @@
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(z %n GB przidajnego)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Co nojmynij %1 GB datÅw ôstanie spamiyntane w tym katalogu, daty te bydÅm z czasym corÅz srogsze.</translation>
@@ -846,10 +864,6 @@
<translation type="unfinished">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 type="unfinished">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 type="unfinished">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 sebiyranie bydzie kÅntynuowane ôd placu w kerym ôstaÅ‚o zastawiÅne.</translation>
</message>
@@ -1498,7 +1512,7 @@
<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 type="unfinished">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>
<context>
<name>SignVerifyMessageDialog</name>
<message>
diff --git a/src/qt/locale/bitcoin_ta.ts b/src/qt/locale/bitcoin_ta.ts
index 85b7bb4691..63b7b63a74 100644
--- a/src/qt/locale/bitcoin_ta.ts
+++ b/src/qt/locale/bitcoin_ta.ts
@@ -92,6 +92,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">à®®à¯à®•à®µà®°à®¿ படà¯à®Ÿà®¿à®¯à®²à¯ à®à®•à¯à®¸à¯à®ªà¯‹à®°à¯à®Ÿà¯ செயà¯à®•Â </translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">கமா பிரிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ கோபà¯à®ªà¯</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">à®®à¯à®•à®µà®°à®¿ படà¯à®Ÿà®¿à®¯à®²à¯ˆ %1 கà¯à®•à¯ சேமிகà¯à®• à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à¯à®®à¯ ஒர௠பிழை à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯. தயவà¯à®šà¯†à®¯à¯à®¤à¯ மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
@@ -235,8 +240,33 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">ரனவே எகà¯à®¸à¯†à®ªà¯à®·à®©à¯</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">ஒர௠அபாயகரமான à®à®°à®±à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯. %1 இனி பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®• தொடர à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯ மறà¯à®±à¯à®®à¯ வெளியேறà¯à®®à¯</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">உள௠எறரà¯</translation>
+ </message>
+ </context>
+<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">அமைபà¯à®ªà¯à®•à®³à¯ˆ இயலà¯à®ªà¯à®¨à®¿à®²à¯ˆ மதிபà¯à®ªà¯à®•à®³à¯à®•à¯à®•à¯ மீடà¯à®Ÿà®®à¯ˆà®•à¯à®• வேணà¯à®Ÿà¯à®®à®¾ அலà¯à®²à®¤à¯ மாறà¯à®±à®™à¯à®•à®³à¯ˆà®šà¯ செயà¯à®¯à®¾à®®à®²à¯ நிறà¯à®¤à¯à®¤ வேணà¯à®Ÿà¯à®®à®¾?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">ஒர௠அபாயகரமான பிழை à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯. அமைபà¯à®ªà¯à®•à®³à¯ கோபà¯à®ªà¯ எழà¯à®¤à®•à¯à®•à¯‚டியதா எனà¯à®ªà®¤à¯ˆà®šà¯ சரிபாரà¯à®•à¯à®•à®µà¯à®®à¯ அலà¯à®²à®¤à¯ -nosettings மூலம௠இயகà¯à®• à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">பிழை: கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ தரவ௠அடைவ௠"%1" இலà¯à®²à¯ˆ.</translation>
</message>
@@ -249,6 +279,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">பிழை: %1</translation>
</message>
<message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1இனà¯à®©à¯à®®à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®• வெளியேரவிலà¯à®²à¯ˆ ...</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">தெரியாத</translation>
</message>
@@ -324,6 +358,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">அமைபà¯à®ªà¯à®•à®³à¯ கோபà¯à®ªà¯ˆà®ªà¯ படிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">அமைபà¯à®ªà¯à®•à®³à¯ கோபà¯à®ªà¯ˆ எழà¯à®¤ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">%s டெவலபà¯à®ªà®°à¯à®•à®³à¯</translation>
</message>
@@ -400,6 +442,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">தீரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯ -%s à®®à¯à®•à®µà®°à®¿: '%s'</translation>
</message>
<message>
+ <source>Cannot set -peerblockfilters without -blockfilterindex.</source>
+ <translation type="unfinished">-blockfiltersindex இலà¯à®²à®¾à®¤ -peerblockfilters அமைபà¯à®ªà¯ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯ </translation>
+ </message>
+ <message>
<source>Copyright (C) %i-%i</source>
<translation type="unfinished">பதிபà¯à®ªà¯à®°à®¿à®®à¯ˆ (ப) %i-%i</translation>
</message>
@@ -452,10 +498,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">டேடà¯à®Ÿà®¾à®ªà¯‡à®šà®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ படிபà¯à®ªà®¤à®¿à®²à¯ பிழை, ஷட௠டவà¯à®©à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">செயினà¯à®¸à¯à®Ÿà¯‡à®Ÿà¯ தகவலà¯à®¤à®³à®¤à¯à®¤à¯ˆ மேமà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®µà®¤à®¿à®²à¯ பிழை</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">பிழை: டிஸà¯à®•à¯ ஸà¯à®ªà¯‡à®¸à¯ %s கà¯à®•à¯ கà¯à®±à¯ˆà®µà®¾à®• உளà¯à®³à®¤à¯</translation>
</message>
@@ -596,10 +638,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">தெரியாத மாறà¯à®±à¯ வகை '%s'</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">UTXO தகவலà¯à®¤à®³à®®à¯ மேமà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯</translation>
- </message>
- <message>
<source>Wallet needed to be rewritten: restart %s to complete</source>
<translation type="unfinished">வாலட௠மீணà¯à®Ÿà¯à®®à¯ எழà¯à®¤ படவேணà¯à®Ÿà¯à®®à¯: à®®à¯à®Ÿà®¿à®•à¯à®• %s ஠மறà¯à®¤à¯Šà®Ÿà®•à¯à®•à®®à¯ செயà¯à®¯à¯à®™à¯à®•à®³à¯</translation>
</message>
@@ -655,6 +693,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">பà¯à®¤à®¿à®¯ வாலடà¯à®Ÿà¯ˆ உரà¯à®µà®¾à®•à¯à®•à¯</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;கà¯à®±à¯ˆà®¤à¯à®¤à®²à¯</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">கைபà¯à®ªà¯ˆ:</translation>
</message>
@@ -688,10 +730,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;பெறà¯</translation>
</message>
<message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;விரà¯à®ªà¯à®ªà®™à¯à®•à®³à¯</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">உஙà¯à®•à®³à¯ பணபà¯à®ªà¯ˆà®šà¯ சேரà¯à®¨à¯à®¤ தனிபà¯à®ªà®Ÿà¯à®Ÿ விசைகளை கà¯à®±à®¿à®¯à®¾à®•à¯à®•à¯à®•</translation>
</message>
<message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;பேகà¯à®•à®ªà¯ வாலடà¯...</translation>
+ </message>
+ <message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
<translation type="unfinished">உஙà¯à®•à®³à¯ பிடà¯à®Ÿà®¿à®©à®¿à®©à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯à®Ÿà®©à¯ செயà¯à®¤à®¿à®•à®³à¯ˆ உஙà¯à®•à®³à®¿à®Ÿà®®à¯ வைதà¯à®¤à®¿à®°à¯à®ªà¯à®ªà®¤à¯ˆ நிரூபிகà¯à®•</translation>
</message>
@@ -700,6 +750,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿ விகà¯à®•à®¿à®ªà¯€à®Ÿà®¿à®¯à®¾ à®®à¯à®•à®µà®°à¯à®•à®³à¯à®Ÿà®©à¯ கையொபà¯à®ªà®®à®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ˆ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤, செயà¯à®¤à®¿à®•à®³à¯ˆ சரிபாரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
</message>
<message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">திறநà¯à®¤ &amp;யூஆறà¯à®...</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation type="unfinished">&amp;கோபà¯à®ªà¯</translation>
</message>
@@ -828,6 +882,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">வாலட௠எதà¯à®µà¯à®®à¯ இலà¯à®²à¯ˆ</translation>
</message>
<message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">வாலட௠பெயரà¯</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;சாளரமà¯</translation>
</message>
@@ -1244,6 +1303,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(%n ஜிபி தேவை)</numerusform>
+ <numerusform>(%n ஜிபி தேவை)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">கà¯à®±à¯ˆà®¨à¯à®¤à®¤à¯ %1 ஜிபி தரவ௠இநà¯à®¤ அடைவில௠சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯, மேலà¯à®®à¯ காலபà¯à®ªà¯‹à®•à¯à®•à®¿à®²à¯ அத௠வளரà¯à®®à¯.</translation>
@@ -1289,10 +1362,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">இத௠மà¯à®¤à®²à¯ à®®à¯à®±à¯ˆà®¯à®¾à®• தà¯à®µà®™à¯à®•à®¿à®¯à®¤à¯, நீஙà¯à®•à®³à¯ %1 அதன௠தரவை எஙà¯à®•à¯ சேமிதà¯à®¤à¯ வைகà¯à®•à¯à®®à¯ எனà¯à®ªà®¤à¯ˆ தேரà¯à®µà¯ செயà¯à®¯à®²à®¾à®®à¯.</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 type="unfinished">நீஙà¯à®•à®³à¯ சரி எனà¯à®ªà®¤à¯ˆà®•à¯ கிளிக௠செயà¯à®¤à®¾à®²à¯ %1 ஆரமà¯à®ªà®¤à¯à®¤à®¿à®²à¯ %4 இல௠ஆரமà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ %3 இன௠ஆரமà¯à®ª பரிவரà¯à®¤à¯à®¤à®©à¯ˆà®•à®³à¯ˆà®¤à¯ தொடஙà¯à®•à¯à®®à¯ போத௠மà¯à®´à¯ %4 தொகà¯à®¤à®¿ சஙà¯à®•à®¿à®²à®¿ (%2GB) பதிவிறகà¯à®• மறà¯à®±à¯à®®à¯ செயலாகà¯à®•à®¤à¯ தொடஙà¯à®•à¯à®®à¯.</translation>
- </message>
- <message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">இநà¯à®¤ அமைபà¯à®ªà¯ˆ மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®• à®®à¯à®´à¯ பிளாகà¯à®šà¯†à®¯à®¿à®©à¯ˆà®¯à¯à®®à¯ மீணà¯à®Ÿà¯à®®à¯ டவà¯à®©à¯à®²à¯‹à®Ÿà¯ செயà¯à®¯ வேணà¯à®Ÿà¯à®®à¯. à®®à¯à®¤à®²à®¿à®²à¯ à®®à¯à®´à¯ செயினையà¯à®®à¯ டவà¯à®©à¯à®²à¯‹à®Ÿà¯ செயà¯à®¤ பினà¯à®©à®°à¯ பà¯à®°à¯‚ன௠செயà¯à®µà®¤à¯ வேகமான செயல௠ஆகà¯à®®à¯. சில மேமà¯à®ªà®Ÿà¯à®Ÿ à®…à®®à¯à®šà®™à¯à®•à®³à¯ˆ à®®à¯à®Ÿà®•à¯à®•à¯à®®à¯.</translation>
</message>
@@ -1565,10 +1634,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">நாணயக௠கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ à®…à®®à¯à®šà®™à¯à®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà®²à®¾à®®à®¾ அலà¯à®²à®¤à¯ இலà¯à®²à¯ˆà®¯à®¾.</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">இநà¯à®¤ உரையாடலில௠அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³ விரà¯à®ªà¯à®ªà®™à¯à®•à®³à¯ கடà¯à®Ÿà®³à¯ˆ வரியில௠அலà¯à®²à®¤à¯ கடà¯à®Ÿà®®à¯ˆà®ªà¯à®ªà¯ கோபà¯à®ªà®¿à®²à¯ மீளமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">&amp;சரி</translation>
</message>
@@ -1582,14 +1647,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">விரà¯à®ªà¯à®ªà®™à¯à®•à®³à¯ˆ மீடà¯à®Ÿà®®à¯ˆà®•à¯à®•à®µà¯à®®à¯</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">மாறà¯à®±à®™à¯à®•à®³à¯ˆà®šà¯ செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤ கிளையன௠மறà¯à®¤à¯Šà®Ÿà®•à¯à®•à®®à¯ தேவை.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">கிளையணà¯à®Ÿà¯ மூடபà¯à®ªà®Ÿà¯à®®à¯. நீஙà¯à®•à®³à¯ தொடர விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾?</translation>
</message>
<message>
@@ -1697,6 +1765,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>PSBTOperationsDialog</name>
<message>
+ <source>Sign Tx</source>
+ <translation type="unfinished">கையெழà¯à®¤à¯à®¤à¯ Tx</translation>
+ </message>
+ <message>
<source>Close</source>
<translation type="unfinished">நெரà¯à®•à¯à®•à®®à®¾à®©</translation>
</message>
@@ -2419,10 +2491,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Transaction creation failed!</source>
<translation type="unfinished">பரிவரà¯à®¤à¯à®¤à®©à¯ˆ உரà¯à®µà®¾à®•à¯à®•à®®à¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯!</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">கடà¯à®Ÿà®£à®®à¯ கோரிகà¯à®•à¯ˆ காலாவதியானதà¯.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2498,14 +2566,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">செயà¯à®¤à®¿:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">இத௠ஒர௠அஙà¯à®•à¯€à®•à®°à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ கடà¯à®Ÿà®£ கோரிகà¯à®•à¯ˆ.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">இத௠ஒர௠அஙà¯à®•à¯€à®•à®°à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ கடà¯à®Ÿà®£ கோரிகà¯à®•à¯ˆ.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">இநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®•à®µà®°à®¿à®•à®³à®¿à®©à¯ படà¯à®Ÿà®¿à®¯à®²à®¿à®²à¯ சேரà¯à®•à¯à®• ஒர௠லேபிளை உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯.</translation>
</message>
@@ -2513,14 +2573,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<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 type="unfinished">பிடà¯à®•à®¾à®¯à®¿à®©à¯à®Ÿà®©à¯ இணைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ செயà¯à®¤à®¿: உஙà¯à®•à®³à¯ எதிரà¯à®•à®¾à®² கà¯à®±à®¿à®ªà¯à®ªà¯à®•à¯à®•à®¾à®• பரிவரà¯à®¤à¯à®¤à®©à¯ˆà®¯à¯à®Ÿà®©à¯ யூஆரà¯à® சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯. கà¯à®±à®¿à®ªà¯à®ªà¯: இநà¯à®¤ செயà¯à®¤à®¿ பிடà¯à®•à®¾à®¯à®¿à®©à¯ வலையமைபà¯à®ªà®¿à®±à¯à®•à¯ அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà®¾à®¤à¯.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">பணம௠செலà¯à®¤à¯à®¤à¯:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">கà¯à®±à®¿à®ªà¯à®ªà®¾à®£à¯ˆ:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -2665,33 +2717,32 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">ஷடà¯à®Ÿà®µà¯à®©à¯ செயà¯à®¯, "q" à® à®…à®´à¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
+ </message>
+</context>
+<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">%1 உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à¯à®•à®³à¯à®Ÿà®©à¯ ஒர௠பரிவரà¯à®¤à¯à®¤à®©à¯ˆ à®®à¯à®°à®£à¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà®¾à®¤à®¤à¯, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">மெமரி பூலில௠உளà¯à®³à®¤à¯</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">மெமரி பூலில௠இலà¯à®²à¯ˆ</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">கைவிடபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà®¾à®¤à®¤à¯</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à¯</translation>
</message>
<message>
@@ -2983,6 +3034,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">பரிவரà¯à®¤à¯à®¤à®©à¯ˆà®¯à®¿à®©à¯ வரலாறà¯à®±à¯ˆ எகà¯à®¸à¯à®ªà¯‹à®°à¯à®Ÿà¯ செயà¯</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">கமா பிரிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ கோபà¯à®ªà¯</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">உறà¯à®¤à®¿à®¯à®¾à®•</translation>
</message>
diff --git a/src/qt/locale/bitcoin_te.ts b/src/qt/locale/bitcoin_te.ts
index 38e49ee98a..46849fd51e 100644
--- a/src/qt/locale/bitcoin_te.ts
+++ b/src/qt/locale/bitcoin_te.ts
@@ -70,6 +70,12 @@
<translation type="unfinished">ఇవి మీరౠపంపే చెలà±à°²à°¿à°‚à°ªà±à°² బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à±. నాణేలౠపంపే à°®à±à°‚దౠపà±à°°à°¤à°¿à°¸à°¾à°°à°¿ à°…à°‚à°¦à±à°•à±à°¨à±‡ à°šà°¿à°°à±à°¨à°¾à°®à°¾ మరియౠచెలà±à°²à°¿à°‚పౠమొతà±à°¤à°‚ సరిచూసà±à°•à±‹à°‚à°¡à°¿.</translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">చెలà±à°²à°¿à°‚à°ªà±à°²à°¨à± à°¸à±à°µà±€à°•à°°à°¿à°‚చడానికి ఇవి మీ బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à±. కొతà±à°¤ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à°¨à± సృషà±à°Ÿà°¿à°‚చడానికి à°¸à±à°µà±€à°•à°°à°¿à°‚చే à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à±‹à°¨à°¿ 'కొతà±à°¤ à°¸à±à°µà±€à°•à°°à°¿à°‚చే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± సృషà±à°Ÿà°¿à°‚à°šà±' బటనà±â€Œà°¨à± ఉపయోగించండి.
+'లెగసీ' à°°à°•à°‚ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à°¤à±‹ మాతà±à°°à°®à±‡ సంతకం చేయడం సాధà±à°¯à°®à°µà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± కాపీ చెయà±à°¯à°‚à°¡à°¿</translation>
</message>
@@ -86,6 +92,11 @@
<translation type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾ జాబితానౠఎగà±à°®à°¤à°¿ చేయండి</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">కామాతో వేరౠచేయబడిన ఫైలà±</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾ పటà±à°Ÿà°¿à°•à°¨à± %1 లోనికి à°ªà±à°°à±‹à°¦à±à°ªà°°à±à°šà±à°Ÿà°²à±‹ లోపమà±. మరà±à°² à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°¿ à°šà±à°¡à°‚à°¡à°¿.</translation>
@@ -229,8 +240,57 @@
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°² ఫైలౠ1 %1 పాడై ఉండవచà±à°šà± లేదా చెలà±à°²à°¦à±</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">à°°à°¨à±à°…వే మినహాయింపà±</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">ఘోరమైన లోపం సంభవించింది. %1 ఇకపై à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ కొనసాగదౠమరియౠనిషà±à°•à±à°°à°®à°¿à°¸à±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">అంతరà±à°—à°¤ లోపం</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">అంతరà±à°—à°¤ లోపం సంభవించింది. %1 à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ కొనసాగించడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±à°‚ది. ఇది ఊహించని బగà±, దీనిని దిగà±à°µ వివరించిన విధంగా నివేదించవచà±à°šà±.</translation>
+ </message>
+</context>
+<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">మీరౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± డిఫాలà±à°Ÿà± విలà±à°µà°²à°•à± రీసెటౠచేయాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾ లేదా మారà±à°ªà±à°²à± చేయకà±à°‚డానే నిలిపివేయాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">ఘోరమైన లోపం సంభవించింది. సెటà±à°Ÿà°¿à°‚à°—à±à°² ఫైలౠవà±à°°à°¾à°¯à°¦à°—ినదో లేదో తనిఖీ చేయండి లేదా - నోసెటà±à°Ÿà°¿à°‚à°—à±à°¸à± తో అమలౠచేయడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation type="unfinished">లోపం: పేరà±à°•à±Šà°¨à±à°¨ డేటా డైరెకà±à°Ÿà°°à±€ " %1 " లేదà±.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">లోపం: కానà±à°«à°¿à°—రేషనౠఫైలà±â€Œà°¨à± à°…à°¨à±à°µà°¯à°¿à°‚చలేరà±: %1.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">లోపం: %1</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 ఇంకా à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ బయటకౠరాలేదà±...</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">తెలియదà±</translation>
</message>
@@ -238,50 +298,296 @@
<source>Amount</source>
<translation type="unfinished">మొతà±à°¤à°‚</translation>
</message>
+ <message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation type="unfinished">బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± నమోదౠచేయండి (ఉదా. %1)</translation>
+ </message>
+ <message>
+ <source>Unroutable</source>
+ <translation type="unfinished">రూటౠచేయలేనిది</translation>
+ </message>
+ <message>
+ <source>Internal</source>
+ <translation type="unfinished">అంతరà±à°—à°¤</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
+ <translation type="unfinished">ఇనà±â€Œà°¬à±Œà°‚à°¡à±</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment>
+ <translation type="unfinished">à°…à°µà±à°Ÿà± బౌండà±</translation>
+ </message>
+ <message>
+ <source>Full Relay</source>
+ <extracomment>Peer connection type that relays all network information.</extracomment>
+ <translation type="unfinished">పూరà±à°¤à°¿à°—à°¾ à°à°°à±à°ªà°°à°šà±à°Ÿ</translation>
+ </message>
+ <message>
+ <source>Block Relay</source>
+ <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">à°à°°à±à°ªà°¾à°Ÿà± చేయà±à°Ÿà°¨à± నిరోధించండి</translation>
+ </message>
+ <message>
+ <source>Manual</source>
+ <extracomment>Peer connection type established manually through one of several methods.</extracomment>
+ <translation type="unfinished">మానవీయంగా</translation>
+ </message>
+ <message>
+ <source>Feeler</source>
+ <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">à°…à°¨à±à°­à±‚తి</translation>
+ </message>
+ <message>
+ <source>Address Fetch</source>
+ <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
+ <translation type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾ పొందండి</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished">à°à°¦à±€ లేదà±</translation>
+ </message>
+ <message>
+ <source>N/A</source>
+ <translation type="unfinished">వరà±à°¤à°¿à°‚à°šà°¦à±</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n సెకనà±(à°²à±)</numerusform>
+ <numerusform>%n సెకనà±(à°²à±)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n నిమిషం(à°²à±)</numerusform>
+ <numerusform>%n నిమిషం(à°²à±)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n à°—à°‚à°Ÿ(à°²à±)</numerusform>
+ <numerusform>%n à°—à°‚à°Ÿ(à°²à±)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n రోజà±(à°²à±)</numerusform>
+ <numerusform>%n రోజà±(à°²à±)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n వారం(à°²à±)</numerusform>
+ <numerusform>%n వారం(à°²à±)</numerusform>
</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation type="unfinished">%1 మరియౠ%2</translation>
+ </message>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n సంవతà±à°¸à°°à°‚(à°²à±)</numerusform>
+ <numerusform>%n సంవతà±à°¸à°°à°‚(à°²à±)</numerusform>
</translation>
</message>
</context>
<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°² ఫైలౠచదవడం సాధà±à°¯à°‚ కాలేదà±</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">సెటà±à°Ÿà°¿à°‚à°—à±à°² ఫైలౠవà±à°°à°¾à°¯à°¬à°¡à°¦à±</translation>
+ </message>
+ <message>
+ <source>Cannot set -peerblockfilters without -blockfilterindex.</source>
+ <translation type="unfinished">-blockfilterindex లేకà±à°‚à°¡à°¾ -peerblockfilters సెటౠచేయలేమà±.</translation>
+ </message>
+ <message>
+ <source>Error reading from database, shutting down.</source>
+ <translation type="unfinished">డేటాబేసౠనà±à°‚à°¡à°¿ చదవడంలో లోపం, షటౠడౌనà±.</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">లావాదేవీ పరిమాణానà±à°¨à°¿ అంచనా వేయడానికి పరిషà±à°•à°¾à°° డేటా లేదà±</translation>
+ </message>
+ <message>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation type="unfinished">à°ªà±à°°à±‚నే à°ªà±à°°à°¤à°¿à°•à±‚à°² విలà±à°µà°¤à±‹ కానà±à°«à°¿à°—రౠచేయబడదà±.</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation type="unfinished">à°ªà±à°°à±‚నౠమోడౠ-txindexà°•à°¿ à°…à°¨à±à°•à±‚లంగా లేదà±.</translation>
+ </message>
+ <message>
+ <source>Section [%s] is not recognized.</source>
+ <translation type="unfinished">విభాగం [%s] à°—à±à°°à±à°¤à°¿à°‚చబడలేదà±.</translation>
+ </message>
+ <message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation type="unfinished">పేరà±à°•à±Šà°¨à±à°¨ à°¬à±à°²à°¾à°•à±â€Œà°² డైరెకà±à°Ÿà°°à±€ "%s" ఉనికిలో లేదà±.</translation>
+ </message>
+ <message>
+ <source>Starting network threads…</source>
+ <translation type="unfinished">నెటà±â€Œà°µà°°à±à°•à± à°¥à±à°°à±†à°¡à±â€Œà°²à°¨à± à°ªà±à°°à°¾à°°à°‚à°­à°¿à°¸à±à°¤à±‹à°‚ది…</translation>
+ </message>
+ <message>
+ <source>The source code is available from %s.</source>
+ <translation type="unfinished">%s à°¨à±à°‚à°¡à°¿ సోరà±à°¸à± కోడౠఅందà±à°¬à°¾à°Ÿà±à°²à±‹ ఉంది.</translation>
+ </message>
+ <message>
+ <source>The specified config file %s does not exist</source>
+ <translation type="unfinished">పేరà±à°•à±Šà°¨à±à°¨ కానà±à°«à°¿à°—రౠఫైలౠ%s ఉనికిలో లేదà±</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation type="unfinished">à°°à±à°¸à±à°®à± చెలà±à°²à°¿à°‚చడానికి లావాదేవీ మొతà±à°¤à°‚ చాలా à°šà°¿à°¨à±à°¨à°¦à°¿</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation type="unfinished">వాలెటౠకనీస రిలే à°°à±à°¸à±à°®à± కంటే తకà±à°•à±à°µ చెలà±à°²à°¿à°‚చడానà±à°¨à°¿ నివారిసà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation type="unfinished">ఇది à°ªà±à°°à°¯à±‹à°—ాతà±à°®à°• సాఫà±à°Ÿà±â€Œà°µà±‡à°°à±.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation type="unfinished">ఇది à°ªà±à°°à°¤à°¿ లావాదేవీకి మీరౠచెలà±à°²à°¿à°‚చే కనీస లావాదేవీ à°°à±à°¸à±à°®à±.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation type="unfinished">మీరౠలావాదేవీని పంపితే మీరౠచెలà±à°²à°¿à°‚చే లావాదేవీ à°°à±à°¸à±à°®à± ఇది.</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation type="unfinished">లావాదేవీ మొతà±à°¤à°‚ చాలా à°šà°¿à°¨à±à°¨à°¦à°¿</translation>
+ </message>
+ <message>
+ <source>Transaction amounts must not be negative</source>
+ <translation type="unfinished">లావాదేవీ మొతà±à°¤à°¾à°²à± à°ªà±à°°à°¤à°¿à°•à±‚లంగా ఉండకూడదà±</translation>
+ </message>
+ <message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">లావాదేవీ మారà±à°ªà± à°…à°µà±à°Ÿà±â€Œà°ªà±à°Ÿà± సూచిక పరిధి వెలà±à°ªà°² ఉంది</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation type="unfinished">లావాదేవీ మెంపూలౠచైనà±â€Œà°²à±‹ చాలా పొడవà±à°—à°¾ ఉంది</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation type="unfinished">లావాదేవీకి కనీసం à°’à°• à°—à±à°°à°¹à±€à°¤ ఉండాలి</translation>
+ </message>
+ <message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">లావాదేవీకి à°šà°¿à°°à±à°¨à°¾à°®à°¾ మారà±à°ªà± అవసరం, కానీ మేమౠదానిని రూపొందించలేమà±.</translation>
+ </message>
+ <message>
+ <source>Transaction too large</source>
+ <translation type="unfinished">లావాదేవీ చాలా పెదà±à°¦à°¦à°¿</translation>
+ </message>
+ <message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">-maxsigcacheize కోసం మెమరీని కేటాయించడం సాధà±à°¯à°‚ కాలేదà±: '%s' MiB</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer (bind returned error %s)</source>
+ <translation type="unfinished">బైండౠచేయడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à± %s à°ˆ à°•à°‚à°ªà±à°¯à±‚à°Ÿà°°à±â€Œà°²à±‹ (బైండౠరిటరà±à°¨à± à°Žà°°à±à°°à°°à± %s)</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation type="unfinished">బైండౠచేయడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à± %s à°ˆ à°•à°‚à°ªà±à°¯à±‚à°Ÿà°°à±â€Œà°²à±‹. %s బహà±à°¶à°¾ ఇపà±à°ªà°Ÿà°¿à°•à±‡ అమలà±à°²à±‹ ఉంది.</translation>
+ </message>
+ <message>
+ <source>Unable to create the PID file '%s': %s</source>
+ <translation type="unfinished">PID ఫైలà±â€Œà°¨à°¿ సృషà±à°Ÿà°¿à°‚à°šà°¡à°‚ సాధà±à°¯à°‚ కాలేదౠ'%s': %s</translation>
+ </message>
+ <message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">బాహà±à°¯ ఇనà±â€Œà°ªà±à°Ÿà± కోసం UTXOని à°•à°¨à±à°—ొనడం సాధà±à°¯à°‚ కాలేదà±</translation>
+ </message>
+ <message>
+ <source>Unable to generate initial keys</source>
+ <translation type="unfinished">à°ªà±à°°à°¾à°°à°‚à°­ కీలనౠరూపొందించడం సాధà±à°¯à°‚ కాలేదà±</translation>
+ </message>
+ <message>
+ <source>Unable to generate keys</source>
+ <translation type="unfinished">కీలనౠరూపొందించడం సాధà±à°¯à°‚ కాలేదà±</translation>
+ </message>
+ <message>
+ <source>Unable to open %s for writing</source>
+ <translation type="unfinished">తెరవడం సాధà±à°¯à°‚ కాదౠ%s రాయడం కోసం</translation>
+ </message>
+ <message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">-maxuploadtarget à°…à°¨à±à°µà°¯à°¿à°‚à°šà°¡à°‚ సాధà±à°¯à°‚ కాలేదà±: '%s'</translation>
+ </message>
+ <message>
+ <source>Unable to start HTTP server. See debug log for details.</source>
+ <translation type="unfinished">HTTP సరà±à°µà°°à±â€Œà°¨à°¿ à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°¡à°‚ సాధà±à°¯à°‚ కాలేదà±. వివరాల కోసం డీబగౠలాగౠచూడండి.</translation>
+ </message>
+ <message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">తరలించడానికి à°®à±à°‚దౠవాలెటà±â€Œà°¨à°¿ à°…à°¨à±â€Œà°²à±‹à°¡à± చేయడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±</translation>
+ </message>
+ <message>
+ <source>Unknown -blockfilterindex value %s.</source>
+ <translation type="unfinished">తెలియని -blockfilterindex విలà±à°µ %s.</translation>
+ </message>
+ <message>
+ <source>Unknown address type '%s'</source>
+ <translation type="unfinished">తెలియని à°šà°¿à°°à±à°¨à°¾à°®à°¾ à°°à°•à°‚ '%s'</translation>
+ </message>
+ <message>
+ <source>Unknown change type '%s'</source>
+ <translation type="unfinished">తెలియని మారà±à°ªà± à°°à°•à°‚ '%s'</translation>
+ </message>
+ <message>
+ <source>Unknown network specified in -onlynet: '%s'</source>
+ <translation type="unfinished">తెలియని నెటà±â€Œà°µà°°à±à°•à± -onlynetలో పేరà±à°•à±Šà°¨à°¬à°¡à°¿à°‚ది: '%s'</translation>
+ </message>
+ <message>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished">తెలియని కొతà±à°¤ నియమాలౠ(వెరà±à°·à°¨à±â€Œà°¬à°¿à°Ÿà±â€Œ %i)ని యాకà±à°Ÿà°¿à°µà±‡à°Ÿà± చేశాయి</translation>
+ </message>
+ <message>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">మదà±à°¦à°¤à± లేని à°—à±à°²à±‹à°¬à°²à± లాగింగౠసà±à°¥à°¾à°¯à°¿ -లాగà±â€Œà°²à±†à°µà±†à°²à±=%s. చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ విలà±à°µà°²à±: %s.</translation>
+ </message>
+ <message>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">మదà±à°¦à°¤à± లేని లాగింగౠవరà±à°—à°‚ %s=%s</translation>
+ </message>
+ <message>
+ <source>User Agent comment (%s) contains unsafe characters.</source>
+ <translation type="unfinished">వినియోగదారౠà°à°œà±†à°‚à°Ÿà± à°µà±à°¯à°¾à°–à±à°¯ (%s)లో à°…à°¸à±à°°à°•à±à°·à°¿à°¤ à°…à°•à±à°·à°°à°¾à°²à± ఉనà±à°¨à°¾à°¯à°¿.</translation>
+ </message>
+ <message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">à°¬à±à°²à°¾à°•à±â€Œà°²à°¨à± ధృవీకరిసà±à°¤à±‹à°‚ది…</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)…</source>
+ <translation type="unfinished">వాలెటà±(à°²)ని ధృవీకరిసà±à°¤à±‹à°‚ది...</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ మళà±à°²à±€ à°µà±à°°à°¾à°¯à°¾à°²à°¿: పూరà±à°¤à°¿ చేయడానికి à°ªà±à°¨à°ƒà°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿ %s</translation>
+ </message>
+</context>
+<context>
<name>BitcoinGUI</name>
<message>
<source>&amp;Overview</source>
@@ -332,8 +638,12 @@
<translation type="unfinished">&lt;div&gt;&lt;/div&gt;</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;తగà±à°—ించడానికి</translation>
+ </message>
+ <message>
<source>Wallet:</source>
- <translation type="unfinished">ధనమà±à°¨à± తీసà±à°•à±Šà°¨à°¿à°ªà±‹à°µà± సంచి</translation>
+ <translation type="unfinished">వాలెటà±â€Œ:</translation>
</message>
<message>
<source>Network activity disabled.</source>
@@ -341,6 +651,10 @@
<translation type="unfinished">నెటà±â€Œà°µà°°à±à°•à± కారà±à°¯à°¾à°šà°°à°£ నిలిపివేయబడింది.</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation type="unfinished">à°ªà±à°°à°¾à°•à±à°¸à±€ &lt;b&gt;à°ªà±à°°à°¾à°°à°‚భించబడింది&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation type="unfinished">బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± à°šà°¿à°°à±à°¨à°¾à°®à°¾à°•à± నాణేలనౠపంపండి</translation>
</message>
@@ -360,14 +674,142 @@
<source>&amp;Receive</source>
<translation type="unfinished">à°¸à±à°µà±€à°•à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
</message>
+ <message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;ఎంపికలà±...</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;వాలెటà±â€Œà°¨à°¿ à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°šà±...</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">మీ వాలెటà±â€Œà°•à± చెందిన à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కీలనౠగà±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;à°¬à±à°¯à°¾à°•à°ªà± వాలెటà±...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;సంకేతపదం మారà±à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">సంతకం &amp;సందేశం...</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">మీ బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à± మీ à°¸à±à°µà°‚తమని నిరూపించà±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ వాటితో సందేశాలనౠసంతకం చేయండి</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;సందేశానà±à°¨à°¿ ధృవీకరించండి...</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">సందేశాలౠపేరà±à°•à±Šà°¨à±à°¨ బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à°¤à±‹ సంతకం చేసినటà±à°²à± నిరà±à°§à°¾à°°à°¿à°‚à°šà±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ వాటిని ధృవీకరించండి</translation>
+ </message>
+ <message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;ఫైలౠనà±à°‚à°¡à°¿ PSBTని లోడౠచేయండి...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">&amp;URI ని తెరవండి...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">వాలెటౠని మూసివేయి...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">వాలెటౠని సృషà±à°Ÿà°¿à°‚à°šà°‚à°¡à°¿...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">à°…à°¨à±à°¨à°¿ వాలెటà±à°²à°¨à± మూసివేయి…</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation type="unfinished">&amp;ఫైలà±</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation type="unfinished">&amp;సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation type="unfinished">&amp;సహాయం</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation type="unfinished">à°Ÿà±à°¯à°¾à°¬à±â€Œà°² టూలà±â€Œà°¬à°¾à°°à±</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">శీరà±à°·à°¿à°•à°²à°¨à± సమకాలీకరించడం (%1%)...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">నెటà±â€Œà°µà°°à±à°•à±â€Œà°¤à±‹ సమకాలీకరించబడà±à°¤à±‹à°‚ది...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">à°¡à°¿à°¸à±à°•à±â€Œà°²à±‹ à°¬à±à°²à°¾à°•à±â€Œà°²à°¨à± సూచిక చేసà±à°¤à±‹à°‚ది…</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">à°¡à°¿à°¸à±à°•à±â€Œà°²à±‹ à°¬à±à°²à°¾à°•à±â€Œà°²à°¨à± à°ªà±à°°à°¾à°¸à±†à°¸à± చేసà±à°¤à±‹à°‚ది...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">à°¡à°¿à°¸à±à°•à±â€Œà°²à±‹à°¨à°¿ à°¬à±à°²à°¾à°•à±â€Œà°²à°¨à± రీఇండెకà±à°¸à°¿à°‚గౠచేసà±à°¤à±‹à°‚ది...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">తోటివారితో à°•à°²à±à°¸à±à°¤à±à°‚ది…</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation type="unfinished">చెలà±à°²à°¿à°‚à°ªà±à°²à°¨à± à°…à°­à±à°¯à°°à±à°¥à°¿à°‚à°šà°‚à°¡à°¿ (QR కోడà±â€Œà°²à± మరియౠబిటà±â€Œà°•à°¾à°¯à°¿à°¨à±â€Œà°²à°¨à± ఉతà±à°ªà°¤à±à°¤à°¿ చేసà±à°¤à±à°‚ది: URIà°²à±)</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation type="unfinished">ఉపయోగించిన పంపే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à± మరియౠలేబà±à°²à±â€Œà°² జాబితానౠచూపండి</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation type="unfinished">ఉపయోగించిన à°¸à±à°µà±€à°•à°°à°¿à°‚చే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à± మరియౠలేబà±à°²à±â€Œà°² జాబితానౠచూపండి</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation type="unfinished">&amp;కమాండà±-లైనౠఎంపికలà±</translation>
+ </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>లావాదేవీ %n à°šà°°à°¿à°¤à±à°° యొకà±à°• à°ªà±à°°à°¾à°¸à±†à°¸à± చేయబడిన à°¬à±à°²à°¾à°•à±(à°²à±).</numerusform>
+ <numerusform>లావాదేవీ %n à°šà°°à°¿à°¤à±à°° యొకà±à°• à°ªà±à°°à°¾à°¸à±†à°¸à± చేయబడిన à°¬à±à°²à°¾à°•à±(à°²à±).</numerusform>
</translation>
</message>
<message>
+ <source>%1 behind</source>
+ <translation type="unfinished">%1 వెనà±à°•</translation>
+ </message>
+ <message>
+ <source>Catching up…</source>
+ <translation type="unfinished">పటà±à°Ÿà±à°•à±‹à°µà°¡à°‚...</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation type="unfinished">చివరిగా à°…à°‚à°¦à±à°•à±à°¨à±à°¨ à°¬à±à°²à°¾à°•à± రూపొందించబడింది %1 à°•à±à°°à°¿à°¤à°‚</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation type="unfinished">దీని తరà±à°µà°¾à°¤ లావాదేవీలౠఇంకా కనిపించవà±.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">లోపం</translation>
</message>
@@ -383,15 +825,244 @@
<source>Up to date</source>
<translation type="unfinished">తాజాగా ఉంది</translation>
</message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">పాకà±à°·à°¿à°•à°‚à°—à°¾ సంతకం చేసిన బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± లావాదేవీని లోడౠచేయండి</translation>
+ </message>
+ <message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">&amp;à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à± à°¨à±à°‚à°¡à°¿ PSBTని లోడౠచేయండి...</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à± à°¨à±à°‚à°¡à°¿ పాకà±à°·à°¿à°•à°‚à°—à°¾ సంతకం చేసిన బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± లావాదేవీని లోడౠచేయండి</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">నోడౠవిండో</translation>
+ </message>
+ <message>
+ <source>Open node debugging and diagnostic console</source>
+ <translation type="unfinished">నోడౠడీబగà±à°—ింగౠమరియౠడయాగà±à°¨à°¸à±à°Ÿà°¿à°•à± à°•à°¨à±à°¸à±‹à°²à± తెరవండి</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">&amp;à°šà°¿à°°à±à°¨à°¾à°®à°¾ పంపà±à°¤à±‹à°‚ది</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">&amp;à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à°¨à± à°¸à±à°µà±€à°•à°°à°¿à°¸à±à°¤à±‹à°‚ది</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI</source>
+ <translation type="unfinished">బిటà±â€Œà°•à°¾à°¯à°¿à°¨à±â€Œà°¨à± తెరవండి: URI</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <translation type="unfinished">వాలెటౠతెరవండి</translation>
+ </message>
+ <message>
+ <source>Open a wallet</source>
+ <translation type="unfinished">ఒక వాలెటౠతెరవండి</translation>
+ </message>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ మూసివేయండి</translation>
+ </message>
+ <message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚à°šà±â€¦</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">à°¬à±à°¯à°¾à°•à°ªà± ఫైలౠనà±à°‚à°¡à°¿ వాలెటà±â€Œà°¨à± à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">à°…à°¨à±à°¨à°¿ వాలెటà±à°²à°¨à± మూసివేయండి</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation type="unfinished">%1 సాధà±à°¯à°®à°¯à±à°¯à±‡ బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± కమాండà±-లైనౠఎంపికలతో జాబితానౠపొందడానికి సహాయ సందేశానà±à°¨à°¿ చూపండి</translation>
+ </message>
+ <message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">&amp;విలà±à°µà°²à°¨à± à°•à°ªà±à°ªà°¿à°ªà±à°šà±à°šà±</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">ఓవరà±â€Œà°µà±à°¯à±‚ à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à±‹à°¨à°¿ విలà±à°µà°²à°¨à± à°•à°ªà±à°ªà°¿à°ªà±à°šà±à°šà°¡à°‚ చేయండి</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">డిఫాలà±à°Ÿà± వాలెటà±</translation>
+ </message>
+ <message>
+ <source>No wallets available</source>
+ <translation type="unfinished">వాలెటà±à°²à± à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేవà±</translation>
+ </message>
+ <message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">వాలెటౠసమాచారం</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">వాలెటౠబà±à°¯à°¾à°•à°ªà± లోడౠచేయండి</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">వాలెటౠపేరà±</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;విండో</translation>
+ </message>
+ <message>
+ <source>Zoom</source>
+ <translation type="unfinished">జూమౠచేయండి</translation>
+ </message>
+ <message>
+ <source>Main Window</source>
+ <translation type="unfinished">à°ªà±à°°à°§à°¾à°¨ విండో</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation type="unfinished">%1 à°•à±à°²à°¯à°¿à°‚à°Ÿà±</translation>
+ </message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;దాచà±</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">S&amp;ఎలా</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± నెటà±â€Œà°µà°°à±à°•à±â€Œà°•à± à°•à±à°°à°¿à°¯à°¾à°¶à±€à°² కనెకà±à°·à°¨à±(à°²à±).</numerusform>
+ <numerusform>%n బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± నెటà±â€Œà°µà°°à±à°•à±â€Œà°•à± à°•à±à°°à°¿à°¯à°¾à°¶à±€à°² కనెకà±à°·à°¨à±(à°²à±).</numerusform>
</translation>
</message>
- </context>
+ <message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">మరినà±à°¨à°¿ à°šà°°à±à°¯à°² కోసం à°•à±à°²à°¿à°•à± చేయండి.</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">పీరà±à°¸à± à°Ÿà±à°¯à°¾à°¬à±â€Œà°¨à°¿ చూపించà±</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">నెటà±â€Œà°µà°°à±à°•à± కారà±à°¯à°¾à°šà°°à°£à°¨à± నిలిపివేయండి</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">నెటà±â€Œà°µà°°à±à°•à± కారà±à°¯à°¾à°šà°°à°£à°¨à± à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">హెడà±â€Œà°²à°¨à± à°ªà±à°°à±€-సింకౠచేసà±à°¤à±‹à°‚ది (%1%)...</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">లోపం: %1</translation>
+ </message>
+ <message>
+ <source>Warning: %1</source>
+ <translation type="unfinished">హెచà±à°šà°°à°¿à°•: %1</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation type="unfinished">తేదీ: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation type="unfinished">మొతà±à°¤à°‚: %1
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation type="unfinished">వాలెటà±: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation type="unfinished">à°°à°•à°‚: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation type="unfinished">లేబà±à°²à±: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation type="unfinished">పంపిన లావాదేవీ</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation type="unfinished">కొతà±à°¤à°—à°¾ వచà±à°šà°¿à°¨ లావాదేవీ</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD à°•à±€ ఉతà±à°ªà°¤à±à°¤à°¿ &lt;b&gt;à°ªà±à°°à°¾à°°à°‚భించబడింది&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD à°•à±€ ఉతà±à°ªà°¤à±à°¤à°¿ &lt;b&gt;నిలిపివేయబడింది&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">à°ªà±à°°à±ˆà°µà±‡à°Ÿà± à°•à±€ &lt;b&gt;నిలిపివేయబడింది&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 type="unfinished">వాలెటౠ&lt;b&gt;à°Žà°¨à±â€Œà°•à±à°°à°¿à°ªà±à°Ÿà± చేయబడింది&lt;/b&gt; మరియౠపà±à°°à°¸à±à°¤à±à°¤à°‚ &lt;b&gt;à°…à°¨à±â€Œà°²à°¾à°•à± చేయబడింది&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 type="unfinished">వాలెటౠ&lt;b&gt;à°Žà°¨à±â€Œà°•à±à°°à°¿à°ªà±à°Ÿà± చేయబడింది&lt;/b&gt; మరియౠపà±à°°à°¸à±à°¤à±à°¤à°‚ &lt;b&gt;లాకౠచేయబడింది&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">అసలౠసందేశం:</translation>
+ </message>
+</context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">అమౌంటౠని చూపించడానికి యూనిటà±. మరొక యూనిటà±â€Œà°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ à°•à±à°²à°¿à°•à± చేయండి.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -403,25 +1074,402 @@
<translation type="unfinished">పరిమాణం</translation>
</message>
<message>
+ <source>Bytes:</source>
+ <translation type="unfinished">బైటà±â€Œà°²à±:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">మొతà±à°¤à°‚:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">à°°à±à°¸à±à°®à±:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">à°¦à±à°®à±à°®à±:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">à°°à±à°¸à±à°®à± తరà±à°µà°¾à°¤:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">మారà±à°šà±:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation type="unfinished">à°Žà°‚à°šà±à°•à±à°¨à±à°¨à°µà°¨à±à°¨à±€ తొలగించà±</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation type="unfinished">చెటà±à°Ÿà± విధానం</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation type="unfinished">జాబితా విధానం</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation type="unfinished">మొతà±à°¤à°‚</translation>
</message>
<message>
+ <source>Received with label</source>
+ <translation type="unfinished">లేబà±à°²à±â€Œà°¤à±‹ à°¸à±à°µà±€à°•à°°à°¿à°‚చబడింది</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¤à±‹ à°¸à±à°µà±€à°•à°°à°¿à°‚చబడింది</translation>
+ </message>
+ <message>
<source>Date</source>
<translation type="unfinished">తేదీ</translation>
</message>
<message>
+ <source>Confirmations</source>
+ <translation type="unfinished">నిరà±à°§à°¾à°°à°£à°²à±</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">నిరà±à°§à°¾à°°à°¿à°‚చబడినది</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">కాపీ అమౌంటà±</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;కాపీ à°šà°¿à°°à±à°¨à°¾à°®à°¾</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">కాపీ &amp;లేబà±à°²à±</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">కాపీ &amp;అమౌంటà±</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">లావాదేవీ &amp;ID మరియౠఅవà±à°Ÿà±â€Œà°ªà±à°Ÿà± సూచికనౠకాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">à°–à°°à±à°šà± చేయనిది లాకౠచేయండి</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;à°–à°°à±à°šà± చేయనిది విడిపించండి</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">కాపీ పరిమాణం</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">à°°à±à°¸à±à°®à± కాపీ</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">à°°à±à°¸à±à°®à± తరà±à°µà°¾à°¤ కాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">బైటà±â€Œà°²à°¨à± కాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">à°¦à±à°®à±à°®à±à°¨à± కాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">మారà±à°ªà±à°¨à°¿ కాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation type="unfinished">(%1 లాకౠచేయబడింది)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation type="unfinished">à°…à°µà±à°¨à±</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation type="unfinished">లేదà±</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished">à°à°¦à±ˆà°¨à°¾ à°—à±à°°à°¹à±€à°¤ à°ªà±à°°à°¸à±à°¤à±à°¤ ధూళి à°¥à±à°°à±†à°·à±‹à°²à±à°¡à± కంటే à°šà°¿à°¨à±à°¨ మొతà±à°¤à°¾à°¨à±à°¨à°¿ à°¸à±à°µà±€à°•à°°à°¿à°¸à±à°¤à±‡ à°ˆ లేబà±à°²à± à°Žà°°à±à°ªà± à°°à°‚à°—à±à°²à±‹à°•à°¿ మారà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation type="unfinished">à°’à°•à±à°•à±‹ ఇనà±â€Œà°ªà±à°Ÿà±â€Œà°•à± +/- %1 సతోషి(à°²à±) మారవచà±à°šà±.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">( ఉలà±à°²à°¾à°•à± లేదౠ)</translation>
</message>
- </context>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation type="unfinished">à°¨à±à°‚à°¡à°¿ మారà±à°šà°‚à°¡à°¿ %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation type="unfinished">(మారà±à°ªà±)</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletActivity</name>
+ <message>
+ <source>Create Wallet</source>
+ <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ సృషà±à°Ÿà°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ సృషà±à°Ÿà°¿à°‚à°šà°‚à°¡à°¿ &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Create wallet failed</source>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ సృషà±à°Ÿà°¿à°‚à°šà°¡à°‚ విఫలమైంది</translation>
+ </message>
+ <message>
+ <source>Create wallet warning</source>
+ <translation type="unfinished">వాలెటౠహెచà±à°šà°°à°¿à°•à°¨à± సృషà±à°Ÿà°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">సంతకం చేసేవారిని జాబితా చేయలేరà±</translation>
+ </message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">చాలా à°Žà°•à±à°•à±à°µ బాహà±à°¯ సంతకాలౠకనà±à°—ొనబడà±à°¡à°¾à°¯à°¿</translation>
+ </message>
+</context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">వాలెటà±à°²à°¨à± లోడౠచేయండి</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">వాలెటà±à°²à°¨à± లోడౠచేసà±à°¤à±‹à°‚ది…</translation>
+ </message>
+</context>
+<context>
+ <name>OpenWalletActivity</name>
+ <message>
+ <source>Open wallet failed</source>
+ <translation type="unfinished">ఓపెనౠవాలెటౠవిఫలమైంది</translation>
+ </message>
+ <message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">ఓపెనౠవాలెటౠహెచà±à°šà°°à°¿à°•</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">డిఫాలà±à°Ÿà± వాలెటà±</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
+ <translation type="unfinished">వాలెటౠతెరవండి</translation>
+ </message>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ తెరà±à°¸à±à°¤à±‹à°‚ది &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°¸à±à°¤à±‹à°‚ది &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚à°šà°¡à°‚ విఫలమైంది</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">వాలెటౠహెచà±à°šà°°à°¿à°•à°¨à± à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">వాలెటౠసందేశానà±à°¨à°¿ à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+</context>
+<context>
+ <name>WalletController</name>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ మూసివేయండి</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">మీరౠఖచà±à°šà°¿à°¤à°‚à°—à°¾ వాలెటà±â€Œà°¨à°¿ మూసివేయాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾ &lt;i&gt;%1&lt;/i&gt;?</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">à°•à°¤à±à°¤à°¿à°°à°¿à°‚పౠపà±à°°à°¾à°°à°‚భించబడితే, వాలెటà±â€Œà°¨à± à°Žà°•à±à°•à±à°µà°¸à±‡à°ªà± మూసివేయడం వలన మొతà±à°¤à°‚ గొలà±à°¸à±à°¨à± మళà±à°²à±€ సమకాలీకరించవలసి ఉంటà±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">à°…à°¨à±à°¨à°¿ వాలెటà±à°²à°¨à± మూసివేయండి</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">మీరౠఖచà±à°šà°¿à°¤à°‚à°—à°¾ à°…à°¨à±à°¨à°¿ వాలెటà±à°²à°¨à± మూసివేయాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
+ </message>
+</context>
<context>
<name>CreateWalletDialog</name>
<message>
+ <source>Create Wallet</source>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ సృషà±à°Ÿà°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <translation type="unfinished">వాలెటౠపేరà±</translation>
+ </message>
+ <message>
<source>Wallet</source>
<translation type="unfinished">వాలెటà±</translation>
</message>
- </context>
+ <message>
+ <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ à°Žà°¨à±â€Œà°•à±à°°à°¿à°ªà±à°Ÿà± చేయండి. వాలెటౠమీకౠనచà±à°šà°¿à°¨ పాసà±â€Œà°«à±à°°à±‡à°œà±â€Œà°¤à±‹ à°Žà°¨à±â€Œà°•à±à°°à°¿à°ªà±à°Ÿà± చేయబడà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>Encrypt Wallet</source>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">à°…à°§à±à°¨à°¾à°¤à°¨ ఎంపికలà±</translation>
+ </message>
+ <message>
+ <source>Disable Private Keys</source>
+ <translation type="unfinished">à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కీలనౠనిలిపివేయండి</translation>
+ </message>
+ <message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">ఖాళీ వాలెటà±â€Œà°¨à°¿ తయారౠచేయండి</translation>
+ </message>
+ <message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">scriptPubKey నిరà±à°µà°¹à°£ కోసం à°¡à°¿à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà°°à±â€Œà°²à°¨à± ఉపయోగించండి</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">à°¡à°¿à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà°°à± వాలెటà±</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">బాహà±à°¯ సంతకందారà±</translation>
+ </message>
+ <message>
+ <source>Create</source>
+ <translation type="unfinished">సృషà±à°Ÿà°¿à°‚à°šà±</translation>
+ </message>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished">Sqlite మదà±à°¦à°¤à± లేకà±à°‚à°¡à°¾ కంపైలౠచేయబడింది (à°¡à°¿à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà°°à± వాలెటà±â€Œà°²à°•à± అవసరం)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">బాహà±à°¯ సంతకం మదà±à°¦à°¤à± లేకà±à°‚à°¡à°¾ సంకలనం చేయబడింది (బాహà±à°¯ సంతకం కోసం అవసరం)</translation>
+ </message>
+</context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± సవరించండి</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation type="unfinished">&amp;లేబà±à°²à±</translation>
+ </message>
+ <message>
+ <source>The label associated with this address list entry</source>
+ <translation type="unfinished">à°ˆ à°šà°¿à°°à±à°¨à°¾à°®à°¾ జాబితా నమోదà±à°¤à±‹ à°…à°¨à±à°¬à°‚ధించబడిన లేబà±à°²à±</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation type="unfinished">&amp;à°šà°¿à°°à±à°¨à°¾à°®à°¾</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation type="unfinished">కొతà±à°¤ పంపే à°šà°¿à°°à±à°¨à°¾à°®à°¾</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation type="unfinished">à°¸à±à°µà±€à°•à°°à°¿à°‚చే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± సవరించండి</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation type="unfinished">పంపే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± సవరించండి</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation type="unfinished">నమోదౠచేసిన à°šà°¿à°°à±à°¨à°¾à°®à°¾ "%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 type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾ "%1" ఇపà±à°ªà°Ÿà°¿à°•à±‡ "%2" లేబà±à°²à±â€Œà°¤à±‹ à°¸à±à°µà±€à°•à°°à°¿à°‚చే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°—à°¾ ఉంది మరియౠపంపే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°—à°¾ జోడించబడదà±.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation type="unfinished">నమోదౠచేసిన à°šà°¿à°°à±à°¨à°¾à°®à°¾ "%1" ఇపà±à°ªà°Ÿà°¿à°•à±‡ à°šà°¿à°°à±à°¨à°¾à°®à°¾ à°ªà±à°¸à±à°¤à°•à°‚లో "%2" లేబà±à°²à±â€Œà°¤à±‹ ఉంది.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ à°…à°¨à±â€Œà°²à°¾à°•à± చేయడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation type="unfinished">కొతà±à°¤ à°•à±€ జనరేషనౠవిఫలమైంది.</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>A new data directory will be created.</source>
+ <translation type="unfinished">కొతà±à°¤ డేటా డైరెకà±à°Ÿà°°à±€ సృషà±à°Ÿà°¿à°‚చబడà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>name</source>
+ <translation type="unfinished">పేరà±</translation>
+ </message>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation type="unfinished">డైరెకà±à°Ÿà°°à±€ ఇపà±à°ªà°Ÿà°¿à°•à±‡ ఉంది. %1 మీరౠఇకà±à°•à°¡ కొతà±à°¤ డైరెకà±à°Ÿà°°à±€à°¨à°¿ సృషà±à°Ÿà°¿à°‚చాలనà±à°•à±à°‚టే జోడించండి.</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation type="unfinished">మారà±à°—à°‚ ఇపà±à°ªà°Ÿà°¿à°•à±‡ ఉంది మరియౠఇది డైరెకà±à°Ÿà°°à±€ కాదà±.</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation type="unfinished">ఇకà±à°•à°¡ డేటా డైరెకà±à°Ÿà°°à±€à°¨à°¿ సృషà±à°Ÿà°¿à°‚చలేరà±.</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -429,36 +1477,932 @@
<translation type="unfinished">బిటà±à°•à±‹à°¯à°¿à°¨à±</translation>
</message>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB à°¸à±à°¥à°²à°‚ à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ ఉంది</numerusform>
+ <numerusform>%n GB à°¸à±à°¥à°²à°‚ à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ ఉంది</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(అవసరమైన %n GB)</numerusform>
+ <numerusform>(అవసరమైన %n GB)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(పూరà±à°¤à°¿ గొలà±à°¸à± కోసం %n GB అవసరం)</numerusform>
+ <numerusform>(పూరà±à°¤à°¿ గొలà±à°¸à± కోసం %n GB అవసరం)</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation type="unfinished">à°ˆ డైరెకà±à°Ÿà°°à±€à°²à±‹ కనీసం %1 GB డేటా నిలà±à°µ చేయబడà±à°¤à±à°‚ది మరియౠఇది కాలకà±à°°à°®à±‡à°£à°¾ పెరà±à°—à±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>Approximately %1 GB of data will be stored in this directory.</source>
+ <translation type="unfinished">à°ˆ డైరెకà±à°Ÿà°°à±€à°²à±‹ à°¸à±à°®à°¾à°°à± %1 GB డేటా నిలà±à°µ చేయబడà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(à°¬à±à°¯à°¾à°•à°ªà±â€Œà°²à°¨à± à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚చడానికి సరిపోతà±à°‚ది %n రోజà±(à°²à±) పాతది)</numerusform>
+ <numerusform>(à°¬à±à°¯à°¾à°•à°ªà±â€Œà°²à°¨à± à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚చడానికి సరిపోతà±à°‚ది %n రోజà±(à°²à±) పాతది)</numerusform>
</translation>
</message>
<message>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation type="unfinished">%1 బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± à°¬à±à°²à°¾à°•à± చైనౠకాపీని డౌనà±â€Œà°²à±‹à°¡à± చేసి నిలà±à°µ చేసà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished">వాలెటౠకూడా à°ˆ డైరెకà±à°Ÿà°°à±€à°²à±‹ నిలà±à°µ చేయబడà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation type="unfinished">లోపం: పేరà±à°•à±Šà°¨à±à°¨ డేటా డైరెకà±à°Ÿà°°à±€ "%1" సృషà±à°Ÿà°¿à°‚చబడదà±.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">లోపం</translation>
</message>
- </context>
+ <message>
+ <source>Welcome</source>
+ <translation type="unfinished">à°¸à±à°µà°¾à°—తం</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation type="unfinished">%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 type="unfinished">à°ªà±à°°à±‹à°—à±à°°à°¾à°®à± à°ªà±à°°à°¾à°°à°‚భించబడటం ఇదే మొదటిసారి కాబటà±à°Ÿà°¿, %1 దాని డేటానౠఎకà±à°•à°¡ నిలà±à°µ చేయాలో మీరౠఎంచà±à°•à±‹à°µà°šà±à°šà±.</translation>
+ </message>
+ <message>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">à°¬à±à°²à°¾à°•à± చైనౠనిలà±à°µà°¨à± పరిమితం చేయండి</translation>
+ </message>
+ <message>
+ <source> GB</source>
+ <translation type="unfinished">GB</translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation type="unfinished">డిఫాలà±à°Ÿà± డేటా డైరెకà±à°Ÿà°°à±€à°¨à°¿ ఉపయోగించండి</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation type="unfinished">à°…à°¨à±à°•à±‚à°² డేటా డైరెకà±à°Ÿà°°à±€à°¨à°¿ ఉపయోగించండి:</translation>
+ </message>
+</context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation type="unfinished">సంసà±à°•à°°à°£</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished">à°—à±à°°à°¿à°‚à°šà°¿ %1</translation>
+ </message>
+ <message>
+ <source>Command-line options</source>
+ <translation type="unfinished">కమాండౠలైనౠఎంపికలà±</translation>
+ </message>
+</context>
+<context>
+ <name>ShutdownWindow</name>
+ <message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 షటౠడౌనౠఅవà±à°¤à±‹à°‚ది…</translation>
+ </message>
+ <message>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation type="unfinished">à°ˆ విండో అదృశà±à°¯à°®à°¯à±à°¯à±‡ వరకౠకంపà±à°¯à±‚à°Ÿà°°à±â€Œà°¨à± ఆపివేయవదà±à°¦à±.</translation>
+ </message>
+</context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">రూపం</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation type="unfinished">మిగిలి ఉనà±à°¨ à°¬à±à°²à°¾à°•à±â€Œà°² సంఖà±à°¯</translation>
+ </message>
+ <message>
+ <source>Unknown…</source>
+ <translation type="unfinished">తెలియని…</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">లెకà±à°•à°¿à°¸à±à°¤à±‹à°‚ది...</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">చివరి à°¬à±à°²à°¾à°•à± సమయం</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation type="unfinished">à°ªà±à°°à±‹à°—తి</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation type="unfinished">à°—à°‚à°Ÿà°•à± à°ªà±à°°à±‹à°—తి పెరà±à°—à±à°¤à±à°‚ది</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation type="unfinished">సమకాలీకరించబడే వరకౠఅంచనా సమయం మిగిలి ఉంది</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">దాచà±</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">తెలియదà±. శీరà±à°·à°¿à°•à°²à°¨à± సమకాలీకరించడం (%1, %2%)...</translation>
+ </message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">తెలియదà±. à°®à±à°‚దసà±à°¤à± సమకాలీకరణ శీరà±à°·à°¿à°•à°²à± (%1, %2%)...</translation>
+ </message>
+</context>
+<context>
+ <name>OpenURIDialog</name>
+ <message>
+ <source>Open bitcoin URI</source>
+ <translation type="unfinished">బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± URIని తెరవండి</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
+ <translation type="unfinished">à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à± à°¨à±à°‚à°¡à°¿ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± అతికించండి</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
+ <source>Options</source>
+ <translation type="unfinished">ఎంపికలà±</translation>
+ </message>
+ <message>
+ <source>&amp;Main</source>
+ <translation type="unfinished">&amp;à°ªà±à°°à°§à°¾à°¨</translation>
+ </message>
+ <message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation type="unfinished">సిసà±à°Ÿà°®à±â€Œà°•à± లాగినౠఅయిన తరà±à°µà°¾à°¤ à°¸à±à°µà°¯à°‚చాలకంగా "%1" ని à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation type="unfinished">సిసà±à°Ÿà°®à± లాగినà±â€Œà°²à±‹ "%1" ని &amp;à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Size of &amp;database cache</source>
+ <translation type="unfinished">డేటాబేసౠకాషౠయొకà±à°• పరిమాణం</translation>
+ </message>
+ <message>
+ <source>Number of script &amp;verification threads</source>
+ <translation type="unfinished">à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± &amp; ధృవీకరణ à°¥à±à°°à±†à°¡à±â€Œà°² సంఖà±à°¯</translation>
+ </message>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation type="unfinished">à°ªà±à°°à°¾à°•à±à°¸à±€ యొకà±à°• IP à°šà°¿à°°à±à°¨à°¾à°®à°¾ (ఉదా. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
+ </message>
+ <message>
+ <source>Open Configuration File</source>
+ <translation type="unfinished">కానà±à°«à°¿à°—రేషనౠఫైలà±â€Œà°¨à°¿ తెరవండి</translation>
+ </message>
+ <message>
+ <source>Reset all client options to default.</source>
+ <translation type="unfinished">à°…à°¨à±à°¨à°¿ à°•à±à°²à°¯à°¿à°‚టౠఎంపికలనౠడిఫాలà±à°Ÿà±â€Œà°—à°¾ రీసెటౠచేయండి.</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation type="unfinished">&amp;రీసెటౠఎంపికలà±</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation type="unfinished">&amp;నెటà±â€Œà°µà°°à±à°•à±</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation type="unfinished">à°¸à±à°Ÿà±‹à°°à±‡à°œà±â€Œà°¨à± à°•à°¤à±à°¤à°¿à°°à°¿à°‚à°šà± &amp; à°¬à±à°²à°¾à°•à± చేయండి</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">à°ˆ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°¨à°¿ తిరిగి మారà±à°šà°¡à°¾à°¨à°¿à°•à°¿ మొతà±à°¤à°‚ à°¬à±à°²à°¾à°•à±â€Œà°šà±†à°¯à°¿à°¨à±â€Œà°¨à± మళà±à°²à±€ డౌనà±â€Œà°²à±‹à°¡à± చేయడం అవసరం.</translation>
+ </message>
+ <message>
+ <source>(0 = auto, &lt;0 = leave that many cores free)</source>
+ <translation type="unfinished">(0 = ఆటో, &lt;0 = చాలా కోరà±à°²à°¨à± ఉచితంగా వదిలివేయండి)</translation>
+ </message>
+ <message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">కమాండà±-లైనౠమరియౠJSON-RPC ఆదేశాల à°¦à±à°µà°¾à°°à°¾ నోడà±â€Œà°¤à±‹ à°•à°®à±à°¯à±‚నికేటౠచేయడానికి ఇది మిమà±à°®à°²à±à°¨à°¿ లేదా మూడవ పకà±à°·à°‚ సాధనానà±à°¨à°¿ à°…à°¨à±à°®à°¤à°¿à°¸à±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">R&amp;PC సరà±à°µà°°à±â€Œà°¨à°¿ à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>W&amp;allet</source>
+ <translation type="unfinished">వా&amp;లెటà±</translation>
+ </message>
+ <message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">డిఫాలà±à°Ÿà±â€Œà°—à°¾ మొతà±à°¤à°‚ à°¨à±à°‚à°¡à°¿ à°°à±à°¸à±à°®à±à°¨à± తీసివేయాలా లేదా అని సెటౠచేయాలా.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">డిఫాలà±à°Ÿà±â€Œà°—à°¾ మొతà±à°¤à°‚ à°¨à±à°‚à°¡à°¿ &amp;ఫీజà±à°¨à± తీసివేయండి</translation>
+ </message>
+ <message>
+ <source>Expert</source>
+ <translation type="unfinished">నిపà±à°£à±à°¡à±</translation>
+ </message>
+ <message>
+ <source>Enable coin &amp;control features</source>
+ <translation type="unfinished">నాణెం &amp;నియంతà±à°°à°£ లకà±à°·à°£à°¾à°²à°¨à± à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>&amp;Spend unconfirmed change</source>
+ <translation type="unfinished">&amp;ధృవీకరించబడని మారà±à°ªà±à°¨à± à°–à°°à±à°šà± చేయండి</translation>
+ </message>
+ <message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">&amp;PSBT నియంతà±à°°à°£à°²à°¨à± à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">PSBT నియంతà±à°°à°£à°²à°¨à± చూపాలా వదà±à°¦à°¾.</translation>
+ </message>
+ <message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">బాహà±à°¯ సంతకం (ఉదా. హారà±à°¡à±â€Œà°µà±‡à°°à± వాలెటà±)</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;బాహà±à°¯ సంతకం à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± మారà±à°—à°‚</translation>
+ </message>
+ <message>
+ <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished">బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± కోరౠఅనà±à°•à±‚à°² à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà±â€Œà°•à°¿ పూరà±à°¤à°¿ మారà±à°—à°‚ (ఉదా. C:\Downloads\hwi.exe లేదా /Users/you/Downloads/hwi.py). జాగà±à°°à°¤à±à°¤: మాలà±à°µà±‡à°°à± మీ నాణేలనౠదొంగిలించగలదà±!</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 type="unfinished">రౌటరà±â€Œà°²à±‹ బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± à°•à±à°²à°¯à°¿à°‚టౠపోరà±à°Ÿà±â€Œà°¨à± à°¸à±à°µà°¯à°‚చాలకంగా తెరవండి. ఇది మీ రూటరౠUPnPà°•à°¿ మదà±à°¦à°¤à± ఇచà±à°šà°¿à°¨à°ªà±à°ªà±à°¡à± మరియౠఅది à°ªà±à°°à°¾à°°à°‚భించబడినపà±à°ªà±à°¡à± మాతà±à°°à°®à±‡ పని చేసà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>Map port using &amp;UPnP</source>
+ <translation type="unfinished">&amp;UPnPని ఉపయోగించి à°®à±à°¯à°¾à°ªà± పోరà±à°Ÿà±</translation>
+ </message>
+ <message>
+ <source>Map port using NA&amp;T-PMP</source>
+ <translation type="unfinished">NA&amp;T-PMPని ఉపయోగించి à°®à±à°¯à°¾à°ªà± పోరà±à°Ÿà±</translation>
+ </message>
+ <message>
+ <source>Accept connections from outside.</source>
+ <translation type="unfinished">బయటి à°¨à±à°‚à°¡à°¿ కనెకà±à°·à°¨à±à°²à°¨à± అంగీకరించండి.</translation>
+ </message>
+ <message>
+ <source>Allow incomin&amp;g connections</source>
+ <translation type="unfinished">ఇనà±â€Œà°•à°®à°¿à°‚&amp;g కనెకà±à°·à°¨à±â€Œà°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
+ <translation type="unfinished">SOCKS5 à°ªà±à°°à°¾à°•à±à°¸à±€ à°¦à±à°µà°¾à°°à°¾ బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± నెటà±â€Œà°µà°°à±à°•à±â€Œà°•à± కనెకà±à°Ÿà± చేయండి.</translation>
+ </message>
+ <message>
+ <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
+ <translation type="unfinished">&amp;SOCKS5 à°ªà±à°°à°¾à°•à±à°¸à±€ à°¦à±à°µà°¾à°°à°¾ కనెకà±à°Ÿà± చేయండి (డిఫాలà±à°Ÿà± à°ªà±à°°à°¾à°•à±à°¸à±€):</translation>
+ </message>
+ <message>
+ <source>Proxy &amp;IP:</source>
+ <translation type="unfinished">à°ªà±à°°à°¾à°•à±à°¸à±€ &amp;IP:</translation>
+ </message>
+ <message>
+ <source>&amp;Port:</source>
+ <translation type="unfinished">&amp;పోరà±à°Ÿà±:</translation>
+ </message>
+ <message>
+ <source>Port of the proxy (e.g. 9050)</source>
+ <translation type="unfinished">à°ªà±à°°à°¾à°•à±à°¸à±€ పోరà±à°Ÿà± (ఉదా. 9050)</translation>
+ </message>
+ <message>
+ <source>Used for reaching peers via:</source>
+ <translation type="unfinished">దీని à°¦à±à°µà°¾à°°à°¾ సహచరà±à°²à°¨à± చేరà±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ ఉపయోగించబడà±à°¤à±à°‚ది:</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;విండో</translation>
+ </message>
+ <message>
+ <source>Show the icon in the system tray.</source>
+ <translation type="unfinished">సిసà±à°Ÿà°®à± à°Ÿà±à°°à±‡à°²à±‹ à°šà°¿à°¹à±à°¨à°¾à°¨à±à°¨à°¿ చూపించà±.</translation>
+ </message>
+ <message>
+ <source>&amp;Show tray icon</source>
+ <translation type="unfinished">&amp;à°Ÿà±à°°à±‡ à°šà°¿à°¹à±à°¨à°¾à°¨à±à°¨à°¿ చూపà±</translation>
+ </message>
+ <message>
+ <source>Show only a tray icon after minimizing the window.</source>
+ <translation type="unfinished">విండోనౠకనిషà±à°Ÿà±€à°•à°°à°¿à°‚à°šà°¿à°¨ తరà±à°µà°¾à°¤ à°Ÿà±à°°à±‡ à°šà°¿à°¹à±à°¨à°¾à°¨à±à°¨à°¿ మాతà±à°°à°®à±‡ చూపించà±.</translation>
+ </message>
+ <message>
+ <source>&amp;Minimize to the tray instead of the taskbar</source>
+ <translation type="unfinished">&amp;టాసà±à°•à±â€Œà°¬à°¾à°°à±â€Œà°•à± బదà±à°²à±à°—à°¾ à°Ÿà±à°°à±‡à°•à°¿ కనిషà±à°Ÿà±€à°•à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>M&amp;inimize on close</source>
+ <translation type="unfinished">à°¦&amp;à°—à±à°—à°°à°—à°¾ కనిషà±à°Ÿà±€à°•à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>&amp;Display</source>
+ <translation type="unfinished">&amp;à°ªà±à°°à°¦à°°à±à°¶à°¨</translation>
+ </message>
+ <message>
+ <source>User Interface &amp;language:</source>
+ <translation type="unfinished">వినియోగదారౠఇంటరà±â€Œà°«à±‡à°¸à± &amp;భాష:</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation type="unfinished">వినియోగదారౠఇంటరà±â€Œà°«à±‡à°¸à± భాషనౠఇకà±à°•à°¡ సెటౠచేయవచà±à°šà±. %1 ని à°ªà±à°¨à°ƒà°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°¿à°¨ తరà±à°µà°¾à°¤ à°ˆ సెటà±à°Ÿà°¿à°‚à°—à± à°ªà±à°°à°­à°¾à°µà°‚ చూపà±à°¤à±à°‚ది.</translation>
+ </message>
+ <message>
+ <source>&amp;Unit to show amounts in:</source>
+ <translation type="unfinished">&amp;యూనిటà±â€Œà°²à±‹ మొతà±à°¤à°¾à°²à°¨à± చూపడానికి:</translation>
+ </message>
+ <message>
+ <source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
+ <translation type="unfinished">ఇంటరà±â€Œà°«à±‡à°¸à±â€Œà°²à±‹ మరియౠనాణేలనౠపంపేటపà±à°ªà±à°¡à± చూపించడానికి డిఫాలà±à°Ÿà± సబà±â€Œà°¡à°¿à°µà°¿à°œà°¨à± యూనిటà±â€Œà°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;మూడవ పకà±à°·à°‚ లావాదేవీ URLà°²à±</translation>
+ </message>
+ <message>
+ <source>Whether to show coin control features or not.</source>
+ <translation type="unfinished">కాయినౠకంటà±à°°à±‹à°²à± ఫీచరà±â€Œà°²à°¨à± చూపించాలా వదà±à°¦à°¾.</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
+ <translation type="unfinished">Tor onion సేవల కోసం à°ªà±à°°à°¤à±à°¯à±‡à°• SOCKS5 à°ªà±à°°à°¾à°•à±à°¸à±€ à°¦à±à°µà°¾à°°à°¾ బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± నెటà±â€Œà°µà°°à±à°•à±â€Œà°•à± కనెకà±à°Ÿà± చేయండి.</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
+ <translation type="unfinished">Tor onion సేవల à°¦à±à°µà°¾à°°à°¾ సహచరà±à°²à°¨à± చేరà±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°¤à±à°¯à±‡à°• SOCKS&amp;5 à°ªà±à°°à°¾à°•à±à°¸à±€à°¨à°¿ ఉపయోగించండి:</translation>
+ </message>
+ <message>
+ <source>Monospaced font in the Overview tab:</source>
+ <translation type="unfinished">ఓవరà±â€Œà°µà±à°¯à±‚ à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à±‹ మోనోసà±à°ªà±‡à°¸à±à°¡à± ఫాంటà±:</translation>
+ </message>
+ <message>
+ <source>embedded "%1"</source>
+ <translation type="unfinished">పొందà±à°ªà°°à°¿à°šà°¾à°°à± "%1"</translation>
+ </message>
+ <message>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">సనà±à°¨à°¿à°¹à°¿à°¤ సరిపోలిక "%1"</translation>
+ </message>
+ <message>
+ <source>&amp;OK</source>
+ <translation type="unfinished">&amp;అలాగే</translation>
+ </message>
+ <message>
+ <source>&amp;Cancel</source>
+ <translation type="unfinished">&amp;à°°à°¦à±à°¦à± చేయండి</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">బాహà±à°¯ సంతకం మదà±à°¦à°¤à± లేకà±à°‚à°¡à°¾ సంకలనం చేయబడింది (బాహà±à°¯ సంతకం కోసం అవసరం)</translation>
+ </message>
+ <message>
+ <source>default</source>
+ <translation type="unfinished">డిఫాలà±à°Ÿà±</translation>
+ </message>
+ <message>
+ <source>none</source>
+ <translation type="unfinished">à°à°¦à±€ లేదà±</translation>
+ </message>
+ <message>
+ <source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
+ <translation type="unfinished">ఎంపికల రీసెటà±â€Œà°¨à°¿ నిరà±à°§à°¾à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
+ </message>
+ <message>
+ <source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
+ <translation type="unfinished">మారà±à°ªà±à°²à°¨à± సకà±à°°à°¿à°¯à°‚ చేయడానికి à°•à±à°²à°¯à°¿à°‚à°Ÿà± à°ªà±à°¨à°ƒà°ªà±à°°à°¾à°°à°‚భించాలà±à°¸à°¿à°¨ అవసరం ఉంది.</translation>
+ </message>
+ <message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">à°ªà±à°°à°¸à±à°¤à±à°¤ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à± "%1" వదà±à°¦ à°¬à±à°¯à°¾à°•à°ªà± చేయబడతాయి.</translation>
+ </message>
+ <message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
+ <translation type="unfinished">à°•à±à°²à°¯à°¿à°‚టౠమూసివేయబడà±à°¤à±à°‚ది. మీరౠకొనసాగించాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
+ </message>
+ <message>
+ <source>Configuration options</source>
+ <extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
+ <translation type="unfinished">కానà±à°«à°¿à°—రేషనౠఎంపికలà±</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>
+ <extracomment>Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</extracomment>
+ <translation type="unfinished">GUI సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± à°­à°°à±à°¤à±€ చేసే à°…à°§à±à°¨à°¾à°¤à°¨ వినియోగదారౠఎంపికలనౠపేరà±à°•à±Šà°¨à°¡à°¾à°¨à°¿à°•à°¿ కానà±à°«à°¿à°—రేషనౠఫైలౠఉపయోగించబడà±à°¤à±à°‚ది. అదనంగా, à°à°¦à±ˆà°¨à°¾ కమాండà±-లైనౠఎంపికలౠఈ కానà±à°«à°¿à°—రేషనౠఫైలà±â€Œà°¨à± à°­à°°à±à°¤à±€ చేసà±à°¤à°¾à°¯à°¿.</translation>
+ </message>
+ <message>
+ <source>Continue</source>
+ <translation type="unfinished">కొనసాగించà±</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">à°°à°¦à±à°¦à± చేయండి</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">లోపం</translation>
</message>
- </context>
+ <message>
+ <source>The configuration file could not be opened.</source>
+ <translation type="unfinished">కానà±à°«à°¿à°—రేషనౠఫైలౠతెరవబడలేదà±.</translation>
+ </message>
+ <message>
+ <source>This change would require a client restart.</source>
+ <translation type="unfinished">à°ˆ మారà±à°ªà±à°•à± à°•à±à°²à°¯à°¿à°‚à°Ÿà± à°ªà±à°¨à°ƒà°ªà±à°°à°¾à°°à°‚à°­à°‚ అవసరం.</translation>
+ </message>
+ <message>
+ <source>The supplied proxy address is invalid.</source>
+ <translation type="unfinished">సరఫరా చేయబడిన à°ªà±à°°à°¾à°•à±à°¸à±€ à°šà°¿à°°à±à°¨à°¾à°®à°¾ చెలà±à°²à°¦à±.</translation>
+ </message>
+</context>
+<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">సెటà±à°Ÿà°¿à°‚à°—à± "%1", %2 చదవడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±, .</translation>
+ </message>
+</context>
+<context>
+ <name>OverviewPage</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">రూపం</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 type="unfinished">à°ªà±à°°à°¦à°°à±à°¶à°¿à°‚చబడిన సమాచారం పాతది కావచà±à°šà±. కనెకà±à°·à°¨à± à°¸à±à°¥à°¾à°ªà°¿à°‚చబడిన తరà±à°µà°¾à°¤ మీ వాలెటౠసà±à°µà°¯à°‚చాలకంగా బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± నెటà±â€Œà°µà°°à±à°•à±â€Œà°¤à±‹ సమకాలీకరించబడà±à°¤à±à°‚ది, కానీ à°ˆ à°ªà±à°°à°•à±à°°à°¿à°¯ ఇంకా పూరà±à°¤à°¿ కాలేదà±.</translation>
+ </message>
+ <message>
+ <source>Watch-only:</source>
+ <translation type="unfinished">చూడటానికి మాతà±à°°à°®à±‡:</translation>
+ </message>
+ <message>
+ <source>Available:</source>
+ <translation type="unfinished">à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ ఉంది:</translation>
+ </message>
+ <message>
+ <source>Your current spendable balance</source>
+ <translation type="unfinished">మీ à°ªà±à°°à°¸à±à°¤à±à°¤ à°–à°°à±à°šà± చేయదగిన à°¬à±à°¯à°¾à°²à±†à°¨à±à°¸à±</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation type="unfinished">పెండింగà±â€Œà°²à±‹ ఉంది:</translation>
+ </message>
+ <message>
+ <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
+ <translation type="unfinished">ఇంకా ధృవీకరించబడని లావాదేవీల మొతà±à°¤à°‚ మరియౠఇంకా à°–à°°à±à°šà± చేయదగిన à°¬à±à°¯à°¾à°²à±†à°¨à±à°¸à±â€Œà°²à±‹ లెకà±à°•à°¿à°‚చబడదà±</translation>
+ </message>
+ <message>
+ <source>Immature:</source>
+ <translation type="unfinished">పరిపకà±à°µà°¤ లేని:</translation>
+ </message>
+ <message>
+ <source>Mined balance that has not yet matured</source>
+ <translation type="unfinished">ఇంకా పరిపకà±à°µà°‚ చెందని సంతà±à°²à°¨à°‚ తవà±à°µà°¬à°¡à°¿à°‚ది</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation type="unfinished">à°¬à±à°¯à°¾à°²à±†à°¨à±à°¸à±â€Œà°²à±</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation type="unfinished">మొతà±à°¤à°‚:</translation>
+ </message>
+ <message>
+ <source>Your current total balance</source>
+ <translation type="unfinished">మీ à°ªà±à°°à°¸à±à°¤à±à°¤ మొతà±à°¤à°‚ à°¬à±à°¯à°¾à°²à±†à°¨à±à°¸à±</translation>
+ </message>
+ <message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation type="unfinished">వీకà±à°·à°£-మాతà±à°°à°®à±‡ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à°²à±‹ మీ à°ªà±à°°à°¸à±à°¤à±à°¤ à°¬à±à°¯à°¾à°²à±†à°¨à±à°¸à±</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation type="unfinished">à°–à°°à±à°šà± చేయదగినది:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation type="unfinished">ఇటీవలి లావాదేవీలà±</translation>
+ </message>
+ <message>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation type="unfinished">వీకà±à°·à°£-మాతà±à°°à°®à±‡ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à°•à± ధృవీకరించబడని లావాదేవీలà±</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation type="unfinished">ఇంకా మెచà±à°¯à±‚రౠకాని వాచà±-à°“à°¨à±à°²à±€ à°…à°¡à±à°°à°¸à±â€Œà°²à°²à±‹ మైనౠచేయబడిన à°¬à±à°¯à°¾à°²à±†à°¨à±à°¸à±</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation type="unfinished">వీకà±à°·à°£-మాతà±à°°à°®à±‡ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à°²à±‹ à°ªà±à°°à°¸à±à°¤à±à°¤ మొతà±à°¤à°‚ à°¬à±à°¯à°¾à°²à±†à°¨à±à°¸à±</translation>
+ </message>
+ <message>
+ <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
+ <translation type="unfinished">అవలోకనం à°Ÿà±à°¯à°¾à°¬à± కోసం గోపà±à°¯à°¤à°¾ మోడౠసకà±à°°à°¿à°¯à°‚ చేయబడింది. విలà±à°µà°²à°¨à± à°…à°¨à±â€Œà°®à°¾à°¸à±à°•à± చేయడానికి, సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±-&gt;మాసà±à°•à± విలà±à°µà°² ఎంపికనౠతీసివేయండి.</translation>
+ </message>
+</context>
+<context>
+ <name>PSBTOperationsDialog</name>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished">డైలాగà±</translation>
+ </message>
+ <message>
+ <source>Sign Tx</source>
+ <translation type="unfinished">లావాదేవీ పై సంతకం చేయండి</translation>
+ </message>
+ <message>
+ <source>Broadcast Tx</source>
+ <translation type="unfinished">à°ªà±à°°à°¸à°¾à°°à°‚ చేయౠలావాదేవీ</translation>
+ </message>
+ <message>
+ <source>Copy to Clipboard</source>
+ <translation type="unfinished">à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à±â€Œà°•à°¿ కాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>Save…</source>
+ <translation type="unfinished">సేవౠచేయి...</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished">మూసివేయి</translation>
+ </message>
+ <message>
+ <source>Failed to load transaction: %1</source>
+ <translation type="unfinished">లావాదేవీని లోడౠచేయడంలో విఫలమైంది: %1</translation>
+ </message>
+ <message>
+ <source>Failed to sign transaction: %1</source>
+ <translation type="unfinished">లావాదేవీపై సంతకం చేయడంలో విఫలమైంది: %1</translation>
+ </message>
+ <message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">వాలెటౠలాకౠచేయబడినపà±à°ªà±à°¡à± ఇనà±â€Œà°ªà±à°Ÿà±â€Œà°²à°ªà±ˆ సంతకం చేయలేరà±.</translation>
+ </message>
+ <message>
+ <source>Could not sign any more inputs.</source>
+ <translation type="unfinished">మరినà±à°¨à°¿ ఇనà±â€Œà°ªà±à°Ÿà±â€Œà°²à°ªà±ˆ సంతకం చేయడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±.</translation>
+ </message>
+ <message>
+ <source>Signed %1 inputs, but more signatures are still required.</source>
+ <translation type="unfinished">సంతకం చేయబడిన %1 ఇనà±â€Œà°ªà±à°Ÿà±â€Œà°²à±, కానీ మరినà±à°¨à°¿ సంతకాలౠఇంకా అవసరం.</translation>
+ </message>
+ <message>
+ <source>Signed transaction successfully. Transaction is ready to broadcast.</source>
+ <translation type="unfinished">లావాదేవీ విజయవంతంగా సంతకం చేయబడింది. లావాదేవీ à°ªà±à°°à°¸à°¾à°°à°¾à°¨à°¿à°•à°¿ సిదà±à°§à°‚à°—à°¾ ఉంది.</translation>
+ </message>
+ <message>
+ <source>Unknown error processing transaction.</source>
+ <translation type="unfinished">లావాదేవీని à°ªà±à°°à°¾à°¸à±†à°¸à± చేయడంలో తెలియని లోపం.</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast successfully! Transaction ID: %1</source>
+ <translation type="unfinished">లావాదేవీ విజయవంతంగా à°ªà±à°°à°¸à°¾à°°à°‚ చేయబడింది! లావాదేవి à°à°¡à°¿: %1</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast failed: %1</source>
+ <translation type="unfinished">లావాదేవీ à°ªà±à°°à°¸à°¾à°°à°‚ విఫలమైంది: %1</translation>
+ </message>
+ <message>
+ <source>PSBT copied to clipboard.</source>
+ <translation type="unfinished">PSBT à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à±â€Œà°•à°¿ కాపీ చేయబడింది.</translation>
+ </message>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">లావాదేవీ డేటానౠసేవౠచేయండి</translation>
+ </message>
+ <message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">పాకà±à°·à°¿à°•à°‚à°—à°¾ సంతకం చేసిన లావాదేవీ (బైనరీ)</translation>
+ </message>
+ <message>
+ <source>PSBT saved to disk.</source>
+ <translation type="unfinished">PSBT à°¡à°¿à°¸à±à°•à±â€Œà°²à±‹ సేవౠచేయబడింది.</translation>
+ </message>
+ <message>
+ <source> * Sends %1 to %2</source>
+ <translation type="unfinished">* %1 ని %2 à°•à°¿ పంపà±à°¤à±à°‚ది</translation>
+ </message>
+ <message>
+ <source>Unable to calculate transaction fee or total transaction amount.</source>
+ <translation type="unfinished">లావాదేవీ à°°à±à°¸à±à°®à± లేదా మొతà±à°¤à°‚ లావాదేవీ మొతà±à°¤à°¾à°¨à±à°¨à°¿ లెకà±à°•à°¿à°‚à°šà°¡à°‚ సాధà±à°¯à°‚ కాలేదà±.</translation>
+ </message>
+ <message>
+ <source>Pays transaction fee: </source>
+ <translation type="unfinished">లావాదేవీ à°°à±à°¸à±à°®à± చెలà±à°²à°¿à°¸à±à°¤à±à°‚ది:</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">పూరà±à°¤à°¿ మొతà±à°¤à°®à±</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">లేదా</translation>
+ </message>
+ <message>
+ <source>Transaction has %1 unsigned inputs.</source>
+ <translation type="unfinished">లావాదేవీ %1 సంతకం చేయని ఇనà±â€Œà°ªà±à°Ÿà±â€Œà°²à°¨à± కలిగి ఉంది.</translation>
+ </message>
+ <message>
+ <source>Transaction is missing some information about inputs.</source>
+ <translation type="unfinished">లావాదేవీ ఇనà±â€Œà°ªà±à°Ÿà±â€Œà°² à°—à±à°°à°¿à°‚à°šà°¿ కొంత సమాచారం లేదà±.</translation>
+ </message>
+ <message>
+ <source>Transaction still needs signature(s).</source>
+ <translation type="unfinished">లావాదేవీకి ఇంకా సంతకం(à°²à±) అవసరం.</translation>
+ </message>
+ <message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(కానీ వాలెటౠలోడౠచేయబడలేదà±.)</translation>
+ </message>
+ <message>
+ <source>(But this wallet cannot sign transactions.)</source>
+ <translation type="unfinished">(కానీ à°ˆ వాలెటౠలావాదేవీలపై సంతకం చేయదà±.)</translation>
+ </message>
+ <message>
+ <source>(But this wallet does not have the right keys.)</source>
+ <translation type="unfinished">(కానీ à°ˆ వాలెటà±â€Œà°²à±‹ సరైన కీలౠలేవà±.)</translation>
+ </message>
+ <message>
+ <source>Transaction is fully signed and ready for broadcast.</source>
+ <translation type="unfinished">లావాదేవీ పూరà±à°¤à°¿à°—à°¾ సంతకం చేయబడింది మరియౠపà±à°°à°¸à°¾à°°à°¾à°¨à°¿à°•à°¿ సిదà±à°§à°‚à°—à°¾ ఉంది.</translation>
+ </message>
+ <message>
+ <source>Transaction status is unknown.</source>
+ <translation type="unfinished">లావాదేవీ à°¸à±à°¥à°¿à°¤à°¿ తెలియదà±.</translation>
+ </message>
+</context>
+<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation type="unfinished">చెలà±à°²à°¿à°‚పౠఅభà±à°¯à°°à±à°§à°¨ లోపం</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation type="unfinished">బిటà±â€Œà°•à°¾à°¯à°¿à°¨à±â€Œà°¨à± à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°¡à°‚ సాధà±à°¯à°‚ కాదà±: à°•à±à°²à°¿à°•à±-à°Ÿà±-పే à°¹à±à°¯à°¾à°‚à°¡à±à°²à°°à±</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation type="unfinished">URI నిరà±à°µà°¹à°£</translation>
+ </message>
+ <message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation type="unfinished">'bitcoin://' చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ URI కాదà±. బదà±à°²à±à°—à°¾ 'bitcoin:' ఉపయోగించండి.</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation type="unfinished">URI à°…à°¨à±à°µà°¯à°¿à°‚చబడదà±! ఇది చెలà±à°²à°¨à°¿ బిటà±â€Œà°•à°¾à°¯à°¿à°¨à± à°šà°¿à°°à±à°¨à°¾à°®à°¾ లేదా తపà±à°ªà±à°—à°¾ రూపొందించబడిన URI పారామీటరà±â€Œà°² వలà±à°² సంభవించవచà±à°šà±.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation type="unfinished">చెలà±à°²à°¿à°‚పౠఅభà±à°¯à°°à±à°¥à°¨ ఫైలౠనిరà±à°µà°¹à°£</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
+ <source>User Agent</source>
+ <extracomment>Title of Peers Table column which contains the peer's User Agent string.</extracomment>
+ <translation type="unfinished">వినియోగదారౠà°à°œà±†à°‚à°Ÿà±</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <extracomment>Title of Peers Table column which indicates the current latency of the connection with the peer.</extracomment>
+ <translation type="unfinished">పింగà±</translation>
+ </message>
+ <message>
+ <source>Peer</source>
+ <extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
+ <translation type="unfinished">పీరà±</translation>
+ </message>
+ <message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">వయసà±à°¸à±</translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
+ <translation type="unfinished">దిశ</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment>
+ <translation type="unfinished">పంపారà±</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have received from the peer.</extracomment>
+ <translation type="unfinished">à°¸à±à°µà±€à°•à°°à°¿à°‚చబడింది</translation>
+ </message>
+ <message>
<source>Address</source>
<extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
<translation type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾</translation>
</message>
- </context>
+ <message>
+ <source>Type</source>
+ <extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment>
+ <translation type="unfinished">à°°à°•à°®à±</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment>
+ <translation type="unfinished">నెటà±â€Œà°µà°°à±à°•à±</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <extracomment>An Inbound Connection from a Peer.</extracomment>
+ <translation type="unfinished">ఇనà±â€Œà°¬à±Œà°‚à°¡à±</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <extracomment>An Outbound Connection to a Peer.</extracomment>
+ <translation type="unfinished">à°…à°µà±à°Ÿà± బౌండà±</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;à°šà°¿à°¤à±à°°à°¾à°¨à±à°¨à°¿ సేవౠచేయి...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation type="unfinished">&amp;ఇమేజౠకాపీ చేయి</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation type="unfinished">URI చాలా పొడవà±à°—à°¾ ఉంది, లేబà±à°²à± / సందేశం కోసం వచనానà±à°¨à°¿ తగà±à°—ించడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation type="unfinished">URIని QR కోడà±â€Œà°²à±‹à°•à°¿ à°Žà°¨à±â€Œà°•à±‹à°¡à± చేయడంలో లోపం.</translation>
+ </message>
+ <message>
+ <source>QR code support not available.</source>
+ <translation type="unfinished">QR కోడౠమదà±à°¦à°¤à± à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±.</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation type="unfinished">QR కోడà±â€Œà°¨à°¿ సేవౠచేయండి</translation>
+ </message>
+ <message>
+ <source>PNG Image</source>
+ <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment>
+ <translation type="unfinished">PNG à°šà°¿à°¤à±à°°à°‚</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
+ <source>N/A</source>
+ <translation type="unfinished">వరà±à°¤à°¿à°‚à°šà°¦à±</translation>
+ </message>
+ <message>
+ <source>Client version</source>
+ <translation type="unfinished">à°•à±à°²à°¯à°¿à°‚టౠవెరà±à°·à°¨à±</translation>
+ </message>
+ <message>
+ <source>&amp;Information</source>
+ <translation type="unfinished">&amp;సమాచారం</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation type="unfinished">సాధారణ</translation>
+ </message>
+ <message>
+ <source>Datadir</source>
+ <translation type="unfinished">సమాచార డైరెకà±à°Ÿà°°à±€</translation>
+ </message>
+ <message>
+ <source>To specify a non-default location of the data directory use the '%1' option.</source>
+ <translation type="unfinished">డేటా డైరెకà±à°Ÿà°°à±€ యొకà±à°• నానà±-డిఫాలà±à°Ÿà± à°¸à±à°¥à°¾à°¨à°¾à°¨à±à°¨à°¿ పేరà±à°•à±Šà°¨à°¡à°¾à°¨à°¿à°•à°¿ '%1' ఎంపికనౠఉపయోగించండి.</translation>
+ </message>
+ <message>
+ <source>Blocksdir</source>
+ <translation type="unfinished">à°¬à±à°²à°¾à°•à±à°¸à± డైరెకà±à°Ÿà°°à±€</translation>
+ </message>
+ <message>
+ <source>To specify a non-default location of the blocks directory use the '%1' option.</source>
+ <translation type="unfinished">à°¬à±à°²à°¾à°•à±à°¸à± డైరెకà±à°Ÿà°°à±€ యొకà±à°• నానà±-డిఫాలà±à°Ÿà± à°¸à±à°¥à°¾à°¨à°¾à°¨à±à°¨à°¿ పేరà±à°•à±Šà°¨à°¡à°¾à°¨à°¿à°•à°¿ '%1' ఎంపికనౠఉపయోగించండి.</translation>
+ </message>
+ <message>
+ <source>Startup time</source>
+ <translation type="unfinished">à°ªà±à°°à°¾à°°à°‚à°­ సమయం</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished">నెటà±â€Œà°µà°°à±à°•à±</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished">పేరà±</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation type="unfinished">కనెకà±à°·à°¨à±à°² సంఖà±à°¯</translation>
+ </message>
+ <message>
+ <source>Block chain</source>
+ <translation type="unfinished">à°¬à±à°²à°¾à°•à± చైనà±</translation>
+ </message>
+ <message>
+ <source>Memory Pool</source>
+ <translation type="unfinished">మెమరీ పూలà±</translation>
+ </message>
+ <message>
+ <source>Current number of transactions</source>
+ <translation type="unfinished">à°ªà±à°°à°¸à±à°¤à±à°¤ లావాదేవీల సంఖà±à°¯</translation>
+ </message>
+ <message>
+ <source>Memory usage</source>
+ <translation type="unfinished">మెమరీ వినియోగం</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation type="unfinished">(à°à°¦à±€ లేదà±)</translation>
+ </message>
+ <message>
+ <source>&amp;Reset</source>
+ <translation type="unfinished">&amp;రీసెటà±</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation type="unfinished">à°¸à±à°µà±€à°•à°°à°¿à°‚చబడింది</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation type="unfinished">పంపారà±</translation>
+ </message>
+ <message>
+ <source>&amp;Peers</source>
+ <translation type="unfinished">&amp;తోటివారి</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation type="unfinished">సహచరà±à°²à°¨à± నిషేధించారà±</translation>
+ </message>
+ <message>
+ <source>Select a peer to view detailed information.</source>
+ <translation type="unfinished">వివరణాతà±à°®à°• సమాచారానà±à°¨à°¿ వీకà±à°·à°¿à°‚చడానికి పీరà±â€Œà°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
+ </message>
+ <message>
+ <source>User Agent</source>
+ <translation type="unfinished">వినియోగదారౠà°à°œà±†à°‚à°Ÿà±</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">నోడౠవిండో</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">చివరి à°¬à±à°²à°¾à°•à± సమయం</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;కాపీ à°šà°¿à°°à±à°¨à°¾à°®à°¾</translation>
+ </message>
+ <message>
<source>To</source>
<translation type="unfinished">à°•à±</translation>
</message>
@@ -468,11 +2412,82 @@
</message>
</context>
<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>Remove the selected entries from the list</source>
+ <translation type="unfinished">జాబితా à°¨à±à°‚à°¡à°¿ à°Žà°‚à°šà±à°•à±à°¨à±à°¨ à°Žà°‚à°Ÿà±à°°à±€à°²à°¨à± తీసివేయండి</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation type="unfinished">తొలగించà±</translation>
+ </message>
+ <message>
+ <source>Copy &amp;URI</source>
+ <translation type="unfinished">కాపీ &amp;URI</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;కాపీ à°šà°¿à°°à±à°¨à°¾à°®à°¾</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">కాపీ &amp;లేబà±à°²à±</translation>
+ </message>
+ <message>
+ <source>Copy &amp;message</source>
+ <translation type="unfinished">కాపీ &amp;సందేశం</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">కాపీ &amp;అమౌంటà±</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">వాలెటà±â€Œà°¨à°¿ à°…à°¨à±â€Œà°²à°¾à°•à± చేయడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±.</translation>
+ </message>
+ <message>
+ <source>Could not generate new %1 address</source>
+ <translation type="unfinished">కొతà±à°¤ %1 à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± రూపొందించడం సాధà±à°¯à°‚ కాలేదà±</translation>
+ </message>
+</context>
+<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>Request payment to …</source>
+ <translation type="unfinished">దీనికి చెలà±à°²à°¿à°‚à°ªà±à°¨à± à°…à°­à±à°¯à°°à±à°¥à°¿à°‚చండి…</translation>
+ </message>
+ <message>
+ <source>Address:</source>
+ <translation type="unfinished">à°šà°¿à°°à±à°¨à°¾à°®à°¾:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">మొతà±à°¤à°‚:</translation>
+ </message>
+ <message>
+ <source>Label:</source>
+ <translation type="unfinished">లేబà±à°²à±:</translation>
+ </message>
+ <message>
+ <source>Message:</source>
+ <translation type="unfinished">సందేశం:</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">ధనమà±à°¨à± తీసà±à°•à±Šà°¨à°¿à°ªà±‹à°µà± సంచి</translation>
</message>
+ <message>
+ <source>Copy &amp;URI</source>
+ <translation type="unfinished">కాపీ &amp;URI</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Address</source>
+ <translation type="unfinished">కాపీ &amp;à°šà°¿à°°à±à°¨à°¾à°®à°¾Â </translation>
+ </message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;à°šà°¿à°¤à±à°°à°¾à°¨à±à°¨à°¿ సేవౠచేయి...</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -499,11 +2514,104 @@
<source>Quantity:</source>
<translation type="unfinished">పరిమాణం</translation>
</message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">బైటà±â€Œà°²à±:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">మొతà±à°¤à°‚:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">à°°à±à°¸à±à°®à±:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">à°°à±à°¸à±à°®à± తరà±à°µà°¾à°¤:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">మారà±à°šà±:</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 type="unfinished">ఫాలà±â€Œà°¬à±à°¯à°¾à°•à±â€Œà°«à±€à°¨à°¿ ఉపయోగించడం వలన లావాదేవీని పంపడం à°¦à±à°µà°¾à°°à°¾ నిరà±à°§à°¾à°°à°¿à°‚చడానికి చాలా గంటలౠలేదా రోజà±à°²à± (లేదా à°Žà°ªà±à°ªà±à°¡à±‚) పటà±à°Ÿà°µà°šà±à°šà±. మీ à°°à±à°¸à±à°®à±à°¨à± మానà±à°¯à±à°µà°²à±â€Œà°—à°¾ à°Žà°‚à°šà±à°•à±‹à°µà°¡à°¾à°¨à±à°¨à°¿ పరిగణించండి లేదా మీరౠపూరà±à°¤à°¿ గొలà±à°¸à±à°¨à± ధృవీకరించే వరకౠవేచి ఉండండి.</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">దాచà±</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">à°¦à±à°®à±à°®à±:</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">కాపీ పరిమాణం</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">కాపీ అమౌంటà±</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">à°°à±à°¸à±à°®à± కాపీ</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">à°°à±à°¸à±à°®à± తరà±à°µà°¾à°¤ కాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">బైటà±â€Œà°²à°¨à± కాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">à°¦à±à°®à±à°®à±à°¨à± కాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">మారà±à°ªà±à°¨à°¿ కాపీ చేయండి</translation>
+ </message>
+ <message>
+ <source>%1 (%2 blocks)</source>
+ <translation type="unfinished">%1 (%2 à°¬à±à°²à°¾à°•à±â€Œà°²à±)</translation>
+ </message>
+ <message>
+ <source> from wallet '%1'</source>
+ <translation type="unfinished">వాలెటౠనà±à°‚à°¡à°¿ '%1'</translation>
+ </message>
+ <message>
+ <source>%1 to '%2'</source>
+ <translation type="unfinished">%1 à°•à± '%2'</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation type="unfinished">%1 à°•à± %2</translation>
+ </message>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">లావాదేవీ డేటానౠసేవౠచేయండి</translation>
+ </message>
+ <message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">పాకà±à°·à°¿à°•à°‚à°—à°¾ సంతకం చేసిన లావాదేవీ (బైనరీ)</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">లేదా</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">పూరà±à°¤à°¿ మొతà±à°¤à°®à±</translation>
+ </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n à°¬à±à°²à°¾à°•à±(à°²)లో నిరà±à°§à°¾à°°à°£ à°ªà±à°°à°¾à°°à°‚భమవà±à°¤à±à°‚దని అంచనా వేయబడింది.</numerusform>
+ <numerusform>%n à°¬à±à°²à°¾à°•à±(à°²)లో నిరà±à°§à°¾à°°à°£ à°ªà±à°°à°¾à°°à°‚భమవà±à°¤à±à°‚దని అంచనా వేయబడింది.</numerusform>
</translation>
</message>
<message>
@@ -512,6 +2620,39 @@
</message>
</context>
<context>
+ <name>SendCoinsEntry</name>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation type="unfinished">à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à± à°¨à±à°‚à°¡à°¿ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± అతికించండి</translation>
+ </message>
+ <message>
+ <source>Message:</source>
+ <translation type="unfinished">సందేశం:</translation>
+ </message>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation type="unfinished">à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à± à°¨à±à°‚à°¡à°¿ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± అతికించండి</translation>
+ </message>
+ <message>
+ <source>Enter the message you want to sign here</source>
+ <translation type="unfinished">మీరౠసంతకం చేయాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨ సందేశానà±à°¨à°¿ ఇకà±à°•à°¡ నమోదౠచేయండి</translation>
+ </message>
+ <message>
+ <source>Signature</source>
+ <translation type="unfinished">సంతకం</translation>
+ </message>
+ </context>
+<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">à°·à°Ÿà±â€Œà°¡à±Œà°¨à± చేయడానికి q నొకà±à°•à°‚à°¡à°¿</translation>
+ </message>
+</context>
+<context>
<name>TransactionDesc</name>
<message>
<source>Status</source>
@@ -536,8 +2677,8 @@
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n మరినà±à°¨à°¿ à°¬à±à°²à°¾à°•à±(à°²à±)లో మెచà±à°¯à±‚à°°à± à°…à°µà±à°¤à±à°‚ది</numerusform>
+ <numerusform>%n మరినà±à°¨à°¿ à°¬à±à°²à°¾à°•à±(à°²à±)లో మెచà±à°¯à±‚à°°à± à°…à°µà±à°¤à±à°‚ది</numerusform>
</translation>
</message>
<message>
@@ -560,6 +2701,10 @@
<translation type="unfinished">తేదీ</translation>
</message>
<message>
+ <source>Type</source>
+ <translation type="unfinished">à°°à°•à°®à±</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">ఉలà±à°²à°¾à°•à±</translation>
</message>
@@ -571,12 +2716,37 @@
<context>
<name>TransactionView</name>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;కాపీ à°šà°¿à°°à±à°¨à°¾à°®à°¾</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">కాపీ &amp;లేబà±à°²à±</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">కాపీ &amp;అమౌంటà±</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">కామాతో వేరౠచేయబడిన ఫైలà±</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">నిరà±à°§à°¾à°°à°¿à°‚చబడినది</translation>
+ </message>
+ <message>
<source>Date</source>
<translation type="unfinished">తేదీ</translation>
</message>
<message>
+ <source>Type</source>
+ <translation type="unfinished">à°°à°•à°®à±</translation>
+ </message>
+ <message>
<source>Label</source>
- <translation type="unfinished">ఉలà±à°²à°¾à°•à±</translation>
+ <translation type="unfinished">లేబà±à°²à±</translation>
</message>
<message>
<source>Address</source>
@@ -595,7 +2765,7 @@
<name>WalletFrame</name>
<message>
<source>Create a new wallet</source>
- <translation type="unfinished">&lt;div&gt;&lt;/div&gt;</translation>
+ <translation type="unfinished">కొతà±à°¤ వాలెటà±â€Œà°¨à°¿ సృషà±à°Ÿà°¿à°‚à°šà°‚à°¡à°¿</translation>
</message>
<message>
<source>Error</source>
@@ -603,6 +2773,13 @@
</message>
</context>
<context>
+ <name>WalletModel</name>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">డిఫాలà±à°Ÿà± వాలెటà±</translation>
+ </message>
+</context>
+<context>
<name>WalletView</name>
<message>
<source>&amp;Export</source>
@@ -612,5 +2789,18 @@
<source>Export the data in the current tab to a file</source>
<translation type="unfinished">à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ ఉనà±à°¨ సమాచారానà±à°¨à°¿ ఫైలౠలోనికి à°Žà°—à±à°®à°¤à°¿ చేసà±à°•à±‹à°‚à°¡à°¿</translation>
</message>
- </context>
+ <message>
+ <source>Backup Wallet</source>
+ <translation type="unfinished">à°¬à±à°¯à°¾à°•à°ªà± వాలెటà±</translation>
+ </message>
+ <message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">వాలెటౠసమాచారం</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">à°°à°¦à±à°¦à± చేయండి</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_th.ts b/src/qt/locale/bitcoin_th.ts
index 1d7c403a4c..7def58a90d 100644
--- a/src/qt/locale/bitcoin_th.ts
+++ b/src/qt/locale/bitcoin_th.ts
@@ -3,11 +3,11 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">คลิà¸à¸‚วาเพื่อà¹à¸à¹‰à¹„ขที่อยู่หรือป้ายชื่อ</translation>
+ <translation type="unfinished">คลิà¸à¸‚วา เพื่อ à¹à¸à¹‰à¹„ข à¹à¸­à¸”เดรส หรือ เลเบล</translation>
</message>
<message>
<source>Create a new address</source>
- <translation type="unfinished">สร้างที่อยู่ใหม่</translation>
+ <translation type="unfinished">สร้าง à¹à¸­à¸”เดรส ใหม่</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 type="unfinished">คัดลอà¸à¸—ี่อยู่ที่เลือà¸à¹ƒà¸™à¸›à¸±à¸ˆà¸ˆà¸¸à¸šà¸±à¸™à¹„ปยังคลิปบอร์ดของระบบ</translation>
+ <translation type="unfinished">คัดลอภà¹à¸­à¸”เดรส ที่เลือภในปัจจุบัน ไปยัง คลิปบอร์ด ของระบบ</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -27,11 +27,11 @@
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation type="unfinished">ลบที่อยู่ที่เลือà¸à¹ƒà¸™à¸›à¸±à¸ˆà¸ˆà¸¸à¸šà¸±à¸™à¸­à¸­à¸à¸ˆà¸²à¸à¸£à¸²à¸¢à¸à¸²à¸£</translation>
+ <translation type="unfinished">ลบà¹à¸­à¸”เดรสที่เลือà¸à¹ƒà¸™à¸›à¸±à¸ˆà¸ˆà¸¸à¸šà¸±à¸™à¸­à¸­à¸à¸ˆà¸²à¸à¸£à¸²à¸¢à¸à¸²à¸£</translation>
</message>
<message>
<source>Enter address or label to search</source>
- <translation type="unfinished">ป้อนที่อยู่หรือป้ายชื่อเพื่อค้นหา</translation>
+ <translation type="unfinished">ป้อน à¹à¸­à¸”เดรส หรือ เลเบล เพื่อ ทำà¸à¸²à¸£à¸„้นหา</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
@@ -47,11 +47,11 @@
</message>
<message>
<source>Choose the address to send coins to</source>
- <translation type="unfinished">เลือà¸à¸—ี่อยู่ที่จะส่งเหรียà¸</translation>
+ <translation type="unfinished">เลือภà¹à¸­à¸”เดรส ที่จะ ส่ง คอยน์ ไป</translation>
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation type="unfinished">เลือà¸à¸—ี่อยู่ที่จะรับเหรียà¸</translation>
+ <translation type="unfinished">เลือภà¹à¸­à¸”เดรส ที่จะ รับ คอยน์</translation>
</message>
<message>
<source>C&amp;hoose</source>
@@ -59,19 +59,29 @@
</message>
<message>
<source>Sending addresses</source>
- <translation type="unfinished">ที่อยู่à¸à¸²à¸£à¸ªà¹ˆà¸‡</translation>
+ <translation type="unfinished">à¹à¸­à¸”เดรส à¸à¸²à¸£à¸ªà¹ˆà¸‡</translation>
</message>
<message>
<source>Receiving addresses</source>
- <translation type="unfinished">ที่อยู่à¸à¸²à¸£à¸£à¸±à¸š</translation>
+ <translation type="unfinished">à¹à¸­à¸”เดรส à¸à¸²à¸£à¸£à¸±à¸š</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 type="unfinished">These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'</translation>
</message>
<message>
<source>&amp;Copy Address</source>
- <translation type="unfinished">&amp;คัดลอà¸à¸—ี่อยู่</translation>
+ <translation type="unfinished">&amp;คัดลอภà¹à¸­à¸”เดรส</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation type="unfinished">&amp;คัดลอà¸à¸›à¹‰à¸²à¸¢à¸Šà¸·à¹ˆà¸­</translation>
+ <translation type="unfinished">คัดลอภ&amp;เลเบล</translation>
</message>
<message>
<source>&amp;Edit</source>
@@ -79,12 +89,17 @@
</message>
<message>
<source>Export Address List</source>
- <translation type="unfinished">ส่งออà¸à¸£à¸²à¸¢à¸à¸²à¸£à¸—ี่อยู่</translation>
+ <translation type="unfinished">ส่งออà¸à¸£à¸²à¸¢à¸à¸²à¸£à¹à¸­à¸”เดรส</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">เครื่องหมายจุลภาค (Comma) เพื่อà¹à¸¢à¸à¹„ฟล์</translation>
</message>
<message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
- <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาดขณะพยายามบันทึà¸à¸£à¸²à¸¢à¸à¸²à¸£à¸—ี่อยู่ไปยัง %1 โปรดลองอีà¸à¸„รั้ง</translation>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาดขณะพยายามบันทึà¸à¸£à¸²à¸¢à¸à¸²à¸£à¹à¸­à¸”เดรสไปยัง %1 โปรดลองอีà¸à¸„รั้ง</translation>
</message>
<message>
<source>Exporting Failed</source>
@@ -95,92 +110,140 @@
<name>AddressTableModel</name>
<message>
<source>Label</source>
- <translation type="unfinished">ป้ายชื่อ</translation>
+ <translation type="unfinished">เลเบล</translation>
</message>
<message>
<source>Address</source>
- <translation type="unfinished">ที่อยู่</translation>
+ <translation type="unfinished">à¹à¸­à¸”เดรส</translation>
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(ไม่มีป้ายชื่อ)</translation>
+ <translation type="unfinished">(ไม่มีเลเบล)</translation>
</message>
</context>
<context>
<name>AskPassphraseDialog</name>
<message>
<source>Passphrase Dialog</source>
- <translation type="unfinished">à¸à¸¥à¹ˆà¸­à¸‡à¹‚ต้ตอบวลีรหัสผ่าน</translation>
+ <translation type="unfinished">พาสเฟส ไดอะล็อà¸</translation>
</message>
<message>
<source>Enter passphrase</source>
- <translation type="unfinished">ป้อนวลีรหัสผ่าน</translation>
+ <translation type="unfinished">ป้อน พาสเฟส</translation>
</message>
<message>
<source>New passphrase</source>
- <translation type="unfinished">วลีรหัสผ่านใหม่</translation>
+ <translation type="unfinished">พาสดฟสใหม่</translation>
</message>
<message>
<source>Repeat new passphrase</source>
- <translation type="unfinished">ทำซ้ำวลีรหัสผ่านใหม่</translation>
+ <translation type="unfinished">ทำซ้ำ พาสเฟส ใหม่</translation>
</message>
<message>
<source>Show passphrase</source>
- <translation type="unfinished">à¹à¸ªà¸”งวลีรหัสผ่าน</translation>
+ <translation type="unfinished">à¹à¸ªà¸”งพาสเฟส</translation>
</message>
<message>
<source>Encrypt wallet</source>
- <translation type="unfinished">เข้ารหัสà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">เข้ารหัสวอลเล็ต</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£ นี้ ต้องà¸à¸²à¸£ วอลเล็ต พาสเฟส ของ คุณ เพื่อ ปลดล็อค วอลเล็ต</translation>
</message>
<message>
<source>Unlock wallet</source>
- <translation type="unfinished">ปลดล็อคà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">ปลดล็อควอลเล็ต</translation>
</message>
<message>
<source>Change passphrase</source>
- <translation type="unfinished">เปลี่ยนวลีรหัสผ่าน</translation>
+ <translation type="unfinished">เปลี่ยนพาสเฟส</translation>
</message>
<message>
<source>Confirm wallet encryption</source>
- <translation type="unfinished">ยืนยันà¸à¸²à¸£à¹€à¸‚้ารหัสà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">ยืนยันà¸à¸²à¸£à¹€à¸‚้ารหัสวอลเล็ต</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 type="unfinished">คำเตือน: หาภคุณ เข้ารหัส วอลเล็ต ของคุณ à¹à¸¥à¸° ทำพาสเฟส หาย , คุณ จะ สูà¸à¹€à¸ªà¸µà¸¢ &lt;b&gt;BITCOINS ทั้งหมดของคุณ&lt;/b&gt;!</translation>
</message>
<message>
<source>Are you sure you wish to encrypt your wallet?</source>
- <translation type="unfinished">คุณà¹à¸™à¹ˆà¹ƒà¸ˆà¸«à¸£à¸·à¸­à¹„ม่ว่าต้องà¸à¸²à¸£à¹€à¸‚้ารหัสà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ของคุณ?</translation>
+ <translation type="unfinished">คุณ à¹à¸™à¹ˆà¹ƒà¸ˆ หรือไม่ว่า ต้องà¸à¸²à¸£ เข้ารหัส วอลเล็ต ของคุณ?</translation>
</message>
<message>
<source>Wallet encrypted</source>
- <translation type="unfinished">เข้ารหัสบัà¸à¸Šà¸µà¹€à¸£à¸µà¸¢à¸šà¸£à¹‰à¸­à¸¢</translation>
+ <translation type="unfinished">เข้ารหัสวอลเล็ตเรียบร้อย</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase for 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 type="unfinished">ป้อน พาสเฟส ใหม่ สำหรับ วอลเล็ต&lt;br/&gt;à¸à¸£à¸¸à¸“า ใช้ พาสเฟส ของ &lt;b&gt;สิบ หรือ อัà¸à¸‚ระ สุ่ม สิบ ตัว ขึ้นไป &lt;/b&gt;, หรือ &lt;b&gt;à¹à¸›à¸” หรือ à¹à¸›à¸”คำขึ้นไป&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase for the wallet.</source>
+ <translation type="unfinished">ป้อนพาสเฟสเà¸à¹ˆà¸²à¹à¸¥à¸°à¸žà¸²à¸ªà¹€à¸Ÿà¸ªà¹ƒà¸«à¸¡à¹ˆà¸ªà¸³à¸«à¸£à¸±à¸šà¸§à¸­à¸¥à¹€à¸¥à¹‡à¸•</translation>
+ </message>
+ <message>
+ <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation type="unfinished">โปรดจำ ไว้ว่า à¸à¸²à¸£à¹€à¸‚้ารหัส วอลเล็ต ของคุณ ไม่สามารถ ปà¸à¸›à¹‰à¸­à¸‡ bitcoins ของคุณ ได้อย่างเต็มที่ จาà¸à¸à¸²à¸£ ถูà¸à¸‚โมย โดยมัลà¹à¸§à¸£à¹Œ ที่ติดไวรัส บนคอมพิวเตอร์ ของคุณ</translation>
+ </message>
+ <message>
+ <source>Wallet to be encrypted</source>
+ <translation type="unfinished">วอลเล็ตที่จะเข้ารหัส</translation>
</message>
<message>
<source>Your wallet is about to be encrypted. </source>
- <translation type="unfinished">บัà¸à¸Šà¸µà¸‚องคุณà¸à¸³à¸¥à¸±à¸‡à¸–ูà¸à¹€à¸‚้ารหัส</translation>
+ <translation type="unfinished">วอลเล็ตของคุณà¸à¸³à¸¥à¸±à¸‡à¸–ูà¸à¹€à¸‚้ารหัส</translation>
</message>
<message>
<source>Your wallet is now encrypted. </source>
- <translation type="unfinished">บัà¸à¸Šà¸µà¸‚องคุณถูà¸à¹€à¸‚้ารหัสเรียบร้อยà¹à¸¥à¹‰à¸§</translation>
+ <translation type="unfinished">วอลเล็ตของคุณถูà¸à¹€à¸‚้ารหัสเรียบร้อยà¹à¸¥à¹‰à¸§</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 type="unfinished">สำคัà¸: à¸à¸²à¸£à¸ªà¸³à¸£à¸­à¸‡à¸‚้อมูลใด ๆ à¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¸—ี่คุณได้ทำขึ้นจาà¸à¹„ฟล์วอลเล็ตของคุณควรถูà¸à¹à¸—นที่ด้วยไฟล์วอลเล็ตที่เข้ารหัสที่สร้างขึ้นใหม่ ด้วยเหตุผลด้านความปลอดภัย à¸à¸²à¸£à¸ªà¸³à¸£à¸­à¸‡à¸‚้อมูลà¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²à¸‚องไฟล์วอลเล็ตที่ไม่ได้เข้ารหัสจะไม่มีประโยชน์ทันทีที่คุณเริ่มใช้วอลเล็ตใหม่ที่เข้ารหัส</translation>
</message>
<message>
<source>Wallet encryption failed</source>
- <translation type="unfinished">à¸à¸²à¸£à¹€à¸‚้ารหัสà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ล้มเหลว</translation>
+ <translation type="unfinished">à¸à¸²à¸£à¹€à¸‚้ารหัสวอลเล็ตล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation type="unfinished">à¸à¸²à¸£à¹€à¸‚้ารหัส วอลเลต ล้มเหลว เนื่องจาภข้อผิดพลาด ภายใน วอลเล็ต ของคุณ ไม่ได้ เข้ารหัส</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">พาสเฟสที่ป้อนไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
</message>
<message>
<source>Wallet unlock failed</source>
- <translation type="unfinished">à¸à¸²à¸£à¸›à¸¥à¸”ล็อคà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ล้มเหลว</translation>
+ <translation type="unfinished">à¸à¸²à¸£à¸›à¸¥à¸”ล็อควอลเล็ตล้มเหลว</translation>
</message>
- </context>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation type="unfinished">พาสเฟส ที่ป้อน สำหรับ à¸à¸²à¸£à¸–อดรหัส วอลเล็ต ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished">เปลี่ยนพาสเฟสวอลเล็ตสำเร็จà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished">คำเตือน:à¹à¸›à¹‰à¸™à¸„ีย์ตัวอัà¸à¸©à¸£à¸žà¸´à¸¡à¸žà¹Œà¹ƒà¸«à¸à¹ˆ (Cap Lock) ถูà¸à¹€à¸›à¸´à¸”!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
<source>Banned Until</source>
- <translation type="unfinished">ห้ามจนถึง</translation>
+ <translation type="unfinished">ห้าม จนถึง</translation>
</message>
</context>
<context>
<name>BitcoinApplication</name>
<message>
- <source>Internal error</source>
- <translation type="unfinished">ข้อผิดพลาดภายใน</translation>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">ไฟล์ตั้งค่า%1 อาจเสียหายหรือไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
</message>
</context>
<context>
@@ -196,41 +259,84 @@
<translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาดร้ายà¹à¸£à¸‡à¸‚ึ้น, โปรดตรวจสอบว่าไฟล์ตั้งค่านั้นสามารถเขียนทับได้หรือลองใช้งานด้วยคำสั่ง -nosettings</translation>
</message>
<message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation type="unfinished">ข้อผิดพลาด: ข้อมูล ไดเร็à¸à¸—อรี ที่เจาะจง "%1" นั้น ไม่ มี</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">ข้อผิดพลาด: ไม่สามารถ parse configuration ไฟล์: %1.</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">ข้อผิดพลาด: %1</translation>
</message>
<message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 ยังไม่ออà¸à¸­à¸¢à¹ˆà¸²à¸‡à¸›à¸¥à¸­à¸”ภัย...</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished">ไม่ทราบ</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation type="unfinished">จำนวน</translation>
</message>
+ <message>
+ <source>Internal</source>
+ <translation type="unfinished">ภายใน</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
+ <translation type="unfinished">ขาเข้า</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment>
+ <translation type="unfinished">ขาออà¸</translation>
+ </message>
+ <message>
+ <source>Manual</source>
+ <extracomment>Peer connection type established manually through one of several methods.</extracomment>
+ <translation type="unfinished">คู่มือ</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished">ไม่มี</translation>
+ </message>
+ <message>
+ <source>%1 ms</source>
+ <translation type="unfinished">%1 มิลลิวินาที</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform>%n วินาที</numerusform>
+ <numerusform>%nวินาที</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform>%n นาที</numerusform>
+ <numerusform>%nนาที</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform>%n ชั่วโมง</numerusform>
+ <numerusform>%nชั่วโมง</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform>%n วัน</numerusform>
+ <numerusform>%nวัน</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform>%n สัปดาห์</numerusform>
+ <numerusform>%nสัปดาห์</numerusform>
</translation>
</message>
<message>
@@ -240,10 +346,26 @@
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform>%n ปี</numerusform>
+ <numerusform>%nปี</numerusform>
</translation>
</message>
- </context>
+ <message>
+ <source>%1 B</source>
+ <translation type="unfinished">%1 ไบต์</translation>
+ </message>
+ <message>
+ <source>%1 kB</source>
+ <translation type="unfinished">%1 à¸à¸´à¹‚ลไบต์</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation type="unfinished">%1 เมà¸à¸°à¹„บต์</translation>
+ </message>
+ <message>
+ <source>%1 GB</source>
+ <translation type="unfinished">%1 จิà¸à¸°à¹„บต์</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -255,18 +377,346 @@
<translation type="unfinished">ไม่สามารถเขียนข้อมูลลงบนไฟล์ตั้งค่าได้</translation>
</message>
<message>
+ <source>The %s developers</source>
+ <translation type="unfinished">%s นัà¸à¸žà¸±à¸’นา</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
+ <translation type="unfinished">ข้อผิดพลาด: ดัมพ์ไฟล์เวอร์ชัน ไม่รองรับเวอร์ชัน บิตคอยน์-วอลเล็ต รุ่นนี้รองรับไฟล์ดัมพ์เวอร์ชัน 1 เท่านั้น รับดัมพ์ไฟล์พร้อมเวอร์ชัน %s</translation>
+ </message>
+ <message>
+ <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
+ <translation type="unfinished">ข้อผิดพลาด: เลà¸à¸²à¸‹à¸µ วอลเล็ต เพียง สนับสนุน "legacy", "p2sh-segwit", à¹à¸¥à¸° "bech32" ชนิด à¹à¸­à¸”เดรส</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation type="unfinished">จำนวนเงินที่ทำธุรà¸à¸£à¸£à¸¡à¸™à¹‰à¸­à¸¢à¹€à¸à¸´à¸™à¹„ปที่จะส่งหลังจาà¸à¸«à¸±à¸à¸„่าธรรมเนียมà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation type="unfinished">%s ตั้งไว้สูงมาà¸</translation>
+ </message>
+ <message>
<source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
<translation type="unfinished">ไม่สามารถตั้ง -forcednsseed เป็น true ได้เมื่อà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า -dnsseed เป็น false</translation>
</message>
<message>
+ <source>Cannot set -peerblockfilters without -blockfilterindex.</source>
+ <translation type="unfinished">ไม่สามารถตั้งค่า -peerblockfilters โดยที่ไม่มี -blockfilterindex</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%sขอฟังความเห็นเรื่องพอร์ต%u พอร์ตนี้ถือว่า "ไม่ดี" ดังนั้นจึงไม่น่าเป็นไปได้ที่ Bitcoin Core จะเชื่อมต่อà¸à¸±à¸šà¸žà¸­à¸£à¹Œà¸•à¸™à¸µà¹‰ ดู doc/p2p-bad-ports.md สำหรับรายละเอียดà¹à¸¥à¸°à¸£à¸²à¸¢à¸à¸²à¸£à¸—ั้งหมด</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาดในà¸à¸²à¸£à¹‚หลด %s: à¸à¸³à¸¥à¸±à¸‡à¹‚หลดวอลเล็ตผู้ลงนามภายนอà¸à¹‚ดยไม่มีà¸à¸²à¸£à¸£à¸§à¸šà¸£à¸§à¸¡à¸à¸²à¸£à¸ªà¸™à¸±à¸šà¸ªà¸™à¸¸à¸™à¸œà¸¹à¹‰à¸¥à¸‡à¸™à¸²à¸¡à¸ à¸²à¸¢à¸™à¸­à¸</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">ไม่สามารถเปลี่ยนชื่อไฟล์ peers.dat ที่ไม่ถูà¸à¸•à¹‰à¸­à¸‡ โปรดย้ายหรือลบà¹à¸¥à¹‰à¸§à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง</translation>
+ </message>
+ <message>
+ <source>Could not find asmap file %s</source>
+ <translation type="unfinished">ไม่ ตรวจพบ ไฟล์ asmap %s</translation>
+ </message>
+ <message>
+ <source>Could not parse asmap file %s</source>
+ <translation type="unfinished">ไม่ สามารถ à¹à¸¢à¸ วิเคราะห์ ไฟล์ asmap %s</translation>
+ </message>
+ <message>
+ <source>Disk space is too low!</source>
+ <translation type="unfinished">พื้นที่ว่าง ดิสà¸à¹Œ เหลือ น้อย เà¸à¸´à¸™à¹„ป!</translation>
+ </message>
+ <message>
+ <source>Do you want to rebuild the block database now?</source>
+ <translation type="unfinished">คุณต้องà¸à¸²à¸£à¸²à¸£à¹‰à¸²à¸‡à¸à¸²à¸™à¸‚้อมูลบล็อà¸à¹ƒà¸«à¸¡à¹ˆà¸•à¸­à¸™à¸™à¸µà¹‰à¸«à¸£à¸·à¸­à¹„ม่?</translation>
+ </message>
+ <message>
+ <source>Done loading</source>
+ <translation type="unfinished">à¸à¸²à¸£à¹‚หลด เสร็จสิ้น</translation>
+ </message>
+ <message>
+ <source>Dump file %s does not exist.</source>
+ <translation type="unfinished"> ไม่มีไฟล์ดัมพ์ %s </translation>
+ </message>
+ <message>
+ <source>Error creating %s</source>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาด ในà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡%s</translation>
+ </message>
+ <message>
+ <source>Error initializing block database</source>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาดในà¸à¸²à¸£à¹€à¸£à¸´à¹ˆà¸¡à¸•à¹‰à¸™à¸à¸²à¸™à¸‚้อมูลบล็อà¸</translation>
+ </message>
+ <message>
+ <source>Error loading %s</source>
+ <translation type="unfinished">à¸à¸²à¸£à¹‚หลด เà¸à¸´à¸”ข้อผิดพลาด %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation type="unfinished">à¸à¸²à¸£à¹‚หลดเà¸à¸´à¸”ข้อผิดพลาด %s: Private keys สามารถปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸£à¸°à¸«à¸§à¹ˆà¸²à¸‡à¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸‚ึ้นเท่านั้น</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาดในà¸à¸²à¸£à¹‚หลด %s: วอลเล็ตเà¸à¸´à¸”ความเสียหาย</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาดในà¸à¸²à¸£à¹‚หลด %s: วอลเล็ตต้องà¸à¸²à¸£à¹€à¸§à¸­à¸£à¹Œà¸Šà¸±à¸™à¹ƒà¸«à¸¡à¹ˆà¸à¸§à¹ˆà¸² %s</translation>
+ </message>
+ <message>
+ <source>Error loading block database</source>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาด ในà¸à¸²à¸£à¹‚หลด à¸à¸²à¸™à¸‚้อมูล บล็อà¸</translation>
+ </message>
+ <message>
+ <source>Error opening block database</source>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาด ในà¸à¸²à¸£à¹€à¸›à¸´à¸” à¸à¸²à¸™à¸‚้อมูล บล็อà¸</translation>
+ </message>
+ <message>
+ <source>Error reading from database, shutting down.</source>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาด ในà¸à¸²à¸£à¸­à¹ˆà¸²à¸™ จาภà¸à¸²à¸™à¸‚้อมูล, à¸à¸³à¸¥à¸±à¸‡à¸›à¸´à¸”</translation>
+ </message>
+ <message>
+ <source>Error reading next record from wallet database</source>
+ <translation type="unfinished">เà¸à¸´à¸”ข้อผิดพลาด ในà¸à¸²à¸£à¸­à¹ˆà¸²à¸™ บันทึภถัดไป จาภà¸à¸²à¸™à¸‚้อมูล วอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Error: Couldn't create cursor into database</source>
+ <translation type="unfinished">ข้อผิดพลาด: ไม่สามารถ สร้าง เคอร์เซอร์ ใน à¸à¸²à¸™à¸‚้อมูล</translation>
+ </message>
+ <message>
+ <source>Error: Disk space is low for %s</source>
+ <translation type="unfinished">ข้อผิดพลาด: พื้นที่ ดิสà¸à¹Œ เหลือน้อย สำหรับ %s</translation>
+ </message>
+ <message>
+ <source>Error: Missing checksum</source>
+ <translation type="unfinished">ข้อผิดพลาด: ไม่มี เช็คซัม</translation>
+ </message>
+ <message>
+ <source>Error: No %s addresses available.</source>
+ <translation type="unfinished">ข้อผิดพลาด: ไม่มี %s à¹à¸­à¸”เดรสพร้อมใช้งาน</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">ข้อผิดพลาด: วอลเล็ตนี้ใช้ SQLite อยู่à¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">ข้อผิดพลาด: ไม่สามารถสำรองข้อมูลของวอลเล็ตได้</translation>
+ </message>
+ <message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">ข้อผิดพลาด: ไม่สามารถอ่านข้อมูลทั้งหมดในà¸à¸²à¸™à¸‚้อมูลได้</translation>
+ </message>
+ <message>
+ <source>Error: Unable to write record to new wallet</source>
+ <translation type="unfinished">ข้อผิดพลาด: ไม่สามารถเขียนบันทึà¸à¹„ปยังวอลเล็ตใหม่</translation>
+ </message>
+ <message>
+ <source>Failed to rescan the wallet during initialization</source>
+ <translation type="unfinished">ไม่สามารถสà¹à¸à¸™à¸§à¸­à¸¥à¹€à¸¥à¹‡à¸•à¸­à¸µà¸à¸„รั้งในระหว่างà¸à¸²à¸£à¹€à¸£à¸´à¹ˆà¸¡à¸•à¹‰à¸™</translation>
+ </message>
+ <message>
+ <source>Failed to verify database</source>
+ <translation type="unfinished">ไม่สามารถตรวจสอบà¸à¸²à¸™à¸‚้อมูล</translation>
+ </message>
+ <message>
+ <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source>
+ <translation type="unfinished">อัตราค่าธรรมเนียม (%s) ต่ำà¸à¸§à¹ˆà¸²à¸­à¸±à¸•à¸£à¸²à¸„่าธรรมเนียมขั้นต่ำที่ตั้งไว้ (%s)</translation>
+ </message>
+ <message>
+ <source>Ignoring duplicate -wallet %s.</source>
+ <translation type="unfinished">ละเว้นà¸à¸²à¸£à¸—ำซ้ำ -วอลเล็ต %s.</translation>
+ </message>
+ <message>
+ <source>Importing…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸™à¸³à¹€à¸‚้า…</translation>
+ </message>
+ <message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">ไม่พบข้อมูลที่ป้อนหรือใช้ไปà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>Insufficient funds</source>
+ <translation type="unfinished">เงินทุน ไม่เพียงพอ</translation>
+ </message>
+ <message>
+ <source>Loading P2P addresses…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¹‚หลด P2P addresses…</translation>
+ </message>
+ <message>
+ <source>Loading banlist…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¹‚หลด banlist…</translation>
+ </message>
+ <message>
+ <source>Loading block index…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¹‚หลด block index…</translation>
+ </message>
+ <message>
+ <source>Loading wallet…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¹‚หลด วอลเล็ต...</translation>
+ </message>
+ <message>
<source>Missing amount</source>
- <translation type="unfinished">จำนวนที่หายไป</translation>
+ <translation type="unfinished">จำนวน ที่หายไป</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">ไม่มีข้อมูลà¸à¸²à¸£à¹à¸à¹‰à¹„ขสำหรับà¸à¸²à¸£à¸›à¸£à¸°à¸¡à¸²à¸“ค่าขนาดธุรà¸à¸£à¸£à¸¡</translation>
</message>
<message>
<source>No addresses available</source>
- <translation type="unfinished">ไม่มีที่อยู่ที่ใช้งานได้</translation>
+ <translation type="unfinished">ไม่มี à¹à¸­à¸”เดรส ที่ใช้งานได้</translation>
</message>
- </context>
+ <message>
+ <source>Not enough file descriptors available.</source>
+ <translation type="unfinished">มีตัวอธิบายไฟล์ไม่เพียงพอ</translation>
+ </message>
+ <message>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation type="unfinished">ไม่สามารถà¸à¸³à¸«à¸™à¸”ค่าพรุนด้วยค่าลบ</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation type="unfinished">โหมดพรุนเข้าà¸à¸±à¸™à¹„ม่ได้à¸à¸±à¸š -txindex</translation>
+ </message>
+ <message>
+ <source>Rescanning…</source>
+ <translation type="unfinished">ทำà¸à¸²à¸£à¸ªà¹à¸à¸™à¸‹à¹‰à¸³â€¦</translation>
+ </message>
+ <message>
+ <source>Section [%s] is not recognized.</source>
+ <translation type="unfinished">ส่วน [%s] ไม่เป็นที่รู้จัà¸</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" does not exist</source>
+ <translation type="unfinished">Specified -walletdir "%s" ไม่มีอยู่</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is a relative path</source>
+ <translation type="unfinished">Specified -walletdir "%s" เป็นพาธสัมพัทธ์</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is not a directory</source>
+ <translation type="unfinished">Specified -walletdir "%s" ไม่ใช่ไดเร็à¸à¸—อรี</translation>
+ </message>
+ <message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation type="unfinished">ไม่มีไดเร็à¸à¸—อรีบล็อà¸à¸—ี่ระบุ "%s" </translation>
+ </message>
+ <message>
+ <source>Starting network threads…</source>
+ <translation type="unfinished">à¸à¸²à¸£à¹€à¸£à¸´à¹ˆà¸¡à¹€à¸˜à¸£à¸”เครือข่าย…</translation>
+ </message>
+ <message>
+ <source>The source code is available from %s.</source>
+ <translation type="unfinished">ซอร์สโค๊ดสามารถใช้ได้จาภ%s.</translation>
+ </message>
+ <message>
+ <source>The specified config file %s does not exist</source>
+ <translation type="unfinished">ไฟล์à¸à¸³à¸«à¸™à¸”ค่าที่ระบุ %s ไม่มีอยู่</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation type="unfinished">จำนวนธุรà¸à¸£à¸£à¸¡à¸™à¹‰à¸­à¸¢à¹€à¸à¸´à¸™à¹„ปที่จะชำระค่าธรรมเนียม</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation type="unfinished">วอลเล็ตจะหลีà¸à¹€à¸¥à¸µà¹ˆà¸¢à¸‡à¸à¸²à¸£à¸ˆà¹ˆà¸²à¸¢à¸™à¹‰à¸­à¸¢à¸à¸§à¹ˆà¸²à¸„่าธรรมเนียมรีเลย์ขั้นต่ำ</translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation type="unfinished">นี่คือซอฟต์à¹à¸§à¸£à¹Œà¸—ดลอง</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation type="unfinished">นี่คือค่าธรรมเนียมà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡à¸‚ั้นต่ำที่คุณจ่ายในทุà¸à¸˜à¸¸à¸£à¸à¸£à¸£à¸¡</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation type="unfinished">นี่คือค่าธรรมเนียมà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡à¸—ี่คุณจะจ่ายหาà¸à¸„ุณส่งธุรà¸à¸£à¸£à¸¡</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation type="unfinished">จำนวนธุรà¸à¸£à¸£à¸¡à¸™à¹‰à¸­à¸¢à¹€à¸à¸´à¸™à¹„ป</translation>
+ </message>
+ <message>
+ <source>Transaction amounts must not be negative</source>
+ <translation type="unfinished">จำนวนเงินที่ทำธุรà¸à¸£à¸£à¸¡à¸•à¹‰à¸­à¸‡à¹„ม่เป็นค่าติดลบ</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation type="unfinished">ธุรà¸à¸£à¸£à¸¡à¸¡à¸µ เชนเมมพูล ยาวเà¸à¸´à¸™à¹„ป</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation type="unfinished">ธุรà¸à¸£à¸£à¸¡à¸•à¹‰à¸­à¸‡à¸¡à¸µà¸œà¸¹à¹‰à¸£à¸±à¸šà¸­à¸¢à¹ˆà¸²à¸‡à¸™à¹‰à¸­à¸¢à¸«à¸™à¸¶à¹ˆà¸‡à¸£à¸²à¸¢</translation>
+ </message>
+ <message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸—ี่อยู่ à¹à¸•à¹ˆà¹€à¸£à¸²à¹„ม่สามารถสร้างมันขึ้นมาได้</translation>
+ </message>
+ <message>
+ <source>Transaction too large</source>
+ <translation type="unfinished">ธุรà¸à¸£à¸£à¸¡à¹ƒà¸«à¸à¹ˆà¹€à¸à¸´à¸™à¹„ป</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation type="unfinished">ไม่สามารถผูภ%s บนคอมพิวเตอร์นี้ %s อาจเนื่องมาจาà¸à¹€à¸„ยใช้à¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>Unable to create the PID file '%s': %s</source>
+ <translation type="unfinished">ไม่สามารถสร้างไฟล์ PID '%s': %s</translation>
+ </message>
+ <message>
+ <source>Unable to generate initial keys</source>
+ <translation type="unfinished">ไม่สามารถ สร้าง คีย์ เริ่มต้น</translation>
+ </message>
+ <message>
+ <source>Unable to generate keys</source>
+ <translation type="unfinished">ไม่สามารถ สร้าง คีย์</translation>
+ </message>
+ <message>
+ <source>Unable to open %s for writing</source>
+ <translation type="unfinished">ไม่สามารถเปิด %s สำหรับà¸à¸²à¸£à¹€à¸‚ียนข้อมูล</translation>
+ </message>
+ <message>
+ <source>Unknown -blockfilterindex value %s.</source>
+ <translation type="unfinished">ไม่รู้จัภ-ค่า blockfilterindex value %s</translation>
+ </message>
+ <message>
+ <source>Unknown address type '%s'</source>
+ <translation type="unfinished">ไม่รู้จัภประเภท à¹à¸­à¸”เดรส '%s'</translation>
+ </message>
+ <message>
+ <source>Unknown change type '%s'</source>
+ <translation type="unfinished">ไม่รู้จัภประเภท à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡ '%s'</translation>
+ </message>
+ <message>
+ <source>Unknown network specified in -onlynet: '%s'</source>
+ <translation type="unfinished">ไม่รู้จัภเครือข่าย ที่ระบุ ใน -onlynet: '%s'</translation>
+ </message>
+ <message>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">หมวดหมู่à¸à¸²à¸£à¸šà¸±à¸™à¸—ึà¸à¸—ี่ไม่รองรับ %s=%s</translation>
+ </message>
+ <message>
+ <source>User Agent comment (%s) contains unsafe characters.</source>
+ <translation type="unfinished">ความคิดเห็นของ User Agent (%s) มีอัà¸à¸‚ระที่ไม่ปลอดภัย</translation>
+ </message>
+ <message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸š บล็อà¸â€¦</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸š วอลเล็ต…</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation type="unfinished">ต้องเขียน Wallet ใหม่: restart %s เพื่อให้เสร็จสิ้น</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
@@ -275,23 +725,19 @@
</message>
<message>
<source>Show general overview of wallet</source>
- <translation type="unfinished">à¹à¸ªà¸”งภาพรวมทั่วไปของà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">à¹à¸ªà¸”ง ภาพรวม ทั่วไป ของ วอลเล็ต</translation>
</message>
<message>
<source>&amp;Transactions</source>
- <translation type="unfinished">&amp;ธุรà¸à¸£à¸£à¸¡</translation>
+ <translation type="unfinished">&amp;à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
</message>
<message>
<source>Browse transaction history</source>
- <translation type="unfinished">เรียà¸à¸”ูประวัติà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
- </message>
- <message>
- <source>E&amp;xit</source>
- <translation type="unfinished">&amp;ออà¸</translation>
+ <translation type="unfinished">เรียà¸à¸”ู ประวัติ à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
</message>
<message>
<source>Quit application</source>
- <translation type="unfinished">ออà¸à¸ˆà¸²à¸à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชัน</translation>
+ <translation type="unfinished">ออà¸à¸ˆà¸²à¸ à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชัน</translation>
</message>
<message>
<source>&amp;About %1</source>
@@ -299,7 +745,7 @@
</message>
<message>
<source>Show information about %1</source>
- <translation type="unfinished">à¹à¸ªà¸”งข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸š %1</translation>
+ <translation type="unfinished">à¹à¸ªà¸”ง ข้อมูล เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸š %1</translation>
</message>
<message>
<source>About &amp;Qt</source>
@@ -307,15 +753,15 @@
</message>
<message>
<source>Show information about Qt</source>
- <translation type="unfinished">à¹à¸ªà¸”งข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸š Qt</translation>
+ <translation type="unfinished">à¹à¸ªà¸”ง ข้อมูล เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸š Qt</translation>
</message>
<message>
<source>Modify configuration options for %1</source>
- <translation type="unfinished">ปรับเปลี่ยนตัวเลือà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าสำหรับ %1</translation>
+ <translation type="unfinished">ปรับเปลี่ยน ตัวเลือภà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่า สำหรับ %1</translation>
</message>
<message>
<source>Create a new wallet</source>
- <translation type="unfinished">สร้างà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">สร้าง วอลเล็ต ใหม่</translation>
</message>
<message>
<source>&amp;Minimize</source>
@@ -323,19 +769,28 @@
</message>
<message>
<source>Wallet:</source>
- <translation type="unfinished">à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์:</translation>
+ <translation type="unfinished">วอลเล็ต:</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">à¸à¸´à¸ˆà¸à¸£à¸£à¸¡ เครือข่าย ถูà¸à¸›à¸´à¸”ใช้งาน</translation>
+ </message>
+ <message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation type="unfinished">พร็อà¸à¸‹à¸µà¹ˆ ถูภ&lt;b&gt;เปิดใช้งาน&lt;/b&gt;: %1</translation>
</message>
<message>
<source>Send coins to a Bitcoin address</source>
- <translation type="unfinished">ส่งเหรียà¸à¹„ปยังที่อยู่ Bitcoin</translation>
+ <translation type="unfinished">ส่ง เหรียภไปยัง Bitcoin à¹à¸­à¸”เดรส</translation>
</message>
<message>
<source>Backup wallet to another location</source>
- <translation type="unfinished">สำรองข้อมูลà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ไปยังตำà¹à¸«à¸™à¹ˆà¸‡à¸—ี่ตั้งอื่น</translation>
+ <translation type="unfinished">à¹à¸šà¹‡à¸„อัพวอลเล็ตไปยังตำà¹à¸«à¸™à¹ˆà¸‡à¸—ี่ตั้งอื่น</translation>
</message>
<message>
<source>Change the passphrase used for wallet encryption</source>
- <translation type="unfinished">เปลี่ยนรหัสผ่านที่ใช้สำหรับà¸à¸²à¸£à¹€à¸‚้ารหัสà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¹€à¸‡à¸´à¸™</translation>
+ <translation type="unfinished">เปลี่ยน พาสเฟส ที่ใช้ สำหรับ à¸à¸²à¸£à¹€à¸‚้ารหัส วอลเล็ต</translation>
</message>
<message>
<source>&amp;Send</source>
@@ -347,39 +802,59 @@
</message>
<message>
<source>&amp;Options…</source>
- <translation type="unfinished">&amp;ตั้งค่า…</translation>
+ <translation type="unfinished">&amp;ตัวเลือà¸â€¦</translation>
</message>
<message>
<source>&amp;Encrypt Wallet…</source>
- <translation type="unfinished">&amp;เข้ารหัสà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์...</translation>
+ <translation type="unfinished">&amp;เข้ารหัส วอลเล็ต...</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">เข้ารหัสà¸à¸¸à¸à¹à¸ˆà¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§à¸—ี่เป็นของà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ของคุณ</translation>
</message>
<message>
<source>&amp;Backup Wallet…</source>
- <translation type="unfinished">&amp;สำรองข้อมูลà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์...</translation>
+ <translation type="unfinished">&amp;à¹à¸šà¹‡à¸„อัพวอลเล็ต…</translation>
</message>
<message>
<source>&amp;Change Passphrase…</source>
- <translation type="unfinished">&amp;เปลี่ยนวลีรหัสผ่าน...</translation>
+ <translation type="unfinished">&amp;เปลี่ยน พาสเฟส...</translation>
</message>
<message>
<source>Sign &amp;message…</source>
- <translation type="unfinished">&amp;เซ็นข้อความ...</translation>
+ <translation type="unfinished">เซ็น &amp;ข้อความ...</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">เซ็นชื่อด้วยข้อความ ที่เà¸à¹‡à¸š Bitcoin เพื่อà¹à¸ªà¸”งว่าท่านเป็นเจ้าของ bitcoin นี้จริง</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;ยืนยัน ข้อความ…</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">ตรวจสอบ ข้อความ เพื่อให้à¹à¸™à¹ˆà¹ƒà¸ˆà¸§à¹ˆà¸² à¸à¸²à¸£à¹€à¸‹à¹‡à¸™à¸•à¹Œà¸Šà¸·à¹ˆà¸­ ด้วยที่เà¸à¹‡à¸š Bitcoin à¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;โหลด PSBT จาภไฟล์...</translation>
</message>
<message>
<source>Open &amp;URI…</source>
- <translation type="unfinished">&amp;เปิด URI...</translation>
+ <translation type="unfinished">เปิด &amp;URI…</translation>
</message>
<message>
<source>Close Wallet…</source>
- <translation type="unfinished">ปิดà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">ปิด วอลเล็ต…</translation>
</message>
<message>
<source>Create Wallet…</source>
- <translation type="unfinished">สร้างà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ใหม่</translation>
+ <translation type="unfinished">สร้าง วอลเล็ต…</translation>
</message>
<message>
<source>Close All Wallets…</source>
- <translation type="unfinished">ปิดà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ทั้งหมด...</translation>
+ <translation type="unfinished">ปิด วอลเล็ต ทั้งหมด...</translation>
</message>
<message>
<source>&amp;File</source>
@@ -395,23 +870,43 @@
</message>
<message>
<source>Tabs toolbar</source>
- <translation type="unfinished">à¹à¸–บเครื่องมือà¹à¸—็บ</translation>
+ <translation type="unfinished">à¹à¸–บ เครื่องมือ</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸‹à¸´à¸‡à¸„์ส่วนหัว (%1%)…</translation>
</message>
<message>
<source>Synchronizing with network…</source>
- <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸‹à¸´à¸‡à¸„์ข้อมูลà¸à¸±à¸šà¸—างเครือข่าย ...</translation>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸‹à¸´à¸‡à¸„์ข้อมูล à¸à¸±à¸šà¸—าง เครือข่าย ...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸”ัชนีบล็อà¸à¸šà¸™à¸”ิสà¸à¹Œâ€¦</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸›à¸£à¸°à¸¡à¸§à¸¥à¸œà¸¥à¸šà¸¥à¹‡à¸­à¸à¸šà¸™à¸”ิสà¸à¹Œâ€¦</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸”ัชนีบล็อà¸à¹ƒà¸«à¸¡à¹ˆà¸šà¸™à¸”ิสà¸à¹Œâ€¦</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­ ไปยัง peers…</translation>
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation type="unfinished">เรียà¸à¹€à¸à¹‡à¸š à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™ (สร้าง QR codes à¹à¸¥à¸° bitcoin: URIs)</translation>
+ <translation type="unfinished">ขอà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™ (สร้างรหัส QR à¹à¸¥à¸° bitcoin: URIs)</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
- <translation type="unfinished">à¹à¸ªà¸”งรายà¸à¸²à¸£ ที่เà¸à¹‡à¸šà¹€à¸‡à¸´à¸™à¸—ี่จะส่ง bitcoin ออภà¹à¸¥à¸°à¸›à¹‰à¸²à¸¢à¸Šà¸·à¹ˆà¸­ ที่ใช้ไปà¹à¸¥à¹‰à¸§</translation>
+ <translation type="unfinished">à¹à¸ªà¸”งรายà¸à¸²à¸£à¸—ี่ใช้ในà¸à¸²à¸£à¸ªà¹ˆà¸‡à¹à¸­à¸”เดรสà¹à¸¥à¸°à¹€à¸¥à¹€à¸šà¸¥à¸—ี่ใช้à¹à¸¥à¹‰à¸§</translation>
</message>
<message>
<source>Show the list of used receiving addresses and labels</source>
- <translation type="unfinished">à¹à¸ªà¸”งรายà¸à¸²à¸£ ที่เà¸à¹‡à¸šà¹€à¸‡à¸´à¸™à¸—ี่จะรับ bitcoin เข้า à¹à¸¥à¸°à¸›à¹‰à¸²à¸¢à¸Šà¸·à¹ˆà¸­ ที่ใช้ไปà¹à¸¥à¹‰à¸§</translation>
+ <translation type="unfinished">à¹à¸ªà¸”งรายà¸à¸²à¸£à¸—ี่ได้ใช้ในà¸à¸²à¸£à¸£à¸±à¸šà¹à¸­à¸”เดรสà¹à¸¥à¸°à¹€à¸¥à¹€à¸šà¸¥</translation>
</message>
<message>
<source>&amp;Command-line options</source>
@@ -420,20 +915,24 @@
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>ประมวลผล %n บล็อà¸à¸‚องประวัติà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</numerusform>
</translation>
</message>
<message>
<source>%1 behind</source>
- <translation type="unfinished">%1 ตามหลัง</translation>
+ <translation type="unfinished">%1 เบื้องหลัง</translation>
+ </message>
+ <message>
+ <source>Catching up…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸•à¸´à¸”ตามถึงรายà¸à¸²à¸£à¸¥à¹ˆà¸²à¸ªà¸¸à¸”…</translation>
</message>
<message>
<source>Last received block was generated %1 ago.</source>
- <translation type="unfinished">บล็อà¸à¸ªà¸¸à¸”ท้ายที่ได้รับ สร้างขึ้นเมื่อ %1 มาà¹à¸¥à¹‰à¸§</translation>
+ <translation type="unfinished">บล็อà¸à¸—ี่ได้รับล่าสุดถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¸‚ึ้นเมื่อ %1 ที่à¹à¸¥à¹‰à¸§</translation>
</message>
<message>
<source>Transactions after this will not yet be visible.</source>
- <translation type="unfinished">ธุรà¸à¸£à¸£à¸¡à¸«à¸¥à¸±à¸‡à¸ˆà¸²à¸à¸™à¸µà¹‰à¸ˆà¸°à¸¢à¸±à¸‡à¹„ม่สามารถมองเห็น</translation>
+ <translation type="unfinished">ธุรà¸à¸£à¸£à¸¡à¸«à¸¥à¸±à¸‡à¸ˆà¸²à¸à¸™à¸µà¹‰à¸ˆà¸°à¸¢à¸±à¸‡à¹„ม่ปราà¸à¸à¹ƒà¸«à¹‰à¹€à¸«à¹‡à¸™</translation>
</message>
<message>
<source>Error</source>
@@ -449,7 +948,85 @@
</message>
<message>
<source>Up to date</source>
- <translation type="unfinished">ทันสมัย</translation>
+ <translation type="unfinished">ปัจจุบัน</translation>
+ </message>
+ <message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">โหลด PSBT จาà¸à¸„ลิปบอร์ด...</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">หน้าต่างโหนด</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">&amp;ที่อยู่à¸à¸²à¸£à¸ªà¹ˆà¸‡</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">&amp;ที่อยู่à¸à¸²à¸£à¸£à¸±à¸š</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <translation type="unfinished">เปิดà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ </message>
+ <message>
+ <source>Open a wallet</source>
+ <translation type="unfinished">เปิดà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ </message>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">ปิดà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ </message>
+ <message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">à¸à¸¹à¹‰à¸„ืนวอลเล็ต…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">à¸à¸¹à¹‰à¸„ืนวอลเล็ตจาà¸à¹„ฟล์สำรองข้อมูล</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">ปิด วอลเล็ต ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">&amp;ค่ามาสà¸à¹Œ</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">วอลเล็ต เริ่มต้น</translation>
+ </message>
+ <message>
+ <source>No wallets available</source>
+ <translation type="unfinished">ไม่มี วอลเล็ต ที่พร้อมใช้งาน</translation>
+ </message>
+ <message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">ข้อมูล วอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">โหลดสำรองข้อมูลวอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">à¸à¸¹à¹‰à¸„ืนวอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">ชื่อ วอลเล็ต</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;วินโดว์</translation>
</message>
<message>
<source>Zoom</source>
@@ -457,7 +1034,7 @@
</message>
<message>
<source>Main Window</source>
- <translation type="unfinished">หน้าต่างหลัà¸</translation>
+ <translation type="unfinished">วินโดว์ หลัà¸</translation>
</message>
<message>
<source>%1 client</source>
@@ -469,16 +1046,36 @@
</message>
<message>
<source>S&amp;how</source>
- <translation type="unfinished">à¹à¸ªà¸”ง</translation>
+ <translation type="unfinished">&amp;à¹à¸ªà¸”ง</translation>
</message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform>%n à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸—ี่ใช้งานได้ เพื่อเชื่อมà¸à¸±à¸šà¹€à¸„รือข่าย Bitcoin</numerusform>
+ <numerusform>%n เครือข่ายที่สามารถใช้เชื่อมต่อไปยังเครือข่ายบิตคอยน์ได้</numerusform>
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">คลิà¸à¹€à¸žà¸·à¹ˆà¸­à¸”ูà¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">à¹à¸ªà¸”ง Peers à¹à¸—็ป</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">ปิดใช้งาน à¸à¸´à¸ˆà¸à¸£à¸£à¸¡ เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">เปิดใช้งาน à¸à¸´à¸ˆà¸à¸£à¸£à¸¡ เครือข่าย</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">ข้อผิดพลาด: %1</translation>
</message>
@@ -501,61 +1098,80 @@
<message>
<source>Wallet: %1
</source>
- <translation type="unfinished">à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์: %1
+ <translation type="unfinished">วอลเล็ต: %1
</translation>
</message>
<message>
<source>Type: %1
</source>
- <translation type="unfinished">ชนิด: %1
+ <translation type="unfinished">รูปà¹à¸šà¸š: %1
</translation>
</message>
<message>
<source>Label: %1
</source>
- <translation type="unfinished">ป้ายชื่อ: %1
+ <translation type="unfinished">เลเบล: %1
</translation>
</message>
<message>
<source>Address: %1
</source>
- <translation type="unfinished">ที่อยู่: %1
+ <translation type="unfinished">à¹à¸­à¸”เดรส: %1
</translation>
</message>
<message>
<source>Sent transaction</source>
- <translation type="unfinished">รายà¸à¸²à¸£à¸—ี่ส่ง</translation>
+ <translation type="unfinished">รายà¸à¸²à¸£ ที่ส่ง</translation>
</message>
<message>
<source>Incoming transaction</source>
- <translation type="unfinished">à¸à¸²à¸£à¸—ำรายà¸à¸²à¸£à¸‚าเข้า</translation>
+ <translation type="unfinished">à¸à¸²à¸£à¸—ำรายà¸à¸²à¸£ ขาเข้า</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD key generation ถูภ&lt;b&gt;เปิดใช้งาน&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD key generation ถูภ&lt;b&gt;ปิดใช้งาน&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">คีย์ ส่วนตัว &lt;b&gt;ถูà¸à¸›à¸´à¸”ใช้งาน&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 type="unfinished">ระเป๋าเงินถูภ&lt;b&gt;เข้ารหัส&lt;/b&gt; à¹à¸¥à¸°à¹ƒà¸™à¸‚ณะนี้ &lt;b&gt;ปลดล็อคà¹à¸¥à¹‰à¸§&lt;/b&gt;</translation>
+ <translation type="unfinished">วอลเล็ต ถูภ&lt;b&gt;เข้ารหัส&lt;/b&gt; à¹à¸¥à¸° ในขณะนี้ &lt;b&gt;ปลดล็อคà¹à¸¥à¹‰à¸§&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 type="unfinished">à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¹€à¸‡à¸´à¸™à¸–ูภ&lt;b&gt;เข้ารหัส&lt;/b&gt; à¹à¸¥à¸°à¹ƒà¸™à¸›à¸±à¸ˆà¸ˆà¸¸à¸šà¸±à¸™ &lt;b&gt;ล็อค &lt;/b&gt;</translation>
+ <translation type="unfinished">วอลเล็ต ถูภ&lt;b&gt;เข้ารหัส&lt;/b&gt; à¹à¸¥à¸° ในขณะนี้ &lt;b&gt;ล็อคà¹à¸¥à¹‰à¸§ &lt;/b&gt;</translation>
</message>
<message>
<source>Original message:</source>
- <translation type="unfinished">ข้อความดั้งเดิม:</translation>
+ <translation type="unfinished">ข้อความ ดั้งเดิม:</translation>
+ </message>
+</context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">หน่วยà¹à¸ªà¸”งจำนวนเงิน คลิà¸à¹€à¸žà¸·à¹ˆà¸­à¹€à¸¥à¸·à¸­à¸à¸«à¸™à¹ˆà¸§à¸¢à¸­à¸·à¹ˆà¸™</translation>
</message>
</context>
<context>
<name>CoinControlDialog</name>
<message>
<source>Coin Selection</source>
- <translation type="unfinished">à¸à¸²à¸£à¹€à¸¥à¸·à¸­à¸à¹€à¸«à¸£à¸µà¸¢à¸</translation>
+ <translation type="unfinished">à¸à¸²à¸£à¹€à¸¥à¸·à¸­à¸à¸„อยน์</translation>
</message>
<message>
<source>Quantity:</source>
- <translation type="unfinished">จำนวน:</translation>
+ <translation type="unfinished">ปริมาณ:</translation>
</message>
<message>
<source>Bytes:</source>
- <translation type="unfinished">ไบต์:</translation>
+ <translation type="unfinished">ไบทส์:</translation>
</message>
<message>
<source>Amount:</source>
@@ -567,27 +1183,27 @@
</message>
<message>
<source>Dust:</source>
- <translation type="unfinished">เศษ:</translation>
+ <translation type="unfinished">ดัสท์:</translation>
</message>
<message>
<source>After Fee:</source>
- <translation type="unfinished">ส่วนที่เหลือจาà¸à¸„่าธรรมเนียม:</translation>
+ <translation type="unfinished">หลังค่าธรรมเนียม:</translation>
</message>
<message>
<source>Change:</source>
- <translation type="unfinished">เงินทอน:</translation>
+ <translation type="unfinished">เปลี่ยน:</translation>
</message>
<message>
<source>(un)select all</source>
- <translation type="unfinished">(ไม่)เลือà¸à¸—ั้งหมด</translation>
+ <translation type="unfinished">(un)เลือà¸à¸—ั้งหมด</translation>
</message>
<message>
<source>Tree mode</source>
- <translation type="unfinished">โหมดà¹à¸šà¸šà¸•à¹‰à¸™à¹„ม้</translation>
+ <translation type="unfinished">โหมด à¹à¸šà¸šTree</translation>
</message>
<message>
<source>List mode</source>
- <translation type="unfinished">โหมดà¹à¸šà¸šà¸£à¸²à¸¢à¸à¸²à¸£</translation>
+ <translation type="unfinished">โหมด à¹à¸šà¸šà¸£à¸²à¸¢à¸à¸²à¸£</translation>
</message>
<message>
<source>Amount</source>
@@ -595,11 +1211,11 @@
</message>
<message>
<source>Received with label</source>
- <translation type="unfinished">รับด้วยป้ายชื่อ</translation>
+ <translation type="unfinished">รับ ด้วย เลเบล</translation>
</message>
<message>
<source>Received with address</source>
- <translation type="unfinished">รับด้วยที่อยู่</translation>
+ <translation type="unfinished">รับ ด้วย à¹à¸­à¸”เดรส</translation>
</message>
<message>
<source>Date</source>
@@ -607,7 +1223,7 @@
</message>
<message>
<source>Confirmations</source>
- <translation type="unfinished">à¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™</translation>
+ <translation type="unfinished">ทำà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™</translation>
</message>
<message>
<source>Confirmed</source>
@@ -615,15 +1231,75 @@
</message>
<message>
<source>Copy amount</source>
- <translation type="unfinished">คัดลอà¸à¸ˆà¸³à¸™à¸§à¸™à¹€à¸‡à¸´à¸™</translation>
+ <translation type="unfinished">คัดลอภจำนวน</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;คัดลอภà¹à¸­à¸”เดรส</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">คัดลอภ&amp;เลเบล</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">คัดลอภ&amp;จำนวน</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">คัดล็อภ&amp;ID ธุรà¸à¸£à¸£à¸¡ à¹à¸¥à¸° ส่งออภเป็นดัชนี</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">L&amp;ock ที่ไม่ได้ใข้</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;ปลดล็อค ที่ไม่ไดใช้</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">คัดลอภปริมาณ</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">คัดลอภค่าธรรมเนียม</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">คัดลอภหลัง ค่าธรรมเนียม</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">คัดลอภbytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">คัดลอภdust</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">คัดลอภchange</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation type="unfinished">(%1 ล็อคà¹à¸¥à¹‰à¸§)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation type="unfinished">ใช่</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation type="unfinished">ไม่</translation>
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(ไม่มีป้ายชื่อ)</translation>
+ <translation type="unfinished">(ไม่มีเลเบล)</translation>
</message>
<message>
<source>change from %1 (%2)</source>
- <translation type="unfinished">เปลี่ยนจาภ%1 (%2)</translation>
+ <translation type="unfinished">เปลี่ยน จาภ%1 (%2)</translation>
</message>
<message>
<source>(change)</source>
@@ -635,7 +1311,24 @@
<message>
<source>Create Wallet</source>
<extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
- <translation type="unfinished">สร้างà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">สร้าง วอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸ªà¸£à¹‰à¸²à¸‡ วอลเล็ต &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Create wallet failed</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡ วอลเล็ต ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Create wallet warning</source>
+ <translation type="unfinished">คำเตือน à¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡ วอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">ไม่สามารถ จัดรายà¸à¸²à¸£ ผู้เซ็น</translation>
</message>
</context>
<context>
@@ -643,26 +1336,67 @@
<message>
<source>Load Wallets</source>
<extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
- <translation type="unfinished">โหลดà¸à¸£à¸°à¹€à¸›à¹‹à¸²</translation>
+ <translation type="unfinished">โหลด วอลเล็ต</translation>
</message>
<message>
<source>Loading wallets…</source>
<extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
- <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¹‚หลดà¸à¸£à¸°à¹€à¸›à¹‹à¸²...</translation>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¹‚หลด วอลเล็ต...</translation>
</message>
</context>
<context>
<name>OpenWalletActivity</name>
<message>
+ <source>Open wallet failed</source>
+ <translation type="unfinished">เปิด วอลเล็ต ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">คำเตือน à¸à¸²à¸£à¹€à¸›à¸´à¸” วอลเล็ต</translation>
+ </message>
+ <message>
<source>default wallet</source>
- <translation type="unfinished">à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์เริ่มต้น</translation>
+ <translation type="unfinished">วอลเล็ต เริ่มต้น</translation>
</message>
<message>
<source>Open Wallet</source>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">เปิดà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
</message>
- </context>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¹€à¸›à¸´à¸” วอลเล็ต &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">à¸à¸¹à¹‰à¸„ืนวอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">ทำà¸à¸²à¸£à¸à¸¹à¹‰à¸„ืนวอลเล็ต &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">à¸à¸²à¸£à¸à¸¹à¹‰à¸„ืนวอลเล็ตล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">คำเตือนà¸à¸²à¸£à¸à¸¹à¹‰à¸„ืนวอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">ข้อความà¸à¸²à¸£à¸à¸¹à¹‰à¸„ืนวอลเล็ต</translation>
+ </message>
+</context>
<context>
<name>WalletController</name>
<message>
@@ -670,131 +1404,177 @@
<translation type="unfinished">ปิดà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
</message>
<message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">คุณ à¹à¸™à¹ˆà¹ƒà¸ˆ หรือไม่ว่า ต้องà¸à¸²à¸£ ปิด วอลเล็ต &lt;i&gt;%1&lt;/i&gt;?</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
- <translation type="unfinished">ปิดà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ทั้งหมด</translation>
+ <translation type="unfinished">ปิด วอลเล็ต ทั้งหมด</translation>
</message>
<message>
<source>Are you sure you wish to close all wallets?</source>
- <translation type="unfinished">คุณà¹à¸™à¹ˆà¹ƒà¸ˆà¸«à¸£à¸·à¸­à¹„ม่ว่าต้องà¸à¸²à¸£à¸›à¸´à¸”à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ทั้งหมด?</translation>
+ <translation type="unfinished">คุณ à¹à¸™à¹ˆà¹ƒà¸ˆ หรือไม่ว่า ต้องà¸à¸²à¸£ ปิด วอลเล็ต ทั้งหมด?</translation>
</message>
</context>
<context>
<name>CreateWalletDialog</name>
<message>
<source>Create Wallet</source>
- <translation type="unfinished">สร้างà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">สร้าง วอลเล็ต</translation>
</message>
<message>
<source>Wallet Name</source>
- <translation type="unfinished">ชื่อà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">ชื่อ วอลเล็ต</translation>
</message>
<message>
<source>Wallet</source>
- <translation type="unfinished">à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¹€à¸‡à¸´à¸™</translation>
+ <translation type="unfinished">วอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
+ <translation type="unfinished">เข้ารหัส วอลเล็ต วอลเล็ต จะถูภเข้ารหัส ด้วย พาสเฟส ที่ คุณ เลือà¸</translation>
</message>
<message>
<source>Encrypt Wallet</source>
- <translation type="unfinished">เข้ารหัสà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">เข้ารหัส วอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">ตัวเลือภขั้นสูง</translation>
+ </message>
+ <message>
+ <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
+ <translation type="unfinished">Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets</translation>
</message>
<message>
<source>Disable Private Keys</source>
- <translation type="unfinished">ปิดใช้งานà¸à¸¸à¸à¹à¸ˆà¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§</translation>
+ <translation type="unfinished">ปิดใช้งาน คีย์ ส่วนตัว</translation>
+ </message>
+ <message>
+ <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
+ <translation type="unfinished">Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time</translation>
</message>
<message>
<source>Make Blank Wallet</source>
- <translation type="unfinished">สร้างà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์เปล่า</translation>
+ <translation type="unfinished">ทำ วอลเล็ต ให้ว่างเปล่า</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">ตัวอธิบาย วอลเล็ต</translation>
</message>
<message>
- <source>Create</source>
- <translation type="unfinished">สร้าง</translation>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first</translation>
</message>
</context>
<context>
<name>EditAddressDialog</name>
<message>
<source>Edit Address</source>
- <translation type="unfinished">à¹à¸à¹‰à¹„ขที่อยู่</translation>
+ <translation type="unfinished">à¹à¸à¹‰à¹„ข à¹à¸­à¸”เดรส</translation>
</message>
<message>
<source>&amp;Label</source>
- <translation type="unfinished">&amp;ป้ายชื่อ</translation>
+ <translation type="unfinished">&amp;เลเบล</translation>
</message>
<message>
<source>The label associated with this address list entry</source>
- <translation type="unfinished">รายà¸à¸²à¸£à¹à¸ªà¸”ง ป้ายชื่อที่เà¸à¸µà¹ˆà¸¢à¸§à¸‚้องà¸à¸±à¸šà¸—ี่เà¸à¹‡à¸šà¸™à¸µà¹‰</translation>
- </message>
- <message>
- <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
- <translation type="unfinished">ที่เà¸à¹‡à¸šà¸—ี่เà¸à¸µà¹ˆà¸¢à¸§à¸‚้องà¸à¸±à¸š ที่เà¸à¹‡à¸šà¸—ี่à¹à¸ªà¸”งรายà¸à¸²à¸£à¸™à¸µà¹‰ à¸à¸²à¸£à¸›à¸£à¸±à¸šà¸›à¸£à¸¸à¸‡à¸™à¸µà¹‰à¸—ำได้สำหรับ ที่เà¸à¹‡à¸šà¹€à¸‡à¸´à¸™à¸—ี่จะใช่ส่งเงิน เท่านั้น</translation>
+ <translation type="unfinished">รายà¸à¸²à¸£ à¹à¸ªà¸”ง เลเบล ที่ เà¸à¸µà¹ˆà¸¢à¸§à¸‚้องà¸à¸±à¸š ที่เà¸à¹‡à¸š นี้</translation>
</message>
<message>
<source>&amp;Address</source>
- <translation type="unfinished">&amp;ที่อยู่</translation>
+ <translation type="unfinished">&amp;à¹à¸­à¸”เดรส</translation>
</message>
<message>
<source>New sending address</source>
- <translation type="unfinished">ที่อยู่à¸à¸²à¸£à¸ªà¹ˆà¸‡à¹ƒà¸«à¸¡à¹ˆ</translation>
+ <translation type="unfinished">à¹à¸­à¸”เดรส à¸à¸²à¸£à¸ªà¹ˆà¸‡ ใหม่</translation>
</message>
<message>
<source>Edit receiving address</source>
- <translation type="unfinished">à¹à¸à¹‰à¹„ขที่อยู่à¸à¸²à¸£à¸£à¸±à¸š</translation>
+ <translation type="unfinished">à¹à¸à¹‰à¹„ข à¹à¸­à¸”เดรส à¸à¸²à¸£à¸£à¸±à¸š</translation>
</message>
<message>
<source>Edit sending address</source>
- <translation type="unfinished">à¹à¸à¹‰à¹„ขที่อยู่à¸à¸²à¸£à¸ªà¹ˆà¸‡</translation>
+ <translation type="unfinished">à¹à¸à¹‰à¹„ข à¹à¸­à¸”เดรส à¸à¸²à¸£à¸ªà¹ˆà¸‡</translation>
</message>
<message>
- <source>Could not unlock wallet.</source>
- <translation type="unfinished">ไม่สามารถปลดล็อคà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation type="unfinished">à¹à¸­à¸”เดรส ที่ป้อน "%1" เป็น Bitcoin à¹à¸­à¸”เดรส ที่ ไม่ ถูà¸à¸•à¹‰à¸­à¸‡</translation>
</message>
- </context>
-<context>
- <name>FreespaceChecker</name>
<message>
- <source>A new data directory will be created.</source>
- <translation type="unfinished">ไดเร็à¸à¸—อรี่ใหม่ที่ใช้เà¸à¹‡à¸šà¸‚้อมูลจะถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¸‚ึ้นมา</translation>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation type="unfinished">Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address</translation>
</message>
<message>
- <source>name</source>
- <translation type="unfinished">ชื่อ</translation>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation type="unfinished">The entered address "%1" is already in the address book with label "%2"</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">ไม่สามารถปลดล็อà¸à¸§à¸­à¸¥à¹€à¸¥à¹‡à¸•à¹„ด้</translation>
</message>
<message>
- <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation type="unfinished">มีไดเรà¸à¸—อรีอยู่à¹à¸¥à¹‰à¸§ เพิ่ม %1 หาà¸à¸„ุณต้องà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¹„ดเรà¸à¸—อรีใหม่ที่นี่</translation>
+ <source>New key generation failed.</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸„ีย์ใหม่ล้มเหลว</translation>
</message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
<message>
- <source>Path already exists, and is not a directory.</source>
- <translation type="unfinished">มีเส้นทางอยู่à¹à¸¥à¹‰à¸§à¹à¸¥à¸°à¹„ม่ใช่ไดเรà¸à¸—อรี</translation>
+ <source>A new data directory will be created.</source>
+ <translation type="unfinished">ไดเร็à¸à¸—อรีข้อมูลใหม่จะถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¸‚ึ้น</translation>
</message>
<message>
<source>Cannot create data directory here.</source>
- <translation type="unfinished">ไม่สามารถสร้างไดเรà¸à¸—อรีข้อมูลที่นี่</translation>
+ <translation type="unfinished">ไม่สามารถสร้างไดเร็à¸à¸—อรีข้อมูลที่นี่</translation>
</message>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>มีพื้นที่ว่าง %n GB ที่ใช้งานได้</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(ต้องà¸à¸²à¸£à¸žà¸·à¹‰à¸™à¸—ี่ %n GB )</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ </translation>
+ </message>
<message>
- <source>%1 GB of space available</source>
- <translation type="unfinished">มีพื้นที่ว่าง %1 GB ที่ใช้งานได้</translation>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation type="unfinished">At least %1 GB of data will be stored in this directory, and it will grow over time</translation>
</message>
<message>
<source>Approximately %1 GB of data will be stored in this directory.</source>
- <translation type="unfinished">ประมาณ %1 GB ของข้อมูลจะเà¸à¹‡à¸šà¹ƒà¸™à¹„ดเร็à¸à¸—อรี่</translation>
+ <translation type="unfinished">ข้อมูลประมาณ %1 GB จะถูà¸à¹€à¸à¹‡à¸šà¹„ว้ในไดเร็à¸à¸—อรีนี้</translation>
</message>
<message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
</translation>
</message>
<message>
- <source>The wallet will also be stored in this directory.</source>
- <translation type="unfinished">The wallet เà¸à¹‡à¸šà¹ƒà¸§à¹‰à¹ƒà¸™à¹„ดเร็à¸à¸—อรี่</translation>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation type="unfinished">%1 จะดาวน์โหลดà¹à¸¥à¸°à¸ˆà¸±à¸”เà¸à¹‡à¸šà¸ªà¸³à¹€à¸™à¸²à¸‚องบล็อà¸à¹€à¸Šà¸™ Bitcoin</translation>
</message>
<message>
- <source>Error: Specified data directory "%1" cannot be created.</source>
- <translation type="unfinished">ข้อผิดพลาด: ไดเร็à¸à¸—อรี่ข้อมูลที่ต้องà¸à¸²à¸£ "%1" ไม่สามารถสร้างได้</translation>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished"> วอลเล็ตจะถูà¸à¹€à¸à¹‡à¸šà¹ƒà¸§à¹‰à¹ƒà¸™à¹„ดเร็à¸à¸—อรีนี้เช่นà¸à¸±à¸™</translation>
</message>
<message>
<source>Error</source>
@@ -806,26 +1586,38 @@
</message>
<message>
<source>Welcome to %1.</source>
- <translation type="unfinished">ยินดีต้อนรับสู่ %1</translation>
+ <translation type="unfinished">ยินดีต้อนรับเข้าสู่ %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 type="unfinished">นี่เป็นà¸à¸²à¸£à¸£à¸±à¸™à¹‚ปรà¹à¸à¸£à¸¡à¸„รั้งà¹à¸£à¸ ท่านสามารถเลือภว่าจะเà¸à¹‡à¸šà¸‚้อมูลไว้ที่ %1</translation>
+ <translation type="unfinished">เนื่องจาà¸à¸™à¸µà¹ˆà¹€à¸›à¹‡à¸™à¸„รั้งà¹à¸£à¸à¸—ี่โปรà¹à¸à¸£à¸¡à¹€à¸›à¸´à¸”ตัว คุณสามารถเลือà¸à¹„ด้ว่า %1 จะเà¸à¹‡à¸šà¸‚้อมูลไว้ที่ใด</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
+ <translation type="unfinished">Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features</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 type="unfinished">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</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 type="unfinished">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>
</message>
<message>
<source>Use the default data directory</source>
- <translation type="unfinished">ใช้ไดเรà¸à¸—อรีข้อมูลเริ่มต้น</translation>
+ <translation type="unfinished">ใช้ ไดเรà¸à¸—อรี ข้อมูล เริ่มต้น</translation>
</message>
<message>
<source>Use a custom data directory:</source>
- <translation type="unfinished">ใช้ไดเรà¸à¸—อรีข้อมูลที่à¸à¸³à¸«à¸™à¸”เอง:</translation>
+ <translation type="unfinished">ใช้ ไดเรà¸à¸—อรี ข้อมูล ที่à¸à¸³à¸«à¸™à¸”เอง:</translation>
</message>
</context>
<context>
<name>HelpMessageDialog</name>
<message>
<source>version</source>
- <translation type="unfinished">รุ่น</translation>
+ <translation type="unfinished">เวอร์ชัน</translation>
</message>
<message>
<source>About %1</source>
@@ -833,85 +1625,82 @@
</message>
<message>
<source>Command-line options</source>
- <translation type="unfinished">ตัวเลือà¸à¸šà¸£à¸£à¸—ัดคำสั่ง</translation>
+ <translation type="unfinished">ตัวเลือภCommand-line </translation>
</message>
</context>
<context>
- <name>ModalOverlay</name>
+ <name>ShutdownWindow</name>
<message>
- <source>Form</source>
- <translation type="unfinished">รูป</translation>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 à¸à¸³à¸¥à¸±à¸‡à¸–ูà¸à¸›à¸´à¸”ลง…</translation>
</message>
<message>
- <source>Progress</source>
- <translation type="unfinished">ความคืบหน้า</translation>
- </message>
- <message>
- <source>Hide</source>
- <translation type="unfinished">ซ่อน</translation>
- </message>
- </context>
-<context>
- <name>OpenURIDialog</name>
- <message>
- <source>Paste address from clipboard</source>
- <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
- <translation type="unfinished">วางที่อยู่จาà¸à¸„ลิปบอร์ด</translation>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation type="unfinished">อย่าปิดเครื่องคอมพิวเตอร์จนà¸à¸§à¹ˆà¸²à¸«à¸™à¹‰à¸²à¸•à¹ˆà¸²à¸‡à¸™à¸µà¹‰à¸ˆà¸°à¸«à¸²à¸¢à¹„ป</translation>
</message>
</context>
<context>
- <name>OptionsDialog</name>
+ <name>ModalOverlay</name>
<message>
- <source>Options</source>
- <translation type="unfinished">ตัวเลือà¸</translation>
+ <source>Form</source>
+ <translation type="unfinished">รูปà¹à¸šà¸š</translation>
</message>
<message>
- <source>&amp;Main</source>
- <translation type="unfinished">&amp;หลัà¸</translation>
+ <source>Number of blocks left</source>
+ <translation type="unfinished">ตัวเลข ของ บล็อภที่เหลือ</translation>
</message>
<message>
- <source>Automatically start %1 after logging in to the system.</source>
- <translation type="unfinished">เริ่มต้นอัตโนมัติ %1 หลังจาภล็อà¸à¸­à¸´à¸™ เข้าสู่ระบบà¹à¸¥à¹‰à¸§</translation>
+ <source>Unknown…</source>
+ <translation type="unfinished">ไม่รู้จัà¸â€¦</translation>
</message>
<message>
- <source>&amp;Start %1 on system login</source>
- <translation type="unfinished">&amp;เริ่ม %1 ในà¸à¸²à¸£à¸¥à¹‡à¸­à¸à¸­à¸´à¸™à¸£à¸°à¸šà¸š</translation>
+ <source>calculating…</source>
+ <translation type="unfinished">à¸à¸³à¸¥à¸±à¸‡à¸„ำนวณ…</translation>
</message>
<message>
- <source>Size of &amp;database cache</source>
- <translation type="unfinished">ขนาดของ &amp;database cache</translation>
+ <source>Last block time</source>
+ <translation type="unfinished">บล็อà¸à¹€à¸§à¸¥à¸²à¸¥à¹ˆà¸²à¸ªà¸¸à¸”</translation>
</message>
<message>
- <source>Number of script &amp;verification threads</source>
- <translation type="unfinished">จำนวนของสคริปท์ &amp;verification threads</translation>
+ <source>Progress increase per hour</source>
+ <translation type="unfinished">ความคืบหน้าเพิ่มขึ้นต่อชั่วโมง</translation>
</message>
<message>
- <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
- <translation type="unfinished">IP à¹à¸­à¸”เดส ของ proxy (เช่น IPv4: 127.0.0.1 / IPv6: ::1)</translation>
+ <source>Estimated time left until synced</source>
+ <translation type="unfinished">เวลาโดยประมาณที่เหลือจนà¸à¸§à¹ˆà¸²à¸ˆà¸°à¸‹à¸´à¸‡à¸„์</translation>
</message>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
<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 type="unfinished">มินิไมซ์à¹à¸­à¸ž à¹à¸—นà¸à¸²à¸£à¸­à¸­à¸à¸ˆà¸²à¸à¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชั่น เมื่อวินโดว์ได้รับà¸à¸²à¸£à¸›à¸´à¸” เมื่อเลือà¸à¸•à¸±à¸§à¹€à¸¥à¸·à¸­à¸à¸™à¸µà¹‰ à¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชั่น จะถูà¸à¸›à¸´à¸” à¸à¹‡à¸•à¹ˆà¸­à¹€à¸¡à¸·à¹ˆà¸­ มีà¸à¸²à¸£à¹€à¸¥à¸·à¸­à¸à¹€à¸¡à¸™à¸¹ Exit/ออà¸à¸ˆà¸²à¸à¸£à¸°à¸šà¸š เท่านั้น</translation>
+ <source>Open bitcoin URI</source>
+ <translation type="unfinished">เปิด bitcoin: URI</translation>
</message>
+ </context>
+<context>
+ <name>OptionsDialog</name>
<message>
- <source>Open Configuration File</source>
- <translation type="unfinished">เปิดไฟล์à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่า</translation>
+ <source>Options</source>
+ <translation type="unfinished">ตัวเลือà¸</translation>
</message>
<message>
- <source>Reset all client options to default.</source>
- <translation type="unfinished">รีเซต ไคลเอ็นออพชั่น à¸à¸¥à¸±à¸šà¹„ปเป็นค่าเริ่มต้น</translation>
+ <source>&amp;Main</source>
+ <translation type="unfinished">&amp;หลัà¸</translation>
</message>
<message>
- <source>&amp;Reset Options</source>
- <translation type="unfinished">&amp;รีเซต ออพชั่น</translation>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">ขนาดà¹à¸„ชà¸à¸²à¸™à¸‚้อมูลสูงสุด à¹à¸„ชที่ใหà¸à¹ˆà¸‚ึ้นสามารถนำไปสู่à¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ได้เร็วยิ่งขึ้น หลังจาà¸à¸™à¸±à¹‰à¸™à¸›à¸£à¸°à¹‚ยชน์จะเด่นชัดน้อยลงสำหรับà¸à¸£à¸“ีà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸ªà¹ˆà¸§à¸™à¹ƒà¸«à¸à¹ˆ à¸à¸²à¸£à¸¥à¸”ขนาดà¹à¸„ชจะลดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸«à¸™à¹ˆà¸§à¸¢à¸„วามจำ มีà¸à¸²à¸£à¹à¸Šà¸£à¹Œà¸«à¸™à¹ˆà¸§à¸¢à¸„วามจำ mempool ที่ไม่ได้ใช้สำหรับà¹à¸„ชนี้</translation>
</message>
<message>
- <source>&amp;Network</source>
- <translation type="unfinished">&amp;เครือข่าย</translation>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">à¸à¸³à¸«à¸™à¸”จำนวนเธรดà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸ªà¸„ริปต์ ค่าลบสอดคล้องà¸à¸±à¸šà¸ˆà¸³à¸™à¸§à¸™à¸„อร์ที่คุณต้องà¸à¸²à¸£à¸›à¸¥à¹ˆà¸­à¸¢à¹ƒà¸«à¹‰à¸£à¸°à¸šà¸šà¸§à¹ˆà¸²à¸‡</translation>
</message>
<message>
- <source>(0 = auto, &lt;0 = leave that many cores free)</source>
- <translation type="unfinished">(0 = อัตโนมัติ, &lt;0 = ปล่อย คอร์ อิสระ)</translation>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">สิ่งนี้ช่วยให้คุณหรือเครื่องมือของบุคคลที่สามสามารถสื่อสารà¸à¸±à¸šà¹‚หนดผ่านคำสั่งบรรทัดคำสั่งà¹à¸¥à¸° JSON-RPC</translation>
</message>
<message>
<source>Enable R&amp;PC server</source>
@@ -920,23 +1709,7 @@
</message>
<message>
<source>W&amp;allet</source>
- <translation type="unfinished">&amp;à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
- </message>
- <message>
- <source>Expert</source>
- <translation type="unfinished">ผู้เชี่ยวชาà¸</translation>
- </message>
- <message>
- <source>Enable coin &amp;control features</source>
- <translation type="unfinished">เปิดใช้ coin &amp; รูปà¹à¸šà¸šà¸à¸²à¸£à¸„วบคุม</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 type="unfinished">หาà¸à¸—่านไม่เปิดใช้ à¸à¸²à¸£à¹ƒà¸Šà¹‰à¹€à¸‡à¸´à¸™à¸—อนที่ยังไม่ยืนยัน เงินทอนจาà¸à¸à¸²à¸£à¸—ำรายà¸à¸²à¸£à¸ˆà¸°à¹„ม่สามารถใช้ได้ จนà¸à¸§à¹ˆà¸²à¸£à¸²à¸¢à¸à¸²à¸£à¸—ี่ทำà¸à¸²à¸£ จะได้รับà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸«à¸™à¸¶à¹ˆà¸‡à¸„รั้ง à¹à¸¥à¸°à¸ˆà¸°à¸à¸£à¸°à¸—บà¸à¸²à¸£à¸„ำนวณยอดคงเหลือของท่านด้วย</translation>
- </message>
- <message>
- <source>&amp;Spend unconfirmed change</source>
- <translation type="unfinished">&amp;ใช้เงินทอนที่ยังไม่ยืนยัน</translation>
+ <translation type="unfinished">ว&amp;อลเล็ต</translation>
</message>
<message>
<source>Enable &amp;PSBT controls</source>
@@ -944,48 +1717,24 @@
<translation type="unfinished">เปิดใช้งานà¸à¸²à¸£à¸„วบคุม &amp;PSBT</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 type="unfinished">เปิด Bitcoin ไคล์เอ็นท์พอร์ต/client port บน router โดยอัตโนมัติ วิธีนี้ใช้ได้เมื่อ router สนับสนุน UPnP à¹à¸¥à¸°à¸ªà¸–านะเปิดใช้งาน</translation>
- </message>
- <message>
- <source>Map port using &amp;UPnP</source>
- <translation type="unfinished">จองพอร์ต โดยใช้ &amp;UPnP</translation>
- </message>
- <message>
- <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
- <translation type="unfinished">เชื่อมต่อà¸à¸±à¸š Bitcoin เน็ตเวิร์ภผ่านพร็อà¸à¸‹à¸µà¹ˆà¹à¸šà¸š SOCKS5</translation>
- </message>
- <message>
- <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
- <translation type="unfinished">&amp;เชื่อมต่อผ่าน พร็อà¸à¸‹à¸µà¹ˆ SOCKS5 (พร็อà¸à¸‹à¸µà¹ˆà¹€à¸£à¸´à¹ˆà¸¡à¸•à¹‰à¸™):</translation>
- </message>
- <message>
- <source>Proxy &amp;IP:</source>
- <translation type="unfinished">พร็อà¸à¸‹à¸µà¹ˆ &amp;IP:</translation>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">ผู้ลงนามภายนอภ(เช่น ฮาร์ดà¹à¸§à¸£à¹Œà¸§à¸­à¸¥à¹€à¸¥à¹‡à¸•)</translation>
</message>
<message>
<source>&amp;Port:</source>
- <translation type="unfinished">&amp;พอร์ต</translation>
- </message>
- <message>
- <source>Port of the proxy (e.g. 9050)</source>
- <translation type="unfinished">พอร์ตของพร็อà¸à¸‹à¸µà¹ˆ (ตัวอย่าง 9050)</translation>
- </message>
- <message>
- <source>Used for reaching peers via:</source>
- <translation type="unfinished">ใช้ในà¸à¸²à¸£à¹€à¸‚้าถึงอีà¸à¸à¹ˆà¸²à¸¢à¸«à¸™à¸¶à¹ˆà¸‡ peer โดย:</translation>
+ <translation type="unfinished">&amp;พอร์ต:</translation>
</message>
<message>
<source>&amp;Window</source>
- <translation type="unfinished">&amp;หน้าต่าง</translation>
+ <translation type="unfinished">&amp;วินโดว์</translation>
</message>
<message>
- <source>Show only a tray icon after minimizing the window.</source>
- <translation type="unfinished">à¹à¸ªà¸”งเฉพาะไอคอนถาดหลังจาà¸à¸¢à¹ˆà¸­à¸«à¸™à¹‰à¸²à¸•à¹ˆà¸²à¸‡</translation>
+ <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 type="unfinished">URL ของบุคคลที่สาม (เช่น เครื่องมือสำรวจà¸à¸²à¸£à¸šà¸¥à¹‡à¸­à¸) ที่ปราà¸à¸à¹ƒà¸™à¹à¸—็บธุรà¸à¸£à¸£à¸¡à¹€à¸›à¹‡à¸™à¸£à¸²à¸¢à¸à¸²à¸£à¹€à¸¡à¸™à¸¹à¸šà¸£à¸´à¸šà¸— %s ใน URL จะถูà¸à¹à¸—นที่ด้วยà¹à¸®à¸Šà¸˜à¸¸à¸£à¸à¸£à¸£à¸¡ URL หลายรายà¸à¸²à¸£à¸–ูà¸à¸„ั่นด้วยà¹à¸–บà¹à¸™à¸§à¸•à¸±à¹‰à¸‡ |</translation>
</message>
<message>
- <source>User Interface &amp;language:</source>
- <translation type="unfinished">&amp;ภาษาส่วนติดต่อผู้ใช้:</translation>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;URL ธุรà¸à¸£à¸£à¸¡à¸šà¸¸à¸„คลที่สาม</translation>
</message>
<message>
<source>&amp;OK</source>
@@ -996,9 +1745,8 @@
<translation type="unfinished">&amp;ยà¸à¹€à¸¥à¸´à¸</translation>
</message>
<message>
- <source>Configuration options</source>
- <extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
- <translation type="unfinished">ตัวเลือà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่า</translation>
+ <source>none</source>
+ <translation type="unfinished">ไม่มี</translation>
</message>
<message>
<source>Continue</source>
@@ -1017,68 +1765,288 @@
<name>OverviewPage</name>
<message>
<source>Form</source>
- <translation type="unfinished">รูป</translation>
+ <translation type="unfinished">รูปà¹à¸šà¸š</translation>
+ </message>
+ <message>
+ <source>Available:</source>
+ <translation type="unfinished">พร้อมใช้งาน:</translation>
</message>
<message>
<source>Balances</source>
- <translation type="unfinished">ยอดดุล</translation>
+ <translation type="unfinished">ยอดคงเหลือ</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation type="unfinished">ทั้งหมด:</translation>
+ </message>
+ <message>
+ <source>Your current total balance</source>
+ <translation type="unfinished">ยอดคงเหลือ ทั้งหมด ในปัจจุบัน ของคุณ</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation type="unfinished">ที่สามารถใช้จ่ายได้:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡ ล่าสุด</translation>
</message>
</context>
<context>
<name>PSBTOperationsDialog</name>
<message>
- <source>Copy to Clipboard</source>
- <translation type="unfinished">คัดลอà¸à¹„ปยังคลิปบอร์ด</translation>
+ <source>Save…</source>
+ <translation type="unfinished">บันทึà¸â€¦</translation>
+ </message>
+ <message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">ไม่สามารถลงนามอินพุตในขณะที่วอลเล็ตถูà¸à¸¥à¹‡à¸­à¸„</translation>
</message>
<message>
- <source>Close</source>
- <translation type="unfinished">ปิด</translation>
+ <source>Unknown error processing transaction.</source>
+ <translation type="unfinished">ข้อผิดพลาดที่ไม่รู้จัà¸à¸‚องà¸à¸²à¸£à¸›à¸£à¸°à¸¡à¸§à¸¥à¸œà¸¥à¸˜à¸¸à¸£à¸à¸£à¸£à¸¡</translation>
+ </message>
+ <message>
+ <source>PSBT copied to clipboard.</source>
+ <translation type="unfinished">PSBT คัดลอà¸à¹„ปยังคลิปบอร์ดà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source> * Sends %1 to %2</source>
+ <translation type="unfinished"> * ส่ง %1 ถึง %2</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">จำนวน ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">หรือ</translation>
+ </message>
+ <message>
+ <source>Transaction has %1 unsigned inputs.</source>
+ <translation type="unfinished">ธุรà¸à¸£à¸£à¸¡à¸¡à¸µ %1 อินพุตที่ไม่ได้ลงนาม</translation>
+ </message>
+ <message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(à¹à¸•à¹ˆà¹„ม่มีà¸à¸²à¸£à¹‚หลดวอลเล็ต)</translation>
+ </message>
+ <message>
+ <source>(But this wallet cannot sign transactions.)</source>
+ <translation type="unfinished">(à¹à¸•à¹ˆà¸§à¸­à¸¥à¹€à¸¥à¹‡à¸—นี้ไม่สามารถลงนามà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡à¹„ด้)</translation>
</message>
</context>
<context>
<name>PeerTableModel</name>
<message>
+ <source>Peer</source>
+ <extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
+ <translation type="unfinished">เพียร์</translation>
+ </message>
+ <message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">อายุ</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">ทิศทาง</translation>
</message>
<message>
+ <source>Sent</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment>
+ <translation type="unfinished">ส่งà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have received from the peer.</extracomment>
+ <translation type="unfinished">รับà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
<source>Address</source>
<extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
- <translation type="unfinished">ที่อยู่</translation>
+ <translation type="unfinished">à¹à¸­à¸”เดรส</translation>
</message>
<message>
<source>Type</source>
<extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment>
- <translation type="unfinished">ชนิด</translation>
+ <translation type="unfinished">รูปà¹à¸šà¸š</translation>
</message>
- </context>
+ <message>
+ <source>Network</source>
+ <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment>
+ <translation type="unfinished">เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <extracomment>An Inbound Connection from a Peer.</extracomment>
+ <translation type="unfinished">ขาเข้า</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <extracomment>An Outbound Connection to a Peer.</extracomment>
+ <translation type="unfinished">ขาออà¸</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
<message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;บันทึภภาพ…</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation type="unfinished">&amp;คัดลอภภาพ</translation>
+ </message>
+ <message>
<source>Save QR Code</source>
- <translation type="unfinished">บันทึà¸à¸£à¸«à¸±à¸ª QR</translation>
+ <translation type="unfinished">บันทึภQR Code</translation>
</message>
- </context>
+ <message>
+ <source>PNG Image</source>
+ <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment>
+ <translation type="unfinished">ภาพ PNG</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
+ <source>&amp;Information</source>
+ <translation type="unfinished">&amp;ข้อมูล</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation type="unfinished">ทั่วไป</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished">เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished">ชื่อ</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation type="unfinished">ตัวเลข ของ connections</translation>
+ </message>
+ <message>
+ <source>Block chain</source>
+ <translation type="unfinished">บล็อà¸à¹€à¸Šà¸™</translation>
+ </message>
+ <message>
+ <source>Memory Pool</source>
+ <translation type="unfinished">พูลเมมโมรี่</translation>
+ </message>
+ <message>
+ <source>Memory usage</source>
+ <translation type="unfinished">à¸à¸²à¸£à¹ƒà¸Šà¹‰à¹€à¸¡à¸¡à¹‚มรี่</translation>
+ </message>
+ <message>
<source>Wallet: </source>
- <translation type="unfinished">à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์: </translation>
+ <translation type="unfinished">วอลเล็ต: </translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation type="unfinished">(ไม่มี)</translation>
+ </message>
+ <message>
+ <source>&amp;Reset</source>
+ <translation type="unfinished">&amp;รีเซ็ต</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation type="unfinished">รับà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation type="unfinished">ส่งà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation type="unfinished">เวอร์ชัน</translation>
</message>
<message>
<source>Last Transaction</source>
<translation type="unfinished">ธุรà¸à¸£à¸£à¸¡à¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">ไม่ว่าเราจะรีเลย์à¹à¸­à¸”เดรสปยังเพียร์นี้หรือไม่</translation>
+ </message>
+ <message>
<source>Address Relay</source>
- <translation type="unfinished">รีเลย์ที่อยู่</translation>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">รีเลย์ à¹à¸­à¸”เดรส</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">à¹à¸­à¸”เดรส ที่ประมวลผลà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">à¹à¸­à¸”เดรส จำà¸à¸±à¸”อัตรา</translation>
</message>
<message>
<source>Node window</source>
<translation type="unfinished">หน้าต่างโหนด</translation>
</message>
<message>
+ <source>Decrease font size</source>
+ <translation type="unfinished">ลด ขนาด ตัวอัà¸à¸©à¸£</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation type="unfinished">เพิ่ม ขนาด ตัวอัà¸à¸©à¸£</translation>
+ </message>
+ <message>
+ <source>Permissions</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•</translation>
+ </message>
+ <message>
+ <source>Services</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸šà¸£à¸´à¸à¸²à¸£</translation>
+ </message>
+ <message>
+ <source>High Bandwidth</source>
+ <translation type="unfinished">à¹à¸šà¸™à¸”์วิดท์สูง</translation>
+ </message>
+ <message>
+ <source>Connection Time</source>
+ <translation type="unfinished">เวลาในà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­</translation>
+ </message>
+ <message>
+ <source>Last Block</source>
+ <translation type="unfinished">Block สุดท้าย</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸ªà¹ˆà¸‡à¸¥à¹ˆà¸²à¸ªà¸¸à¸”</translation>
+ </message>
+ <message>
+ <source>Last Receive</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸£à¸±à¸šà¸¥à¹ˆà¸²à¸ªà¸¸à¸”</translation>
+ </message>
+ <message>
+ <source>Ping Time</source>
+ <translation type="unfinished">เวลาในà¸à¸²à¸£ Ping</translation>
+ </message>
+ <message>
+ <source>Ping Wait</source>
+ <translation type="unfinished">คอยในà¸à¸²à¸£ Ping</translation>
+ </message>
+ <message>
+ <source>Min Ping</source>
+ <translation type="unfinished">วินาทีในà¸à¸²à¸£ Ping</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">บล็อà¸à¹€à¸§à¸¥à¸²à¸¥à¹ˆà¸²à¸ªà¸¸à¸”</translation>
+ </message>
+ <message>
<source>&amp;Open</source>
<translation type="unfinished">&amp;เปิด</translation>
</message>
@@ -1087,24 +2055,107 @@
<translation type="unfinished">&amp;คอนโซล</translation>
</message>
<message>
+ <source>Totals</source>
+ <translation type="unfinished">ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Debug log file</source>
+ <translation type="unfinished">ไฟล์บันทึà¸à¸à¸²à¸£à¸”ีบัà¸</translation>
+ </message>
+ <message>
+ <source>In:</source>
+ <translation type="unfinished">เข้า:</translation>
+ </message>
+ <message>
+ <source>Out:</source>
+ <translation type="unfinished">ออà¸:</translation>
+ </message>
+ <message>
+ <source>Inbound: initiated by peer</source>
+ <extracomment>Explanatory text for an inbound peer connection.</extracomment>
+ <translation type="unfinished">ขาเข้า: เริ่มต้นด้วย peer</translation>
+ </message>
+ <message>
+ <source>Outbound Full Relay: default</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment>
+ <translation type="unfinished">ขาออภFull Relay: ค่าเริ่มต้น</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;คัดลอภà¹à¸­à¸”เดรส</translation>
+ </message>
+ <message>
+ <source>&amp;Disconnect</source>
+ <translation type="unfinished">&amp;หยุดเชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>1 &amp;hour</source>
+ <translation type="unfinished">1 &amp;ขั่วโมง</translation>
+ </message>
+ <message>
+ <source>1 d&amp;ay</source>
+ <translation type="unfinished">1 &amp;วัน</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation type="unfinished">1 &amp;สัปดาห์</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation type="unfinished">1 &amp;ปี</translation>
+ </message>
+ <message>
<source>&amp;Copy IP/Netmask</source>
<extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
<translation type="unfinished">&amp;คัดลอภIP/Netmask</translation>
</message>
<message>
+ <source>Executing command without any wallet</source>
+ <translation type="unfinished">ดำเนินà¸à¸²à¸£à¸„ำสั่งโดยไม่มีวอลเล็ตใด ๆ</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation type="unfinished">ดำเนินà¸à¸²à¸£à¸„ำสั่งโดยใช้ "%1" วอลเล็ต</translation>
+ </message>
+ <message>
+ <source>via %1</source>
+ <translation type="unfinished">โดยผ่าน %1</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished">ใช่</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished">ไม่</translation>
+ </message>
+ <message>
<source>To</source>
- <translation type="unfinished">ถึง</translation>
+ <translation type="unfinished">ไปยัง</translation>
</message>
<message>
<source>From</source>
<translation type="unfinished">จาà¸</translation>
</message>
- </context>
+ <message>
+ <source>Never</source>
+ <translation type="unfinished">ไม่เคย</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation type="unfinished">ไม่รู้จัà¸</translation>
+ </message>
+</context>
<context>
<name>ReceiveCoinsDialog</name>
<message>
+ <source>&amp;Amount:</source>
+ <translation type="unfinished">&amp;จำนวน:</translation>
+ </message>
+ <message>
<source>&amp;Label:</source>
- <translation type="unfinished">&amp;ป้ายชื่อ:</translation>
+ <translation type="unfinished">&amp;เลเบล:</translation>
</message>
<message>
<source>&amp;Message:</source>
@@ -1112,7 +2163,7 @@
</message>
<message>
<source>Clear</source>
- <translation type="unfinished">ล้าง</translation>
+ <translation type="unfinished">เคลียร์</translation>
</message>
<message>
<source>Show</source>
@@ -1120,22 +2171,38 @@
</message>
<message>
<source>Remove</source>
- <translation type="unfinished">เอาออà¸</translation>
+ <translation type="unfinished">นำออà¸</translation>
</message>
<message>
<source>Copy &amp;URI</source>
- <translation type="unfinished">&amp;คัดลอภURI</translation>
+ <translation type="unfinished">คัดลอภ&amp;URI</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;คัดลอภà¹à¸­à¸”เดรส</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">คัดลอภ&amp;เลเบล</translation>
+ </message>
+ <message>
+ <source>Copy &amp;message</source>
+ <translation type="unfinished">คัดลอภ&amp;ข้อความ</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">คัดลอภ&amp;จำนวน</translation>
</message>
<message>
<source>Could not unlock wallet.</source>
- <translation type="unfinished">ไม่สามารถปลดล็อคà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">ไม่สามารถปลดล็อà¸à¸§à¸­à¸¥à¹€à¸¥à¹‡à¸•à¹„ด้</translation>
</message>
</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
<source>Address:</source>
- <translation type="unfinished">ที่อยู่:</translation>
+ <translation type="unfinished">à¹à¸­à¸”เดรส:</translation>
</message>
<message>
<source>Amount:</source>
@@ -1143,7 +2210,7 @@
</message>
<message>
<source>Label:</source>
- <translation type="unfinished">ป้ายชื่อ:</translation>
+ <translation type="unfinished">เลเบล:</translation>
</message>
<message>
<source>Message:</source>
@@ -1151,15 +2218,31 @@
</message>
<message>
<source>Wallet:</source>
- <translation type="unfinished">à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์:</translation>
+ <translation type="unfinished">วอลเล็ต:</translation>
</message>
<message>
<source>Copy &amp;URI</source>
- <translation type="unfinished">&amp;คัดลอภURI</translation>
+ <translation type="unfinished">คัดลอภ&amp;URI</translation>
</message>
<message>
<source>Copy &amp;Address</source>
- <translation type="unfinished">&amp;คัดลอà¸à¸—ี่อยู่</translation>
+ <translation type="unfinished">คัดลอà¸Â &amp;à¹à¸­à¸”เดรส</translation>
+ </message>
+ <message>
+ <source>&amp;Verify</source>
+ <translation type="unfinished">&amp;ตรวจสอบ</translation>
+ </message>
+ <message>
+ <source>Verify this address on e.g. a hardware wallet screen</source>
+ <translation type="unfinished">ยืนยัน à¹à¸­à¸”เดรส นี้ อยู่ใน เช่น ฮาร์ดà¹à¸§à¸£à¹Œ วอลเล็ต สà¸à¸£à¸µà¸™</translation>
+ </message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">&amp;บันทึภภาพ…</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation type="unfinished">ข้อมูà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
</message>
</context>
<context>
@@ -1170,7 +2253,7 @@
</message>
<message>
<source>Label</source>
- <translation type="unfinished">ป้ายชื่อ</translation>
+ <translation type="unfinished">เลเบล</translation>
</message>
<message>
<source>Message</source>
@@ -1178,22 +2261,34 @@
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(ไม่มีป้ายชื่อ)</translation>
+ <translation type="unfinished">(ไม่มีเลเบล)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation type="unfinished">(ไม่มีข้อความ)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation type="unfinished">ร้องขอà¹à¸¥à¹‰à¸§</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
- <translation type="unfinished">ส่งเหรียà¸</translation>
+ <translation type="unfinished">ส่ง คอยน์</translation>
+ </message>
+ <message>
+ <source>automatically selected</source>
+ <translation type="unfinished">ทำà¸à¸²à¸£à¹€à¸¥à¸·à¸­à¸ โดยอัตโนมัติà¹à¸¥à¹‰à¸§</translation>
</message>
<message>
<source>Quantity:</source>
- <translation type="unfinished">จำนวน:</translation>
+ <translation type="unfinished">ปริมาณ:</translation>
</message>
<message>
<source>Bytes:</source>
- <translation type="unfinished">ไบต์:</translation>
+ <translation type="unfinished">ไบทส์:</translation>
</message>
<message>
<source>Amount:</source>
@@ -1205,61 +2300,164 @@
</message>
<message>
<source>After Fee:</source>
- <translation type="unfinished">ส่วนที่เหลือจาà¸à¸„่าธรรมเนียม:</translation>
+ <translation type="unfinished">หลังค่าธรรมเนียม:</translation>
</message>
<message>
<source>Change:</source>
- <translation type="unfinished">เงินทอน:</translation>
+ <translation type="unfinished">เปลี่ยน:</translation>
</message>
<message>
- <source>Hide</source>
- <translation type="unfinished">ซ่อน</translation>
+ <source>Custom change address</source>
+ <translation type="unfinished">เปลี่ยน à¹à¸­à¸”เดรส à¹à¸šà¸šà¸à¸³à¸«à¸™à¸”เอง</translation>
</message>
<message>
- <source>Recommended:</source>
- <translation type="unfinished">à¹à¸™à¸°à¸™à¸³:</translation>
+ <source>Transaction Fee:</source>
+ <translation type="unfinished">ค่าธรรมเนียม à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡:</translation>
</message>
<message>
- <source>Custom:</source>
- <translation type="unfinished">à¸à¸³à¸«à¸™à¸”เอง:</translation>
+ <source>Add &amp;Recipient</source>
+ <translation type="unfinished">เพิ่ม &amp;รายชื่อผู้รับ</translation>
</message>
<message>
<source>Dust:</source>
- <translation type="unfinished">เศษ:</translation>
+ <translation type="unfinished">ดัสท์:</translation>
+ </message>
+ <message>
+ <source>Choose…</source>
+ <translation type="unfinished">เลือà¸â€¦</translation>
+ </message>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation type="unfinished">ล้าง &amp;ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Balance:</source>
+ <translation type="unfinished">ยอดคงเหลือ:</translation>
+ </message>
+ <message>
+ <source>S&amp;end</source>
+ <translation type="unfinished">&amp;ส่ง</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">คัดลอภปริมาณ</translation>
</message>
<message>
<source>Copy amount</source>
- <translation type="unfinished">คัดลอà¸à¸ˆà¸³à¸™à¸§à¸™à¹€à¸‡à¸´à¸™</translation>
+ <translation type="unfinished">คัดลอภจำนวน</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">คัดลอภค่าธรรมเนียม</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">คัดลอภหลัง ค่าธรรมเนียม</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">คัดลอภbytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">คัดลอภdust</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">คัดลอภchange</translation>
+ </message>
+ <message>
+ <source>%1 (%2 blocks)</source>
+ <translation type="unfinished">%1 (%2 บล็อà¸)</translation>
+ </message>
+ <message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">ลงชื่อบนอุปà¸à¸£à¸“์</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">เชื่อมต่อฮาร์ดà¹à¸§à¸£à¹Œà¸§à¸­à¸¥à¹€à¸¥à¹‡à¸•à¸‚องคุณà¸à¹ˆà¸­à¸™</translation>
</message>
<message>
<source> from wallet '%1'</source>
- <translation type="unfinished">จาà¸à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์ '%1'</translation>
+ <translation type="unfinished">จาภวอลเล็ต '%1'</translation>
+ </message>
+ <message>
+ <source>%1 to '%2'</source>
+ <translation type="unfinished">%1 ไปยัง '%2'</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation type="unfinished">%1 ไปยัง %2</translation>
+ </message>
+ <message>
+ <source>Sign failed</source>
+ <translation type="unfinished">เซ็น ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>PSBT saved</source>
+ <translation type="unfinished">PSBT บันทึà¸</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">หรือ</translation>
</message>
<message>
<source>Do you want to create this transaction?</source>
<extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
<translation type="unfinished">คุณต้องà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸˜à¸¸à¸£à¸à¸£à¸£à¸¡à¸™à¸µà¹‰à¸«à¸£à¸·à¸­à¹„ม่?</translation>
</message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">โปรดตรวจสอบธุรà¸à¸£à¸£à¸¡à¸‚องคุณ คุณสามารถสร้างà¹à¸¥à¸°à¸ªà¹ˆà¸‡à¸˜à¸¸à¸£à¸à¸£à¸£à¸¡à¸™à¸µà¹‰à¸«à¸£à¸·à¸­à¸ªà¸£à¹‰à¸²à¸‡à¸˜à¸¸à¸£à¸à¸£à¸£à¸¡ Bitcoin ที่ลงชื่อบางส่วน (PSBT) ซึ่งคุณสามารถบันทึà¸à¸«à¸£à¸·à¸­à¸„ัดลอà¸à¹à¸¥à¹‰à¸§à¸¥à¸‡à¸Šà¸·à¹ˆà¸­à¹€à¸‚้าใช้ เช่น วอลเล็ต %1 ออฟไลน์, หรือ PSBT-compatible hardware wallet</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
+ <translation type="unfinished">โปรดตรวจสอบธุรà¸à¸£à¸£à¸¡à¸‚องคุณ</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation type="unfinished">ค่าธรรมเนียม à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">จำนวน ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation type="unfinished">ยืนยัน คอยน์ ที่ส่ง</translation>
+ </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform>คาดà¸à¸²à¸£à¸“์ว่าจะเริ่มà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸ à¸²à¸¢à¹ƒà¸™ %n บล็อà¸</numerusform>
+ <numerusform>Estimated to begin confirmation within %n block(s).</numerusform>
</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation type="unfinished">ยืนยันà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¹à¸­à¸”เดรสที่à¸à¸³à¸«à¸™à¸”เอง</translation>
+ </message>
+ <message>
<source>(no label)</source>
- <translation type="unfinished">(ไม่มีป้ายชื่อ)</translation>
+ <translation type="unfinished">(ไม่มีเลเบล)</translation>
</message>
</context>
<context>
<name>SendCoinsEntry</name>
<message>
- <source>&amp;Label:</source>
- <translation type="unfinished">&amp;ป้ายชื่อ:</translation>
+ <source>A&amp;mount:</source>
+ <translation type="unfinished">&amp;จำนวน:</translation>
</message>
<message>
- <source>Paste address from clipboard</source>
- <translation type="unfinished">วางที่อยู่จาà¸à¸„ลิปบอร์ด</translation>
+ <source>Pay &amp;To:</source>
+ <translation type="unfinished">ชำระ &amp;ให้:</translation>
+ </message>
+ <message>
+ <source>&amp;Label:</source>
+ <translation type="unfinished">&amp;เลเบล:</translation>
</message>
<message>
<source>Message:</source>
@@ -1276,22 +2474,46 @@
<context>
<name>SignVerifyMessageDialog</name>
<message>
- <source>Paste address from clipboard</source>
- <translation type="unfinished">วางที่อยู่จาà¸à¸„ลิปบอร์ด</translation>
+ <source>&amp;Sign Message</source>
+ <translation type="unfinished">&amp;เซ็น ข้อความ</translation>
</message>
<message>
- <source>Signature</source>
- <translation type="unfinished">ลายเซ็น</translation>
+ <source>Sign &amp;Message</source>
+ <translation type="unfinished">เซ็น &amp;ข้อความ</translation>
</message>
<message>
- <source>Sign &amp;Message</source>
- <translation type="unfinished">&amp;เซ็นข้อความ</translation>
+ <source>Clear &amp;All</source>
+ <translation type="unfinished">ล้าง &amp;ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>&amp;Verify Message</source>
+ <translation type="unfinished">&amp;ตรวจสอบ ข้อความ</translation>
+ </message>
+ <message>
+ <source>Verify &amp;Message</source>
+ <translation type="unfinished">ตรวจสอบ &amp;ข้อความ</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation type="unfinished">ปลดล็อควอลเล็ตถูà¸à¸¢à¸à¹€à¸¥à¸´à¸</translation>
</message>
<message>
<source>No error</source>
- <translation type="unfinished">ไม่มีข้อผิดพลาด</translation>
+ <translation type="unfinished">ไม่มี ข้อผิดพลาด</translation>
</message>
- </context>
+ <message>
+ <source>Message signed.</source>
+ <translation type="unfinished">ข้อความ เซ็นà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation type="unfinished">โปรดตรวจสอบลายเซ็นต์à¹à¸¥à¸°à¸¥à¸­à¸‡à¹ƒà¸«à¸¡à¹ˆà¸­à¸µà¸à¸„รั้ง</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation type="unfinished">ข้อความ ตรวจสอบà¹à¸¥à¹‰à¸§</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1306,40 +2528,102 @@
<context>
<name>TransactionDesc</name>
<message>
- <source>Status</source>
- <translation type="unfinished">สถานะ</translation>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
+ <translation type="unfinished">ขัดà¹à¸¢à¹‰à¸‡à¸à¸±à¸šà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡à¸à¸±à¸š %1 à¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
+ <translation type="unfinished">%1 ทำà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™</translation>
</message>
<message>
<source>Date</source>
<translation type="unfinished">วันที่</translation>
</message>
<message>
+ <source>Source</source>
+ <translation type="unfinished">à¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มา</translation>
+ </message>
+ <message>
<source>From</source>
<translation type="unfinished">จาà¸</translation>
</message>
<message>
+ <source>unknown</source>
+ <translation type="unfinished">ไม่ทราบ</translation>
+ </message>
+ <message>
<source>To</source>
- <translation type="unfinished">ถึง</translation>
+ <translation type="unfinished">ไปยัง</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation type="unfinished">à¹à¸­à¸”เดรส คุณเอง</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation type="unfinished">เลเบล</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation type="unfinished">เครดิต</translation>
</message>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>matures in %n more block(s)</numerusform>
</translation>
</message>
<message>
+ <source>not accepted</source>
+ <translation type="unfinished">ไม่ ยอมรับ</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation type="unfinished">เดบิต</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation type="unfinished">เดบิต ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation type="unfinished">เครดิต ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation type="unfinished">ค่าธรรมเนียม à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation type="unfinished">จำนวน สุทธิ</translation>
+ </message>
+ <message>
<source>Message</source>
<translation type="unfinished">ข้อความ</translation>
</message>
<message>
- <source>Comment</source>
- <translation type="unfinished">ความคิดเห็น</translation>
+ <source>Merchant</source>
+ <translation type="unfinished">ร้านค้า</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation type="unfinished">à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
</message>
<message>
<source>Amount</source>
<translation type="unfinished">จำนวน</translation>
</message>
- </context>
+ <message>
+ <source>true</source>
+ <translation type="unfinished">ถูà¸</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation type="unfinished">ผิด</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
@@ -1348,92 +2632,239 @@
</message>
<message>
<source>Type</source>
- <translation type="unfinished">ชนิด</translation>
+ <translation type="unfinished">รูปà¹à¸šà¸š</translation>
</message>
<message>
<source>Label</source>
- <translation type="unfinished">ป้ายชื่อ</translation>
+ <translation type="unfinished">เลเบล</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation type="unfinished">ไม่ยืนยัน</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation type="unfinished">เพิà¸à¹€à¸‰à¸¢</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation type="unfinished">รับ ด้วย</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation type="unfinished">รับ จาà¸</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation type="unfinished">ส่ง ถึง</translation>
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(ไม่มีป้ายชื่อ)</translation>
+ <translation type="unfinished">(ไม่มีเลเบล)</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation type="unfinished">ประเภท ของ à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
</message>
</context>
<context>
<name>TransactionView</name>
<message>
- <source>All</source>
- <translation type="unfinished">ทั้งหมด</translation>
+ <source>This week</source>
+ <translation type="unfinished">สัปดาห์นี้</translation>
</message>
<message>
- <source>Today</source>
- <translation type="unfinished">วันนี้</translation>
+ <source>Received with</source>
+ <translation type="unfinished">รับ ด้วย</translation>
</message>
<message>
- <source>This week</source>
- <translation type="unfinished">สัปดาห์นี้</translation>
+ <source>Sent to</source>
+ <translation type="unfinished">ส่ง ถึง</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation type="unfinished">ถึง ตัวคุณเอง</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation type="unfinished">อื่นๆ</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation type="unfinished">จำนวน ขั้นต่ำ</translation>
</message>
<message>
- <source>This month</source>
- <translation type="unfinished">เดือนนี้</translation>
+ <source>Range…</source>
+ <translation type="unfinished">ช่วง…</translation>
</message>
<message>
- <source>Last month</source>
- <translation type="unfinished">เดือนที่à¹à¸¥à¹‰à¸§</translation>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;คัดลอภà¹à¸­à¸”เดรส</translation>
</message>
<message>
- <source>This year</source>
- <translation type="unfinished">ปีนี้</translation>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">คัดลอภ&amp;เลเบล</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">คัดลอภ&amp;จำนวน</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">คัดลอภtransaction &amp;ID</translation>
+ </message>
+ <message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">คัดลอภ&amp;raw transaction</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">คัดลอภfull transaction &amp;details</translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">&amp;à¹à¸ªà¸”งรายละเอียดà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
+ </message>
+ <message>
+ <source>&amp;Edit address label</source>
+ <translation type="unfinished">&amp;à¹à¸à¹‰à¹„ข à¹à¸­à¸”เดรส เลเบล</translation>
+ </message>
+ <message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">à¹à¸ªà¸”ง ใน %1</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation type="unfinished">ส่งออà¸à¸›à¸£à¸°à¸§à¸±à¸•à¸´à¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">เครื่องหมายจุลภาค (Comma) เพื่อà¹à¸¢à¸à¹„ฟล์</translation>
</message>
<message>
<source>Confirmed</source>
<translation type="unfinished">ยืนยันà¹à¸¥à¹‰à¸§</translation>
</message>
<message>
+ <source>Watch-only</source>
+ <translation type="unfinished">ดูอย่างเดียว</translation>
+ </message>
+ <message>
<source>Date</source>
<translation type="unfinished">วันที่</translation>
</message>
<message>
<source>Type</source>
- <translation type="unfinished">ชนิด</translation>
+ <translation type="unfinished">รูปà¹à¸šà¸š</translation>
</message>
<message>
<source>Label</source>
- <translation type="unfinished">ป้ายชื่อ</translation>
+ <translation type="unfinished">เลเบล</translation>
</message>
<message>
<source>Address</source>
- <translation type="unfinished">ที่อยู่</translation>
+ <translation type="unfinished">à¹à¸­à¸”เดรส</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation type="unfinished">ไอดี</translation>
</message>
<message>
<source>Exporting Failed</source>
<translation type="unfinished">à¸à¸²à¸£à¸ªà¹ˆà¸‡à¸­à¸­à¸à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§</translation>
</message>
- </context>
+ <message>
+ <source>Exporting Successful</source>
+ <translation type="unfinished">ส่งออà¸à¸ªà¸³à¹€à¸£à¹‡à¸ˆ</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation type="unfinished">ช่วง:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation type="unfinished">ถึง</translation>
+ </message>
+</context>
<context>
<name>WalletFrame</name>
<message>
<source>Create a new wallet</source>
- <translation type="unfinished">สร้างà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">สร้าง วอลเล็ต ใหม่</translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished">ข้อผิดพลาด</translation>
</message>
- </context>
+ <message>
+ <source>Load Transaction Data</source>
+ <translation type="unfinished">โหลด Transaction Data</translation>
+ </message>
+ <message>
+ <source>Partially Signed Transaction (*.psbt)</source>
+ <translation type="unfinished">ธุรà¸à¸£à¸£à¸¡à¸—ี่ลงนามบางส่วน (*.psbt)</translation>
+ </message>
+ <message>
+ <source>PSBT file must be smaller than 100 MiB</source>
+ <translation type="unfinished">ไฟล์ PSBT ต้องมีขนาดเล็à¸à¸à¸§à¹ˆà¸² 100 MiB</translation>
+ </message>
+ <message>
+ <source>Unable to decode PSBT</source>
+ <translation type="unfinished">ไม่สามารถถอดรหัส PSBT</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
<message>
<source>Send Coins</source>
- <translation type="unfinished">ส่งเหรียà¸</translation>
+ <translation type="unfinished">ส่ง คอยน์</translation>
+ </message>
+ <message>
+ <source>Increasing transaction fee failed</source>
+ <translation type="unfinished">ค่าธรรมเนียมà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡à¸—ี่เพิ่มขึ้นล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Do you want to increase the fee?</source>
+ <extracomment>Asks a user if they would like to manually increase the fee of a transaction that has already been created.</extracomment>
+ <translation type="unfinished">คุณต้องà¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸„่าธรรมเนียมหรือไม่?</translation>
+ </message>
+ <message>
+ <source>Current fee:</source>
+ <translation type="unfinished">ค่าธรรมเนียมปัจจุบัน:</translation>
+ </message>
+ <message>
+ <source>Increase:</source>
+ <translation type="unfinished">เพิ่มขึ้น:</translation>
+ </message>
+ <message>
+ <source>New fee:</source>
+ <translation type="unfinished">ค่าธรรมเนียม ใหม่:</translation>
+ </message>
+ <message>
+ <source>Confirm fee bump</source>
+ <translation type="unfinished">ยืนยันค่าธรรมเนียมที่เพิ่มขึ้น</translation>
+ </message>
+ <message>
+ <source>Can't draft transaction.</source>
+ <translation type="unfinished">ไม่สามารถร่างธุรà¸à¸£à¸£à¸¡à¹„ด้</translation>
+ </message>
+ <message>
+ <source>Can't sign transaction.</source>
+ <translation type="unfinished">ไม่สามารถลงนามในà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation>
+ </message>
+ <message>
+ <source>Could not commit transaction</source>
+ <translation type="unfinished">ไม่สามารถทำธุรà¸à¸£à¸£à¸¡à¹„ด้</translation>
</message>
<message>
- <source>PSBT copied</source>
- <translation type="unfinished">คัดลอภPSBT à¹à¸¥à¹‰à¸§</translation>
+ <source>Can't display address</source>
+ <translation type="unfinished">ไม่สามารถ à¹à¸ªà¸”ง à¹à¸­à¸”เดรส</translation>
</message>
<message>
<source>default wallet</source>
- <translation type="unfinished">à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์เริ่มต้น</translation>
+ <translation type="unfinished">วอลเล็ต เริ่มต้น</translation>
</message>
</context>
<context>
@@ -1448,11 +2879,24 @@
</message>
<message>
<source>Backup Wallet</source>
- <translation type="unfinished">สำรองข้อมูลà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¸ªà¸•à¸²à¸‡à¸„์</translation>
+ <translation type="unfinished">à¹à¸šà¹‡à¸„อัพวอลเล็ต</translation>
+ </message>
+ <message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">ข้อมูล วอลเล็ต</translation>
</message>
<message>
<source>Backup Failed</source>
- <translation type="unfinished">à¸à¸²à¸£à¸ªà¸³à¸£à¸­à¸‡à¸‚้อมูลล้มเหลว</translation>
+ <translation type="unfinished">à¸à¸²à¸£à¸ªà¸³à¸£à¸­à¸‡à¸‚้อมูล ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation type="unfinished">สำรองข้อมูล สำเร็จà¹à¸¥à¹‰à¸§</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation type="unfinished">บันทึà¸à¸‚้อมูลวอลเล็ตไว้ที่ %1 เรียบร้อยà¹à¸¥à¹‰à¸§</translation>
</message>
<message>
<source>Cancel</source>
diff --git a/src/qt/locale/bitcoin_tk.ts b/src/qt/locale/bitcoin_tk.ts
new file mode 100644
index 0000000000..db47f8b33d
--- /dev/null
+++ b/src/qt/locale/bitcoin_tk.ts
@@ -0,0 +1,1577 @@
+<TS version="2.1" language="tk">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation type="unfinished">Salgyny ýa-da belligi rejelemek üçin syçanjygyň sag düwmesine basyň</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation type="unfinished">Täze salgy döret</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation type="unfinished">&amp;Täze</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation type="unfinished">Häzir saýlanan salgyny ulgamyň alyş-çalyş paneline göçür</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation type="unfinished">&amp;Göçür</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation type="unfinished">Ã&amp;ap</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">Häzir saýlanan salgyny bu sanawdan poz</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">Gözlemek üçin salgy ýa-da belligi ýaz</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Häzirki bellikdäki maglumaty faýla geçir</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;Geçir</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation type="unfinished">&amp;Poz</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">Teňňeleriň haýsy salga iberiljekdigini saýla</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">Teňňeleriň haýsy salgydan alynjakdygyny saýla</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation type="unfinished">S&amp;aýla</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation type="unfinished">Iberýän salgylar</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation type="unfinished">Kabul edýän salgylar</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 type="unfinished">Tölegleri ibermek üçin siziň Bitkoin salgylaryňyz şulardyr. Teňňeleri ibermezden ozal hemişe möçberi we kabul edýän salgyny barlaň.</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Tölegleri kabul etmek üçin siziň Bitkoin salgylaryňyz şulardyr. Täze salgylary döretmek üçin kabul etmek bölüminde "Täze kabul ediji salgyny döret" düwmesini ulan.
+Diňe "miras" görnüşli salgylar bilen gol çekmek mümkin.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished">Salgyny göçür</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">&amp;Belligi göçür</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;Rejele</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">Salgylar sanawyny geçir</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Otur bilen aýrylan faýl</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
+ <translation type="unfinished">Salgylar sanawyny %1 içine bellemäge çalşylanda ýalňyşlyk ýüze çykdy. Täzeden synap görüň.</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">Geçirip bolmady</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Bellik</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">Salgy</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(bellik ýok)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation type="unfinished">Parol sözlemi gepleşigi</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation type="unfinished">Parol sözlemini ýaz</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation type="unfinished">Täze parol sözlemi</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation type="unfinished">Täze parol sözlemini gaýtala</translation>
+ </message>
+ <message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">Parol sözlemini görkez</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">Gapjygy ÅŸifrle</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation type="unfinished">Bu amal üçin gapjygyň parol sözlemi bilen gapjygyňyzyň gulpuny açmagyňyz gerek.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation type="unfinished">Gapjygyň gulpuny aç</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation type="unfinished">Parol sözlemini çalyş</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation type="unfinished">Gapjygyň şifrlenmegini tassykla</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 type="unfinished">DuýduryÅŸ: Eger gapjygyňy ÅŸifrleseň we parol sözlemiňi ýitirseň, sen &lt;b&gt;ÄHLI BITKOINLERIŇI ÃITIRERSIŇ&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished">Gapjygyňy şifrlemek isleýäniň çynmy?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished">Gapjyk ÅŸifrlenen</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase for 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 type="unfinished">Gapjyk üçin täze parol sözlemini ýaz.&lt;br/&gt;&lt;b&gt;On ýa-da has köp tötänleýin nyşandan&lt;/b&gt; ýa-da &lt;b&gt;sekiz ýa-da has köp sözden&lt;/b&gt; ybarat parol sözlemini ulanyň.</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase for the wallet.</source>
+ <translation type="unfinished">Gapjyk üçin öňki we täze parol sözlemiňi ýaz.</translation>
+ </message>
+ <message>
+ <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation type="unfinished">Gapjygyňy şifrlemek kompýuteriňe zyýanly programma ýokuşmak arkaly bitkoinleriň ogurlanmagyndan doly gorap bilmejekdigini ýatdan çykarma.</translation>
+ </message>
+ <message>
+ <source>Wallet to be encrypted</source>
+ <translation type="unfinished">Åžifrlenmeli gapjyk</translation>
+ </message>
+ <message>
+ <source>Your wallet is about to be encrypted. </source>
+ <translation type="unfinished">Gapjygyň şifrlener.</translation>
+ </message>
+ <message>
+ <source>Your wallet is now encrypted. </source>
+ <translation type="unfinished">Gapjygyň häzir şifrlenen.</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 type="unfinished">WAJYP: Gapjyk faýlyň islendik ozalky ätiýaçlyk nusgalary täze emele gelen, şifrlenen gapjyk faýly bilen çalşyrylmaly. Howpsuzlyk maksady bilen, şifrlenen gapjyk faýlynyň ozalky ätiýaçlyk nusgalary täze şifrlenen gapjygy ulanyp başlan badyňyza peýdasyz bolup galar.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation type="unfinished">Gapjygy şifrläp bolmady</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation type="unfinished">Içki ýalňyşlyk sebäpli gapjygy şifrläp bolmady. Gapjygyň şifrlenmedi.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">Üpjün edilen parol sözlemleri gabat gelenok.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation type="unfinished">Gapjygyň gulpuny açyp bolmady</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation type="unfinished">Gapjygyň şifrini açmak üçin ýazylan parol sözlemi nädogry.</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished">Gapjygyň parol sözlemi üstünlikli çalşyldy.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished">Duýduryş: Caps Lock düwmesi açyk!</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>Banned Until</source>
+ <translation type="unfinished">Gadagan edilen möhleti</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">Dolandyryp bolmaýan ýagdaý</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">Ãowuz ýalňyÅŸlyk ýüze çykdy. %1 indi ygtybarly dowam edip bilenok we çykar.</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">Içki ýalňyşlyk</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Içki ýalňyşlyk ýüze çykdy. %1 ygtybarly dowam etmäge çalyşar. Bu garaşylmadyk näsazlyk we ol barada aşakda beýan edilişi ýaly hasabat berip bolar.</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Sazlamalary deslapky ýagdaýyna getirmek isleýäňmi ýa-da hiçhili üýtgeşme girizmezden ýatyrmak?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Ãowuz ýalňyÅŸlyk ýüze çykdy. Sazlamalar faýlyna ýazmak mümkinçiliginiň bardygyny ýa-da ýokdugyny barla, bolmasa -nosettings bilen iÅŸletmäge çalyÅŸ.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation type="unfinished">ÃalňyÅŸlyk: Görkezilen maglumatlar katalogy "%1" ýok.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">ÃalňyÅŸlyk: %1 konfigurasiýa faýlyny derňäp bolanok.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">ÃalňyÅŸlyk: %1</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 entek ygtybarly çykmady...</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Möçber</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Sazlamalar faýlyny okap bolanok</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Sazlamalar faýlyny ýazdyryp bolanok</translation>
+ </message>
+ </context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>&amp;Overview</source>
+ <translation type="unfinished">&amp;Umumy syn</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation type="unfinished">Gapjygyň umumy synyny görkez</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation type="unfinished">&amp;GeleÅŸikler</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation type="unfinished">Geleşikleriň geçmişine göz aýla</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation type="unfinished">Ç&amp;yk</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation type="unfinished">Programmadan çyk</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation type="unfinished">%1 &amp;barada</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation type="unfinished">%1 barada maglumat görkez</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation type="unfinished">&amp;Qt barada</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation type="unfinished">Qt barada maglumat görkez</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation type="unfinished">%1 üçin konfigurasiýa opsiýalaryny üýtget</translation>
+ </message>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Taze gapjyk döret</translation>
+ </message>
+ <message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Kiçelt</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Gapjyk:</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">Ulgamyň işleýşi ýapyk.</translation>
+ </message>
+ <message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation type="unfinished">Proksi &lt;b&gt;işleýär&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation type="unfinished">Bitkoin salgysyna teňňeleri iber</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation type="unfinished">Gapjygyň ätiýaçlyk nusgasyny başga ýere goý</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation type="unfinished">Gapjygy şifrlemek üçin ulanylan parol sözlemini üýtget</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation type="unfinished">&amp;Iber</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation type="unfinished">&amp;Kabul edip al</translation>
+ </message>
+ <message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Opsiýalar…</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;Gapjygy şifrle…</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">Gapjygyňa degişli hususy açarlary şifrle</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;Gapjygyň ätiýaçlyk nusgasyny sakla…</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;Parol sözlemini çalyş...</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">&amp;Habara gol çek…</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">Bitkoin salgylarynyň eýesidigini subut etmek üçin habarlara öz Bitkoin salgylaryň bilen gol çek</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;Habary tassykla…</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">Habarlaryň görkezilen Bitkoin salgylary bilen gol çekilendigini kepillendirmek üçin habarlary tassykla</translation>
+ </message>
+ <message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">Faýldan BGÇBA &amp;ýükle…</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">&amp;URI aç…</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">Gapjygy ýap...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">Gapjyk döret...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">Ähli gapjyklary ýap...</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation type="unfinished">&amp;Faýl</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation type="unfinished">&amp;Sazlamalar</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation type="unfinished">&amp;Kömek</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation type="unfinished">Bölümler gurallar paneli</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Sözbaşylary sinhron ýagdaýa getirmek (%1%)...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Ulgam bilen utgaÅŸdyrmak...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Diskde bloklar indekslenýär...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Diskde bloklar işlenýär...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Diskde bloklar gaýtadan indekslenýär...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Deňdeşlere baglanylýar...</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation type="unfinished">Tölegleri sora (QR kodlary we bitkoin: URIleri döredýär)</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation type="unfinished">Ulanylan iberilýän salgylaryň we bellikleriň sanawyny görkez</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation type="unfinished">Ulanylan kabul edip alýan salgylaryň we bellikleriň sanawyny görkez</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation type="unfinished">&amp;Buýruk setiri opsiýalary</translation>
+ </message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation type="unfinished">
+ <numerusform>Amallar geçmişinden %n blok(lar) işlendi.</numerusform>
+ <numerusform>Amallar geçmişinden %n blok(lar) işlendi.</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation type="unfinished">%1 galdy</translation>
+ </message>
+ <message>
+ <source>Catching up…</source>
+ <translation type="unfinished">Tutulýar...</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation type="unfinished">Soňky kabul edilen blok %1 öň döredilipdi.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation type="unfinished">Mundan soňky geleşikler entek görünmez.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">ÃalňyÅŸlyk</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation type="unfinished">Duýduryş</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation type="unfinished">Maglumat</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation type="unfinished">Döwrebap</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">Bölekleýýin gol çekilen bitkoin geleşigini ýükle</translation>
+ </message>
+ <message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">&amp;alyş-çalyş panelinden BGÇBA ýükle…</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">Bölekleýin gol çekilen bitkoin geleşigini alyş-çalyş panelinden ýükle</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">Düwün penjiresi</translation>
+ </message>
+ <message>
+ <source>Open node debugging and diagnostic console</source>
+ <translation type="unfinished">Düwüni zyýansyzlaşdyrma we anyklaýyş konsolyny aç</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">&amp;Iberilýän salgylar</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">&amp;Kabul edýän salgylar</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI</source>
+ <translation type="unfinished">Bitkoin aç: URI</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <translation type="unfinished">Gapjygy aç</translation>
+ </message>
+ <message>
+ <source>Open a wallet</source>
+ <translation type="unfinished">Gapjyk aç</translation>
+ </message>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">Gapjygy ýap</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">Ähli gapjyklary ýap</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation type="unfinished">Mümkin bolan Bitkoin buýruk setiri opsiýalarynyň sanawyny görmek üçin %1 goldaw habaryny görkez</translation>
+ </message>
+ <message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">&amp;Sanlaryň üstüni ört</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">Gözden geçir bölüminde sanlaryň üstüni ört</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">deslapky bellenen gapjyk</translation>
+ </message>
+ <message>
+ <source>No wallets available</source>
+ <translation type="unfinished">Elýeterli gapjyk ýok</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Gapjygyň ady</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;Penjire</translation>
+ </message>
+ <message>
+ <source>Zoom</source>
+ <translation type="unfinished">Ulalt</translation>
+ </message>
+ <message>
+ <source>Main Window</source>
+ <translation type="unfinished">Esasy penjire</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation type="unfinished">%1 müşderi</translation>
+ </message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Gizle</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">G&amp;örkez</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">
+ <numerusform>Bitkoin toruna %n işjeň arabaglanyşyk.</numerusform>
+ <numerusform>Bitkoin ulgamyna %n işjeň arabaglanyşyk.</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Başga hereketler üçin bas.</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Deňdeşler bölümini görkez</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">Ulgamyň işjeňligini öçür</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">Ulgamyň işjeňligini aç</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">ÃalňyÅŸlyk: %1</translation>
+ </message>
+ <message>
+ <source>Warning: %1</source>
+ <translation type="unfinished">Duýduryş: %1</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation type="unfinished">Sene: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation type="unfinished">Möçber: %1
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation type="unfinished">Gapjyk: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation type="unfinished">Görnüş: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation type="unfinished">Bellik: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation type="unfinished">Salgy: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation type="unfinished">Iberilen geleÅŸik</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation type="unfinished">Gelýän geleşik</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD açar döretmeklik &lt;b&gt;işjeň&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD açar döretmeklik &lt;b&gt;öçük&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">Hususy açar &lt;b&gt;öçük&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 type="unfinished">Gapjyk &lt;b&gt;şifrlenen&lt;/b&gt; we häzirki wagtda &lt;b&gt;gulpy açyk&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 type="unfinished">Gapjyk &lt;b&gt;şifrlenen&lt;/b&gt; we häzirki wagtda &lt;b&gt;gulply&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">BaÅŸdaky habar:</translation>
+ </message>
+</context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">Möçberleri görkezmek üçin ölçeg birligi. Başga ölçeg birligini saýlamak üçin bas.</translation>
+ </message>
+</context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Coin Selection</source>
+ <translation type="unfinished">Teňňe saýlamak</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">Sany:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">Baýtlar:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Möçber:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">Gatanç:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">Toz:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">Soňundan gatanç:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">Çalyş:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation type="unfinished">hemmesini saýla(ma)</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation type="unfinished">Agaç tertibi</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation type="unfinished">Sanaw tertibi</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Möçber</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation type="unfinished">Bellik bilen kabul edildi</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation type="unfinished">Salgy bilen kabul edildi</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Sene</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation type="unfinished">Tassyklamalar</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">Tassyklandy</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Möçberi göçür</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Salgyny göçür</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Belligi göçür</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">&amp;Möçberi göçür</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Amal &amp;IDsini we çykyş indeksini göçür</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">Ulanylmadygyny g&amp;ulpla</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">Ulanylmadygynyň &amp;gulpuny aç</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">Sany göçür</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Gatanjy göçür</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Soňundan gatanjy göçür</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Baýtlary göçür</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">Tozy göçür</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">Gaýtargyny göçür</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation type="unfinished">(%1 gulply)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation type="unfinished">hawa</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation type="unfinished">ýok</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished">Islendik kabul ediji häzirki toz çäginden has kiçi möçberi kabul edip alsa, bu bellik gyzyla öwrülýär.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation type="unfinished">Her giriş üçin +/- %1 satosi üýtgäp biler.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(bellik ýok)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation type="unfinished">%1-den gaýtargy (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation type="unfinished">(gaýtargy)</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletActivity</name>
+ <message>
+ <source>Create Wallet</source>
+ <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
+ <translation type="unfinished">Gapjyk döret</translation>
+ </message>
+ <message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">&lt;b&gt;%1&lt;/b&gt; gapjyk döredilýär...</translation>
+ </message>
+ <message>
+ <source>Create wallet failed</source>
+ <translation type="unfinished">Gapjyk döredip bolmady</translation>
+ </message>
+ <message>
+ <source>Create wallet warning</source>
+ <translation type="unfinished">Gapjyk döretmek duýduryşy</translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Gol çekenleriň sanawyny görkezip bolanok</translation>
+ </message>
+ </context>
+<context>
+ <name>OpenWalletActivity</name>
+ <message>
+ <source>Open wallet failed</source>
+ <translation type="unfinished">Gapjyk açyp bolmady</translation>
+ </message>
+ <message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">Gapjyk açmak duýduryşy</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">deslapky bellenen gapjyk</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
+ <translation type="unfinished">Gapjygy aç</translation>
+ </message>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">&lt;b&gt;%1&lt;/b&gt; gapjyk açylýar...</translation>
+ </message>
+</context>
+<context>
+ <name>WalletController</name>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">Gapjygy ýap</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">&lt;i&gt;%1&lt;/i&gt; gapjygy ýapmak isleýäniňiz çynmy?</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">Kesip gysgaltmaklyk işjeň bolsa, aşa uzak wagtlap gapjygyň ýapylmagy tutuş zynjyryň gaýtadan utgaşmak zerurlygyna getirip biler.</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">Ähli gapjyklary ýap</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">Ähli gapjyklary ýapmak isleýäniňiz çynmy?</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletDialog</name>
+ <message>
+ <source>Create Wallet</source>
+ <translation type="unfinished">Gapjyk döret</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <translation type="unfinished">Gapjygyň ady</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation type="unfinished">Gapjyk</translation>
+ </message>
+ <message>
+ <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
+ <translation type="unfinished">Gapjygy şifrle. Gapjyk siziň saýlan parol sözlemi bilen şifrlener.</translation>
+ </message>
+ <message>
+ <source>Encrypt Wallet</source>
+ <translation type="unfinished">Gapjygy ÅŸifrle</translation>
+ </message>
+ <message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">Giňişleýin opsiýalar</translation>
+ </message>
+ <message>
+ <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
+ <translation type="unfinished">Bu gapjyk üçin hususy açarlary öçür. Hususy açarlary öçük gapjyklaryň hiçhili hususy açary bolmaz we HD esasy açary ýa-da import edilen hususy açary bolmaz. Diňe gözden geçirip bolýan gapjyklar üçin iň göwnejaýydyr.</translation>
+ </message>
+ <message>
+ <source>Disable Private Keys</source>
+ <translation type="unfinished">Hususy açarlary öçür</translation>
+ </message>
+ <message>
+ <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
+ <translation type="unfinished">Boş gapjyk emele getir. Boş gapjyklaryň başda hususy açary ýa-da skripti bolmaýar. Soňra hususy açarlar ýa-da salgylar import edilip bilner ýa-da HD esasy açar bellenip bilner.</translation>
+ </message>
+ <message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">BoÅŸ gapjyk emele getir</translation>
+ </message>
+ <message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">scriptPubKey dolandyryşy üçin beýan edijileri ulan</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">Beýan ediji gapjyk</translation>
+ </message>
+ <message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Enjam gapjygy ýaly daşyndan gol çekilýän enjamy ulan. Ilki bilen gapjygyň ileri tutmalarynda daşyndan gol çekiji skriptini sazla.</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">Daşyndan gol çekiji</translation>
+ </message>
+ <message>
+ <source>Create</source>
+ <translation type="unfinished">Döret</translation>
+ </message>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished">Sqlite goldawsyz (beýan ediji gapjyklar üçin gerek) düzüldi</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Daşyndan gol çekmek üçin goldawsyz (daşyndan gol çekmek üçin gerek) düzüldi</translation>
+ </message>
+</context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation type="unfinished">Salgyny rejele</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation type="unfinished">&amp;Bellik</translation>
+ </message>
+ <message>
+ <source>The label associated with this address list entry</source>
+ <translation type="unfinished">Bu salgy sanawyndaky ýazgy bilen baglanyşykly bellik</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation type="unfinished">Bu salgy sanawyndaky ýazgy bilen baglanyşykly salgy. Bu diňe iberýän salgylar üçin üýtgedilip bilner.</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation type="unfinished">&amp;Salgy</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation type="unfinished">Täze iberýän salgy</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation type="unfinished">Kabul edýän salgyny rejele</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation type="unfinished">Iberýän salgyny rejele</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation type="unfinished">Ãazylan salgy %1 ýaly Bitkoin salgysy ýok.</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 type="unfinished">%1 salgysy %2 bellikli kabul edýän salgy hökmünde eýýäm bar we şonuň üçin ony iberýän salgy hökmünde goşup bolanok.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation type="unfinished">Ãazylan %1 salgysy salgylar kitabynda %2 belligi astynda eýýäm bar.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">Gapjygyň gulpuny açyp bolmady.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation type="unfinished">Täze açar döredip bolmady.</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>A new data directory will be created.</source>
+ <translation type="unfinished">Täze maglumat sanawy dörediler. </translation>
+ </message>
+ <message>
+ <source>name</source>
+ <translation type="unfinished">at</translation>
+ </message>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation type="unfinished">Sanaw eýýäm bar. Bu ýerde täze sanaw döretmekçi bolsaňyz, %1 goşuň.</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation type="unfinished">Ãol eýýäm bar we ol sanaw däldir.</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation type="unfinished">Bu ýerde maglumat sanawyny döredip bolanok.</translation>
+ </message>
+</context>
+<context>
+ <name>Intro</name>
+ <message>
+ <source>Bitcoin</source>
+ <translation type="unfinished">Bitkoin</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation type="unfinished">Bu sanawda azyndan %1 GB maglumat saklanar we ol wagtyň geçmegi bilen köpeler.</translation>
+ </message>
+ <message>
+ <source>Approximately %1 GB of data will be stored in this directory.</source>
+ <translation type="unfinished">Bu sanawda takmynan %1 GB maglumat saklanar.</translation>
+ </message>
+ <message numerus="yes">
+ <source>(sufficient to restore backups %n day(s) old)</source>
+ <extracomment>Explanatory text on the capability of the current prune target.</extracomment>
+ <translation type="unfinished">
+ <numerusform>(%n gün geçen ätiýaçlyk nusgalaryny dikeltmek üçin ýeterlik)</numerusform>
+ <numerusform>(%n gün geçen ätiýaçlyk nusgalaryny dikeltmek üçin ýeterlik)</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation type="unfinished">%1 Bitkoin blok zynjyrynyň nusgasyny ýükläp alar we göçürer.</translation>
+ </message>
+ <message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished">Gapjyk hem bu sanawa saklanar.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation type="unfinished">ÃalňyÅŸlyk: Görkezilen %1 maglumat sanawyny döredip bolanok.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">ÃalňyÅŸlyk</translation>
+ </message>
+ <message>
+ <source>Welcome</source>
+ <translation type="unfinished">Hoş geldiňiz</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation type="unfinished">%1-a hoş geldiňiz.</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 type="unfinished">Bu programma ilkinji gezek başlandygy sebäpli, %1-nyň öz maglumatlaryny nirä saklajakdygyny saýlap bilersiň.</translation>
+ </message>
+ <message>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">Blok zynjyrynyň saklanmagyny çäklendir</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
+ <translation type="unfinished">Bu sazlamany yzyna gaýtarmaklyk tutuş blok zynjyryny gaýtadan ýükläp almak zerur. Ilki bilen tutuş zynjyry ýükläp almak we soň ony kesmek has çalt bolar. Käbir giňişleýin aýratynlyklary öçürer.</translation>
+ </message>
+ <message>
+ <source> GB</source>
+ <translation type="unfinished">GB</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 type="unfinished">Bu başdaky utgaşdyrma örän çylşyrymlydyr we kompýuteriňiziň ozal üns berilmedik enjam näsazlyklaryny ýüze çykaryp biler. Her sapar %1 işledeniňizde ol säginen ýerinden ýükläp almaga dowam eder.</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 type="unfinished">Blok zynjyrynyň saklanyşyny çäklendirmegi (kesip aýyrmagy) saýlan bolsaňyz, geçmiş maglumatlary ýene-de ýüklenip alynmaly we işlenmelidir, emma diskiňiziň ulanylyşyny azaltmak üçin soňundan pozular. </translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation type="unfinished">Deslapky bellenen maglumat sanawyny ulan</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation type="unfinished">Aýratyn maglumat sanawyny ulan:</translation>
+ </message>
+</context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation type="unfinished">wersiýa</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished">%1 barada</translation>
+ </message>
+ <message>
+ <source>Command-line options</source>
+ <translation type="unfinished">Buýruk setiri opsiýalary</translation>
+ </message>
+</context>
+<context>
+ <name>ShutdownWindow</name>
+ <message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 ýapylýar...</translation>
+ </message>
+ <message>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation type="unfinished">Bu penjire ýitýänçä kompýuteri ýapmaň.</translation>
+ </message>
+</context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">Forma</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 type="unfinished">Soňky geleşikler entek görünmän biler, şonuň üçin gapjygyňyzdaky galyndy nädogry bolup biler. Bu maglumat aşakda beýan edilişi ýaly gapjygyňyz bitkoin tory bilen utgaşmagy tamamlanda dogry bolar.</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 type="unfinished">Entek görkezilmedik geleşikleriň täsirine düşen bitkoinleri sarp etmek synanyşygy ulgam tarapyndan kabul edilmez.</translation>
+ </message>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;Penjire</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Daşyndan gol çekmek üçin goldawsyz (daşyndan gol çekmek üçin gerek) düzüldi</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">ÃalňyÅŸlyk</translation>
+ </message>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">Forma</translation>
+ </message>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ <message>
+ <source>Address</source>
+ <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
+ <translation type="unfinished">Salgy</translation>
+ </message>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">Düwün penjiresi</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Salgyny göçür</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Salgyny göçür</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Belligi göçür</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">&amp;Möçberi göçür</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">Gapjygyň gulpuny açyp bolmady.</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Möçber:</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Gapjyk:</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Sene</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Bellik</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(bellik ýok)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">Sany:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">Baýtlar:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Möçber:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">Gatanç:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">Soňundan gatanç:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">Çalyş:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">Toz:</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">Sany göçür</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Möçberi göçür</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Gatanjy göçür</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Soňundan gatanjy göçür</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Baýtlary göçür</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">Tozy göçür</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">Gaýtargyny göçür</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(bellik ýok)</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Sene</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Möçber</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Sene</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Bellik</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(bellik ýok)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Salgyny göçür</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Belligi göçür</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">&amp;Möçberi göçür</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">Geleşigiň &amp;ID-sini göçür</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Otur bilen aýrylan faýl</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">Tassyklandy</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Sene</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Bellik</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">Salgy</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">Geçirip bolmady</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Taze gapjyk döret</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">ÃalňyÅŸlyk</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">deslapky bellenen gapjyk</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;Geçir</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Häzirki bellikdäki maglumaty faýla geçir</translation>
+ </message>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_tl.ts b/src/qt/locale/bitcoin_tl.ts
new file mode 100644
index 0000000000..8d2eb5f5bf
--- /dev/null
+++ b/src/qt/locale/bitcoin_tl.ts
@@ -0,0 +1,1527 @@
+<TS version="2.1" language="tl">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation type="unfinished">I-right-click upang i-edit ang ♦address♦ o ♦label♦</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation type="unfinished">Gumawa ng bagong ♦address♦</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation type="unfinished">&amp;Bago</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation type="unfinished">Kopyahin ang pinipiling ♦address♦ sa kasalakuyan sa ♦clipboard♦ ng sistema</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation type="unfinished">Isara</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">Tanggalin ang kasalukuyang napiling ♦address♦ sa listahan</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">Ilagay ang address o tatak na hahanapin</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">I-export ang datos sa kasalukuyang ♦tab♦ sa isang file</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;I-export</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation type="unfinished">&amp;Tanggalin</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">Piliin ang ♦address♦ kung saan ipapadala ang mga coin</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">Piliin ang ♦address♦ kung saan tatanggap ng mga coin</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation type="unfinished">&amp;Pumili</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation type="unfinished">Pinapadala ang mga ♦address♦</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation type="unfinished">Tinatanggap ang mga ♦address♦</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 type="unfinished">Ito ang mga ♦address♦ ng ♦Bitcoin♦ mo para pagpapadala ng mga bayad. Palaging suriin mo ang halaga at address kung saan tatanggap bago magpadala ka ng mga ♦coin.</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Ito ang mga address ng ♦Bitcoin♦ para sa pagtanggap ng mga baya. Gamitin ang 'Create new receiving address' na button sa receive tab para gumawa ng bagong mga address. Ang pag-sign ay posible lamang sa uri ng mga address na 'legacy'.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished">&amp;Kopyahin ang ♦Address♦</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">Kopyahin ang &amp;Tatak</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;I-edit</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">I-Export ang Listahan ng ♦Address♦</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Kuwir hiwalay na file</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
+ <translation type="unfinished">May mali sa pagsubok na i-save ang listahan ng address sa 1%1. Pakisubukan ulit.</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">Ang pag-export ay Nabigo</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Tatak</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">♦Address♦</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(walang tatak)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation type="unfinished">♦Passphrase♦ na ♦Dialog♦</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation type="unfinished">Ilagay ang ♦passphrase♦</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation type="unfinished">Bagong ♦passphrase♦</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation type="unfinished">Ulitin ang bagong ♦passphrase♦</translation>
+ </message>
+ <message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">Ipakita ang ♦passphrase♦</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">I-encrypt ang pitaka</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation type="unfinished">Ang operasyon na ito ay nangangailangan ng iyong pitaka ♦passphrase♦ para i-unlock ang pitaka.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation type="unfinished">I-unlock ang pitaka</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation type="unfinished">Palitan ang ♦passphrase♦</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation type="unfinished">Kumpirmahin ang ♦encryption♦ ng pitaka</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 type="unfinished">Babala: IKung i-encrypt mo ang iyong pitaka at mawawala ang ♦passphrase♦, &lt;b&gt;MAWAWALA MO ANG LAHAT NG IYONG MGA BITCOIN&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished">Sigurado ka ba na gusto mong i-encrypt ang iyong pitaka?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished">Ang pitaka ay na-encrypt na</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase for 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 type="unfinished">Ilagay ang bagong ♦passphrase♦ para sa pitaka.&lt;br/&gt;Pakigamit ang ♦passphrase♦ of &lt;b&gt;sampu o higit pa na mga ♦random♦ na mga karakter&lt;/b&gt;, o &lt;b&gt;walo o higit pang mga salita&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase for the wallet.</source>
+ <translation type="unfinished">Ilagay ang lumang ♦passphrase♦ at ang bagong ♦passphrase♦ para sa pitaka.</translation>
+ </message>
+ <message>
+ <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation type="unfinished">Tandaan na ang pag-encrypt sa iyong pitaka ay hindi ganap na mapoprotektahan ang mga ♦bitcoin♦ sa pagnanakaw ng ♦malware♦ na makakahawa sa iyong kompyuter.</translation>
+ </message>
+ <message>
+ <source>Wallet to be encrypted</source>
+ <translation type="unfinished">Ang pitaka ay i-encrypt</translation>
+ </message>
+ <message>
+ <source>Your wallet is about to be encrypted. </source>
+ <translation type="unfinished">Ang iyong pitaka ay mae-encrypt na.</translation>
+ </message>
+ <message>
+ <source>Your wallet is now encrypted. </source>
+ <translation type="unfinished">Ang iyong pitaka ay na-encrypt na.</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 type="unfinished">MAHALAGA: Kahit anong dating mga ♦backup♦ na ginawa mo sa ♦file♦ ng pitaka mo ay dapat na mapalitan ng bagong gawang, na-encrypt na ♦file♦ ng pitaka. Para sa mga rason ng seguridad, dating mga ♦backup♦ sa hindi na-encrypt na ♦file♦ ng pitaka ay magiging walang silbi sa lalong madaling panahon na sisimulan mong gamitin ang bago, na na-encrypt na pitaka.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation type="unfinished">Ang pag-encrypt sa pitaka ay nabigo</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation type="unfinished">Nabigo ang pag-encrypt sa pitaka dahil sa panloob na pagkakamali. Ang iyong pitaka ay hindi na-encrypt.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">Ang mga ibinigay na mga ♦passphrase♦ ay hindi nagtugma.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation type="unfinished">Ang pag-unlock sa pitaka ay nabigo</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation type="unfinished">Ang ♦passphrase♦ na ipinasok sa ♦decryption♦ sa pitaka ay hindi tama.</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished">Ang ♦passphrase♦ ng pitaka ay matagumpay na nabago.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished">Babala: Ang ♦Caps Lock Key♦ ay naka-on!</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation type="unfinished">♦IP/Netmask♦</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation type="unfinished">Ipinagbabawal Hanggang</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">Pagbubukod sa pagtakbo papalayo </translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">Malubhang pagkakamali ay naganap. 1%1 hindi na pwedeng magpatuloy ng ligtas at ihihinto na.</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">Panloob na pagkakamali</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">May panloob na pagkakamali ang naganap. 1%1 ay magtatangkang ituloy na ligtas. Ito ay hindi inaasahan na problema na maaaring i-ulat katulad ng pagkalarawan sa ibaba.</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Gusto mo bang i-reset ang mga ♦setting♦ sa ♦default♦ na mga ♦value♦, o itigil na hindi gumagawa ng mga pagbabago?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Isang malubhang pagkakamali ang naganap. Suriin ang mga ♦setting♦ ng ♦file♦ na ♦writable♦, o subukan na patakbuhin sa ♦-nosettings♦.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation type="unfinished">Pagkakamali: Ang natukoy na datos na ♦directory♦ "1%1" ay wala.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">Pagkakamali: Hindi ma-parse ang ♦configuration file♦: %1.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">Pagkakamali: 1%1</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">1%1 hindi pa nag-exit ng ligtas...</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Halaga</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Ang mga ♦setting file♦ ay hindi mabasa</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Ang mga ♦settings file♦ ay hindi maisulat</translation>
+ </message>
+ </context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>&amp;Overview</source>
+ <translation type="unfinished">&amp;Pangkalahatang ideya</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation type="unfinished">Ipakita ang pangkalahatang ideya ng pitaka</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation type="unfinished">&amp;Mga transaksyon</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation type="unfinished">Tignan ang kasaysayan ng transaksyon</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation type="unfinished">♦E&amp;xit</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation type="unfinished">Ihinto ang aplikasyon</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation type="unfinished">&amp;Tungkol sa %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation type="unfinished">Ipakita ang impormasyon tungkol sa %1</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation type="unfinished">Tungkol sa &amp;♦Qt♦</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation type="unfinished">Baguhin ang mga pagpipilian sa ♦configuration♦ para sa %1</translation>
+ </message>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Gumawa ng bagong pitaka</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Pitaka:</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">Na-disable ang aktibidad ng ♦network♦</translation>
+ </message>
+ <message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation type="unfinished">Ang paghalili ay &lt;b&gt;na-enable&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation type="unfinished">Magpadala ng mga ♦coin♦ sa ♦address♦ ng Bitcoin</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation type="unfinished">I-backup ang pitaka sa ibang lokasyon</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation type="unfinished">Palitan ang ♦passphrase♦ na ginamit para sa pag-encrypt sa pitaka</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation type="unfinished">&amp;Ipadala</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation type="unfinished">&amp;Tumanggap</translation>
+ </message>
+ <message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Mga pagpipilian...</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;I-encrypt ang Pitaka</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">I-encrypt ang mga pribadong mga susi na nabibilang sa iyong pitaka</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;I-backup ang Pitaka...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;Palitan ang ♦Passphrase♦...</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">Pirmahan &amp;magmensahe...</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">Tanda na mga mensahe sa mga ♦address♦ ng iyong ♦Bitcoin♦ para patunayan na pagmamay-ari mo sila</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;Patunayan ang mensahe...</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">Patunayan ang mga mensahe para matiyak na sila ay napirmahan ng may tinukoy na mga ♦Bitcoin address♦</translation>
+ </message>
+ <message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;I-load ang PSBT mula sa ♦file♦...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">Buksan ang &amp;♦URL♦...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">Isara ang Pitaka...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">Gumawa ng Pitaka...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">Isara ang Lahat ng mga Pitaka...</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation type="unfinished">&amp;♦File♦</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation type="unfinished">Mga &amp;♦Setting♦</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation type="unfinished">&amp;Tulong</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation type="unfinished">♦Tabs toolbar♦</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">♦Syncing Headers♦ (%1%)…</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Sini-siynchronize sa ♦network♦...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Ini-index ang mga bloke sa ♦disk♦...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Pinoproseso ang mga bloke sa ♦disk♦...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Ni-rere-index ang mga bloke sa ♦disk♦</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Kumokonekta sa mga ♦peers♦...</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation type="unfinished">Humiling ng mga bayad (gumagawa ng ♦QR codes♦ at ♦bitcoin: URIs♦)</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation type="unfinished">Ipakita ang listahan ng nagamit na pagpapadalhan na mga ♦address♦ at mga tatak</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation type="unfinished">Ipakita ang listahan ng nagamit na pagtatanggapan na mga ♦address♦ at mga tatak</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation type="unfinished">&amp;♦Command-line♦ na mga pagpipilian</translation>
+ </message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation type="unfinished">%1 sa likod</translation>
+ </message>
+ <message>
+ <source>Catching up…</source>
+ <translation type="unfinished">Humahabol...</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation type="unfinished">Ang huling natanggap na bloke ay nagawa %1kanina.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation type="unfinished">Ang mga transaksyon pagkatapos nito ay hindi pa muna makikita.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Nagkamali</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation type="unfinished">Babala</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation type="unfinished">Impormasyon</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">Ang ♦Load♦ ay Bahagyang Napirmahan na Transaksyon sa ♦Bitcoin♦</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">Ang ♦Load♦ ay Bahagyang Napirmahan na Transaksyon sa ♦Bitcoin♦ mula sa ♦clipboard♦</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">♦Node window♦</translation>
+ </message>
+ <message>
+ <source>Open node debugging and diagnostic console</source>
+ <translation type="unfinished">Bukas na ♦node debugging♦ at ♦diagnostic console♦</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">&amp;Pagpapadalhan na mga ♦address♦</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">&amp;Pagtatanggapan na mga ♦address♦</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI</source>
+ <translation type="unfinished">Buksan ang ♦bitcoin: URI♦</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <translation type="unfinished">Buksan ang pitaka</translation>
+ </message>
+ <message>
+ <source>Open a wallet</source>
+ <translation type="unfinished">Buksan ang pitaka</translation>
+ </message>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">Isarado ang pitaka</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">Isarado ang lahat na mga pitaka</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation type="unfinished">Ipakita ang %1 tumulong sa mensahe na kumuha ng listahan ng posibleng ♦Bitcoin command-line♦ na mga pagpipilian</translation>
+ </message>
+ <message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">&amp;♦Mask♦ na mga halaga</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">I-mask ang mga halaga sa loob ng ♦Overview tab♦</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">pitaka na ♦default♦</translation>
+ </message>
+ <message>
+ <source>No wallets available</source>
+ <translation type="unfinished">Walang pitaka na mayroon</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Pangalan ng pitaka</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;♦Window♦</translation>
+ </message>
+ <message>
+ <source>Zoom</source>
+ <translation type="unfinished">I-zoom</translation>
+ </message>
+ <message>
+ <source>Main Window</source>
+ <translation type="unfinished">Pangunahing ♦Window♦</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation type="unfinished">%1 na kliyente</translation>
+ </message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Itago</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">
+ <numerusform>%n aktibo na mga ♦connection(s)♦ sa ♦Bitcoin network♦.</numerusform>
+ <numerusform>%n na aktibong mga koneksyon sa ♦Bitcoin network♦</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Mag-click para sa marami pang gagawin.</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Ipakita ang ♦Peers tab♦</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">I-disable ang aktibidad ng ♦network♦</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">I-enable ang aktibidad ng ♦network♦</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">Pagkakamali: 1%1</translation>
+ </message>
+ <message>
+ <source>Warning: %1</source>
+ <translation type="unfinished">Babala: %1</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation type="unfinished">Petsa: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation type="unfinished">Halaga: %1
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation type="unfinished">Pitaka: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation type="unfinished">Uri: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation type="unfinished">Tatak: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation type="unfinished">♦Address♦: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation type="unfinished">Ipinadalang transaksyon</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation type="unfinished">Paparating na transaksyon</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished">♦HD♦ na susi sa henerasyon ay &lt;b&gt;na-enable&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">♦HD key generation♦ ay &lt;b&gt;na-disable&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">Pribadong susi &lt;b&gt;na-disable&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 type="unfinished">Ang pitaka ay &lt;b&gt;na-encrypt&lt;/b&gt; at kasalukuyang &lt;b&gt;na-unlock&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 type="unfinished">Ang pitaka ay &lt;b&gt;na-encrypt&lt;/b&gt; at kasalukuyang &lt;b&gt;na-lock&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">Orihinal na mensahe:</translation>
+ </message>
+</context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">Yunit na ipakita sa mga halaga. Mag-click para pumili ng ibang yunit.</translation>
+ </message>
+</context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Coin Selection</source>
+ <translation type="unfinished">Pagpipilian ng ♦coin♦</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">Dami:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">♦Bytes♦:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Halaga:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">Bayad:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">Alikabok:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">Pagkatapos na Bayad:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">Sukli:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation type="unfinished">i-(un)select lahat</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation type="unfinished">♦Tree mode♦</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation type="unfinished">Listajhan na ♦mode♦</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Halaga</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation type="unfinished">Natanggap na may kasamang ♦tatak♦</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation type="unfinished">Natanggap na may ♦address♦</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Petsa</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation type="unfinished">Mga kumpirmasyon</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">Nakumpirma</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Kopyahin ang halaga</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopyahin ang ♦address♦</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Kopyahin ang &amp;tatak</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopyahin ang &amp;halaga</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">&amp;I-lock ang hindi nagastos</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">&amp;I-unlock ang hindi nagastos</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">Kopyahin ang dami</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Bayad sa pagkopya</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Kopyahin pagkatapos ang bayad</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Kopyahin ang ♦bytes♦</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">Kopyahin ang ♦dust♦</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">Kopyahin ang pagbabago</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation type="unfinished">(%1 naka-lock)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation type="unfinished">oo</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation type="unfinished">hindi</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished">Ang tatak na ito ay nagiging pula kung ang sinomang tatanggap ay tatanggap ng halaga na mas maliit sa kasalukuyang ♦dust threshold♦</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation type="unfinished">Maaaring magbago ng +/- %1♦4satoshi(s)♦ kada ♦input♦.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(walang tatak)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation type="unfinished">ang pagbabago ay mula sa %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation type="unfinished">(pagbabago)</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletActivity</name>
+ <message>
+ <source>Create Wallet</source>
+ <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
+ <translation type="unfinished">Gumawa ng pitaka</translation>
+ </message>
+ <message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">Paggawa ng Pitaka &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Create wallet failed</source>
+ <translation type="unfinished">Ang paggawa ng pitaka ay nabigo</translation>
+ </message>
+ <message>
+ <source>Create wallet warning</source>
+ <translation type="unfinished">Babala sa paggawa ng pitaka</translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Hindi mailista ang mga tagapirma</translation>
+ </message>
+ </context>
+<context>
+ <name>OpenWalletActivity</name>
+ <message>
+ <source>Open wallet failed</source>
+ <translation type="unfinished">Pagbukas ng pitaka ay nabigo</translation>
+ </message>
+ <message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">Babala sa pagbukas ng pitaka</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">pitaka na ♦default♦</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
+ <translation type="unfinished">Buksan ang pitaka</translation>
+ </message>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">Pagbukas sa Pitaka &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+</context>
+<context>
+ <name>WalletController</name>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">Isarado ang pitaka</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">Sigurado ka ba na gusto mong isarado ang pitaka &lt;i&gt;%1&lt;/i&gt;?</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">Ang pagsasarod sa pitaka sa matagal ay maaaring humantong sa pag-resync ng kabuuang ♦chain♦ kung ang pagputol ay na-enable.</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">Isarado ang lahat na mga pitaka</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">Sigurado ka ba na gusto mong isarado lahat ng mga pitaka?
+</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletDialog</name>
+ <message>
+ <source>Create Wallet</source>
+ <translation type="unfinished">Gumawa ng pitaka</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <translation type="unfinished">Pangalan ng pitaka</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation type="unfinished">Pitaka</translation>
+ </message>
+ <message>
+ <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
+ <translation type="unfinished">I-encrypt ang pitaka. Ang pitaka ay mae-encrypt na may ♦passphrase♦ ng iyong mapipili.</translation>
+ </message>
+ <message>
+ <source>Encrypt Wallet</source>
+ <translation type="unfinished">I-encrypt ang pitaka</translation>
+ </message>
+ <message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">Mga Pagpipilian sa pagsulong</translation>
+ </message>
+ <message>
+ <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
+ <translation type="unfinished">I-disable ang mga pribadong mga susi para sa pitaka na ito. Ang mga pitaka na may mga pribadong mga susi na na-disable ay mawawalng ng pribadong mga susi at hindi magkakaroon ng ♦HD seed♦ o mga na-import na pribadong mga susi. Ito ay perpekto lamang para sa mga ♦watch-only♦ na mga pitaka.</translation>
+ </message>
+ <message>
+ <source>Disable Private Keys</source>
+ <translation type="unfinished">I-disable ang Pribadong mga Susi</translation>
+ </message>
+ <message>
+ <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
+ <translation type="unfinished">Gumawa ng blankong pitaka. Ang blankong mga pitaka hindi muna nagkakaroon ng pribadong mga susi o mga ♦script♦. Ang pribadong mga susi at mga ♦address♦ ay pwedeng ma-import, o ang ♦HD seed♦ ay pwedeng mai-set, mamaya.</translation>
+ </message>
+ <message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">Gumawa ng Blankong Pitaka</translation>
+ </message>
+ <message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">Gumawa ng mga ♦descriptors♦ para sa pamamahala sa ♦scriptPubKey♦</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">♦Descriptor♦ na pitaka</translation>
+ </message>
+ <message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Gumamit ng panlabas na pagpirmang ♦device♦ katulad ng ♦hardware♦ na pitaka. I-configure ang panlabas na ♦signer script♦ sa loob ng ♦preferences♦ ng pitaka n listahan. </translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">Panlabas na ♦signer♦</translation>
+ </message>
+ <message>
+ <source>Create</source>
+ <translation type="unfinished">Gumawa</translation>
+ </message>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished">Pinagsama-sama na walang suporta ng ♦sqlite♦ (kailangan para sa ♦descriptor♦ na pitaka)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Pinagsama-sama na walang suporta ng ♦pag-pirma♦ (kailangan para sa panlabasna pagpirma)</translation>
+ </message>
+</context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation type="unfinished">I-edit ang ♦address♦</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation type="unfinished">&amp;Tatak</translation>
+ </message>
+ <message>
+ <source>The label associated with this address list entry</source>
+ <translation type="unfinished">Ang tatak na nauugnay sa ♦entry♦ ng listahan ng ♦address♦</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation type="unfinished">Ang ♦address♦ na may kaugnayan sa ipinasok sa listahan ng ♦address♦. Ito ay maaari lamang ng mabago para sa pagpapadalhan na mga ♦address♦.</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation type="unfinished">&amp;♦Address♦</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation type="unfinished">Bagong pagpapadalhan na ♦address♦</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation type="unfinished">I-edit ang pagtatanggapang ♦address♦</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation type="unfinished">I-edit ang pagpapadalhan na ♦address♦</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation type="unfinished">Ang naipasok na ♦address♦ "%1" ay hindi wasto na ♦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 type="unfinished">Ang ♦Address♦ "%1" ay mayroon na bilang pagtatanggapang ♦address♦ na may tatak "%2" kaya hindi na maaaring maidagdag bilang pagpapadalhan na ♦address♦.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation type="unfinished">Ang naipasok na ♦address♦ "%1" ay nasa aklat na ng ♦address♦ na may tatak "%2".</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">Hindi maaaring ma-unlock ang pitaka.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation type="unfinished">Ang Bagong susi sa ♦generation♦ ay nabigo.</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>A new data directory will be created.</source>
+ <translation type="unfinished">May bagong datos na ♦directory♦ ay magagawa.</translation>
+ </message>
+ <message>
+ <source>name</source>
+ <translation type="unfinished">pangalan</translation>
+ </message>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation type="unfinished">Ang ♦directory♦ ay mayroon na. Magdagdag ng%1kung balak mong gumawa ng bagong ♦directory♦ dito.</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation type="unfinished">Ang ♦path♦ ay mayroon na, at hindi ♦directory♦.</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation type="unfinished">Hindi makakagawa ng datos na ♦directory♦ dito.</translation>
+ </message>
+</context>
+<context>
+ <name>Intro</name>
+ <message>
+ <source>Bitcoin</source>
+ <translation type="unfinished">♦Bitcoin♦</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation type="unfinished">Hindi bababa sa %1 ng ♦GB♦ na dato ay mailalagay sa ♦directory♦, at lalaki sa paglipas ng panahon.</translation>
+ </message>
+ <message numerus="yes">
+ <source>(sufficient to restore backups %n day(s) old)</source>
+ <extracomment>Explanatory text on the capability of the current prune target.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Nagkamali</translation>
+ </message>
+ <message>
+ <source>Welcome</source>
+ <translation type="unfinished">Maligayang Pagdating</translation>
+ </message>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation type="unfinished">bersyon</translation>
+ </message>
+ </context>
+<context>
+ <name>ShutdownWindow</name>
+ <message>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation type="unfinished">Huwag Patayin ang inyong kompyuter hanggang mawala ang window na ito.</translation>
+ </message>
+</context>
+<context>
+ <name>OptionsDialog</name>
+ <message>
+ <source>&amp;Main</source>
+ <translation type="unfinished">&amp;♦Main♦</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation type="unfinished">&amp;Simulan %1 sa pag-login sa sistema</translation>
+ </message>
+ <message>
+ <source>Size of &amp;database cache</source>
+ <translation type="unfinished">Laki ng &amp;♦database cache♦</translation>
+ </message>
+ <message>
+ <source>Number of script &amp;verification threads</source>
+ <translation type="unfinished">Bilang ng ♦script♦ &amp;pagpapatunay na mga ♦threads♦</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation type="unfinished">Mga pagpipilian sa &amp;Pag-reset</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation type="unfinished">&amp;♦Network♦</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation type="unfinished">Putulan &amp;i-block ang imbakan sa</translation>
+ </message>
+ <message>
+ <source>W&amp;allet</source>
+ <translation type="unfinished">&amp;Pitaka</translation>
+ </message>
+ <message>
+ <source>Enable coin &amp;control features</source>
+ <translation type="unfinished">I-enable ang pag-control na mga tampok ng ♦coin♦ </translation>
+ </message>
+ <message>
+ <source>&amp;Spend unconfirmed change</source>
+ <translation type="unfinished">&amp;Gumastos ng hindi nakumpirmang pagbabago</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;Panlabas na ♦signer script♦ na daanan</translation>
+ </message>
+ <message>
+ <source>Map port using &amp;UPnP</source>
+ <translation type="unfinished">♦Port♦ ng mapa gamit ang &amp;♦UPnP♦</translation>
+ </message>
+ <message>
+ <source>Map port using NA&amp;T-PMP</source>
+ <translation type="unfinished">♦Port♦ ng mapa gamit ang NA&amp;T-PMP</translation>
+ </message>
+ <message>
+ <source>Allow incomin&amp;g connections</source>
+ <translation type="unfinished">Pahintulutan ang paparating na mga &amp;koneksyon</translation>
+ </message>
+ <message>
+ <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
+ <translation type="unfinished">&amp;Kumonketa sa pamamagitan ng ♦SOCKS5 proxy (default proxy)♦:</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;♦Window♦</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Pinagsama-sama na walang suporta ng ♦pag-pirma♦ (kailangan para sa panlabasna pagpirma)</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Nagkamali</translation>
+ </message>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ <message>
+ <source>Address</source>
+ <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
+ <translation type="unfinished">♦Address♦</translation>
+ </message>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">♦Node window♦</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Kopyahin ang ♦address♦</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopyahin ang ♦address♦</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Kopyahin ang &amp;tatak</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopyahin ang &amp;halaga</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">Hindi maaaring ma-unlock ang pitaka.</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Halaga:</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Pitaka:</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Petsa</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Tatak</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(walang tatak)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">Dami:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">♦Bytes♦:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Halaga:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">Bayad:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">Pagkatapos na Bayad:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">Sukli:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">Alikabok:</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">Kopyahin ang dami</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Kopyahin ang halaga</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Bayad sa pagkopya</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Kopyahin pagkatapos ang bayad</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Kopyahin ang ♦bytes♦</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">Kopyahin ang ♦dust♦</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">Kopyahin ang pagbabago</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(walang tatak)</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Petsa</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Halaga</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Petsa</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Tatak</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(walang tatak)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Kopyahin ang ♦address♦</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Kopyahin ang &amp;tatak</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">Kopyahin ang &amp;halaga</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">Kopyahin ang transaksyon ng &amp;♦ID♦</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Kuwir hiwalay na file</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">Nakumpirma</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Petsa</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">Tatak</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">♦Address♦</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">Ang pag-export ay Nabigo</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Gumawa ng bagong pitaka</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Nagkamali</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">pitaka na ♦default♦</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;I-export</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">I-export ang datos sa kasalukuyang ♦tab♦ sa isang file</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 c4c7d290a6..c85cbe8a03 100644
--- a/src/qt/locale/bitcoin_tr.ts
+++ b/src/qt/locale/bitcoin_tr.ts
@@ -150,7 +150,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation type="unfinished">Bu işlemi yapabilmek için cüzdan parolanızı girmeniz gerekmektedir
+ <translation type="unfinished">kilidi açmakparolaBu işlemi yapabilmek için cüzdan parolanızı girmeniz gerekmektedir
Cüzdan kilidini aç.</translation>
</message>
<message>
@@ -248,6 +248,10 @@ Cüzdan kilidini aç.</translation>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">%1 ayar dosyası bozuk veya geçersiz olabilir.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">Sızıntı istisnası</translation>
</message>
@@ -360,7 +364,7 @@ Cüzdan kilidini aç.</translation>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform>%ngün</numerusform>
+ <numerusform>%n gün</numerusform>
</translation>
</message>
<message numerus="yes">
@@ -411,14 +415,18 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">%s dosyasının okunması sırasında bir hata meydana geldi! Tüm anahtarlar doğru bir şekilde okundu, ancak işlem verileri ya da adres defteri ögeleri hatalı veya eksik olabilir.</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Hata: İçeri gelen bağlantıların dinlenmesi başarısız oldu (dinleme %s hatasını verdi)</translation>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">%s okuma hatası! İşlem verileri eksik veya yanlış olabilir. Cüzdan yeniden taranıyor.</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 type="unfinished">-maxtxfee=&lt;tutar&gt; için geçersiz tutar: '%s' (Sıkışmış işlemleri önlemek için en az %s değerinde en düşük aktarım ücretine eşit olmalıdır)</translation>
</message>
<message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">Geçersiz veya bozuk peers.dat (%s). Bunun bir hata olduğunu düşünüyorsanız, lütfen %s'e bildirin. Geçici bir çözüm olarak, bir sonraki başlangıçta yeni bir dosya oluşturmak için dosyayı (%s) yoldan çekebilirsiniz (yeniden adlandırabilir, taşıyabilir veya silebilirsiniz).</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 type="unfinished">Lütfen bilgisayarınızın tarih ve saatinin doğruluğunu kontrol edin. Hata varsa %s doğru çalışmayacaktır.</translation>
</message>
@@ -439,6 +447,10 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Blok veritabanı gelecekten gibi görünen bir blok içermektedir. Bu, bilgisayarınızın saat ve tarihinin yanlış ayarlanmış olmasından kaynaklanabilir. Blok veritabanını sadece bilgisayarınızın tarih ve saatinin doğru olduğundan eminseniz yeniden derleyin.</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">Blok dizini db, eski bir 'txindex' içerir. Dolu disk alanını temizlemek için full -reindex çalıştırın, aksi takdirde bu hatayı yok sayın. Bu hata mesajı tekrar görüntülenmeyecek.</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished">Bu işlem, tutar düşüldükten sonra göndermek için çok düşük</translation>
</message>
@@ -475,10 +487,34 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Çözümlenemedi - %s adres: '%s'</translation>
</message>
<message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">-dnsseed false olarak ayarlanırken -forcednsseed true olarak ayarlanamıyor.</translation>
+ </message>
+ <message>
<source>Cannot write to data directory '%s'; check permissions.</source>
<translation type="unfinished">Veriler '%s' klasörüne yazılamıyor ; yetkilendirmeyi kontrol edin.</translation>
</message>
<message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">Önceki bir sürüm tarafından başlatılan -txindex yükseltmesi tamamlanamaz. Önceki sürümle yeniden başlatın veya full -reindex çalıştırın.</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s, %u bağlantı noktasında dinleme isteğinde bulunur. Bu bağlantı noktası "kötü" olarak kabul edilir ve bu nedenle, herhangi bir Bitcoin Core eşinin ona bağlanması olası değildir. Ayrıntılar ve tam liste için doc/p2p-bad-ports.md'ye bakın.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Belirli bağlantılar sağlayamaz ve aynı anda addrman'ın giden bağlantıları bulmasını sağlayamaz.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">%s yüklenirken hata oluştu: Harici imzalayan cüzdanı derlenmiş harici imzalayan desteği olmadan yükleniyor</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Geçersiz peers.dat dosyası yeniden adlandırılamadı. Lütfen taşıyın veya silin ve tekrar deneyin.</translation>
+ </message>
+ <message>
<source>Copyright (C) %i-%i</source>
<translation type="unfinished">Telif Hakkı (C) %i-%i</translation>
</message>
@@ -531,10 +567,6 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Veritabanı okuma hatası, program kapatılıyor.</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Zincirdurumu veritabanı yükseltme hatası</translation>
- </message>
- <message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation type="unfinished">Herhangi bir portun dinlenmesi başarısız oldu. Bunu istiyorsanız -listen=0 seçeneğini kullanınız.</translation>
</message>
@@ -559,6 +591,10 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Başlatma sınaması başarısız oldu. %s kapatılıyor.</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Girdi bulunamadı veya zaten harcandı</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">Yetersiz bakiye</translation>
</message>
@@ -611,6 +647,10 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Eksik tutar</translation>
</message>
<message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">İşlem boyutunu tahmin etmek için çözümleme verileri eksik</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">-whitebind: '%s' ile bir port belirtilmesi lazımdır</translation>
</message>
@@ -687,6 +727,10 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">İşlem tutarı negatif olmamalıdır.</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">İşlem değişikliği çıktı endeksi aralık dışında</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">İşlem çok uzun bir mempool zincirine sahip</translation>
</message>
@@ -695,10 +739,18 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">İşlem en az bir adet alıcıya sahip olmalı.</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">İşlemin bir değişiklik adresine ihtiyacı var, ancak bunu oluşturamıyoruz.</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">İşlem çok büyük</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">-maxsigcachesize: ' %s' MiB için bellek konumlandırılamıyor.</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation type="unfinished">Bu bilgisayarda %s ögesine bağlanılamadı (bağlanma %s hatasını verdi)</translation>
</message>
@@ -707,6 +759,10 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Bu bilgisayarda %s unsuruna bağlanılamadı. %s muhtemelen hâlihazırda çalışmaktadır.</translation>
</message>
<message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">Harici giriş için UTXO bulunamıyor.</translation>
+ </message>
+ <message>
<source>Unable to generate initial keys</source>
<translation type="unfinished">Başlangıç anahtarları üretilemiyor</translation>
</message>
@@ -715,6 +771,10 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Anahtarlar oluşturulamıyor</translation>
</message>
<message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">-maxuploadtarget ayrıştırılamıyor: '%s'</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">HTTP sunucusu başlatılamadı. Ayrıntılar için debug.log dosyasına bakınız.</translation>
</message>
@@ -731,10 +791,6 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Desteklenmeyen günlük kategorisi %s=%s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">UTXO veritabanı yükseltiliyor</translation>
- </message>
- <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">Kullanıcı Aracı açıklaması (%s) güvensiz karakterler içermektedir.</translation>
</message>
@@ -941,7 +997,7 @@ Cüzdan kilidini aç.</translation>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>İşlem geçmişinin %n bloğu işlendi.</numerusform>
</translation>
</message>
<message>
@@ -1017,6 +1073,16 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Cüzdan kapat</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Cüzdanı Geri Yükle...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Yedekleme dosyasından bir cüzdanı geri yükle</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Tüm cüzdanları kapat</translation>
</message>
@@ -1037,6 +1103,26 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Erişilebilir cüzdan yok</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Cüzdan Verisi</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Cüzdan Yedeği Yükle</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Cüzdanı Geri Yükle</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Cüzdan İsmi</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Pencere</translation>
</message>
@@ -1064,7 +1150,7 @@ Cüzdan kilidini aç.</translation>
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>Bitcoin ağına %n etkin bağlantı.</numerusform>
</translation>
</message>
<message>
@@ -1083,6 +1169,10 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">AÄŸ etkinliÄŸini etkinleÅŸtir</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Ãœstbilgiler senkronize ediliyor (%1%)...</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Hata: %1</translation>
</message>
@@ -1169,10 +1259,6 @@ Cüzdan kilidini aç.</translation>
<context>
<name>CoinControlDialog</name>
<message>
- <source>Coin Selection</source>
- <translation type="unfinished">Koin Seçimi</translation>
- </message>
- <message>
<source>Quantity:</source>
<translation type="unfinished">Miktar</translation>
</message>
@@ -1333,7 +1419,11 @@ Cüzdan kilidini aç.</translation>
<source>Create wallet warning</source>
<translation type="unfinished">Cüzdan oluşturma uyarısı</translation>
</message>
- </context>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Çok fazla harici imzalayan bulundu</translation>
+ </message>
+</context>
<context>
<name>LoadWalletsActivity</name>
<message>
@@ -1373,6 +1463,34 @@ Cüzdan kilidini aç.</translation>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Cüzdanı Geri Yükle</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Cüzdan Onarılıyor&lt;b&gt;%1&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Cüzdan geri yüklenemedi</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Cüzdan uyarısını geri yükle</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Cüzdan onarım mesajı</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1522,6 +1640,24 @@ Cüzdan kilidini aç.</translation>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%n GB alan kullanılabilir</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(gereken %n GB alandan)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB tam zincir için gerekli)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">Bu dizinde en az %1 GB veri depolanacak ve zamanla büyüyecek.</translation>
@@ -1534,7 +1670,7 @@ Cüzdan kilidini aç.</translation>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(%n günlük yedekleri geri yüklemek için yeterli)</numerusform>
</translation>
</message>
<message>
@@ -1745,10 +1881,25 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Bu, sizin veya bir üçüncü taraf aracının komut satırı ve JSON-RPC komutları aracılığıyla düğümle iletişim kurmasına olanak tanır.</translation>
</message>
<message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">R&amp;PC sunucusunu etkinleÅŸtir</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">&amp;Cüzdan</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Tutardan çıkarma ücretinin varsayılan olarak ayarlanıp ayarlanmayacağı.</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Varsayılan olarak ücreti tutardan düş</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">GeliÅŸmiÅŸ</translation>
</message>
@@ -1765,6 +1916,16 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">&amp; Onaylanmamış bozuk parayı harcayın</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">PSBT kontrollerini etkinleÅŸtir</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">PSBT kontrollerinin gösterilip gösterilmeyeceği.</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 type="unfinished">Yönlendiricide Bitcoin istemci portlarını otomatik olarak açar. Bu, sadece yönlendiricinizin UPnP desteği bulunuyorsa ve etkinse çalışabilir.</translation>
</message>
@@ -1837,6 +1998,10 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Bitcoin gönderildiğinde arayüzde gösterilecek varsayılan alt birimi seçiniz.</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 type="unfinished">İşlemler sekmesinde bağlam menüsü unsurları olarak görünen üçüncü taraf bağlantıları (mesela bir blok tarayıcısı). URL'deki %s, işlem hash değeri ile değiştirilecektir. Birden çok bağlantılar düşey çubuklar | ile ayrılacaktır.</translation>
+ </message>
+ <message>
<source>&amp;Third-party transaction URLs</source>
<translation type="unfinished">&amp;Üçüncü parti işlem URL'leri</translation>
</message>
@@ -1870,14 +2035,17 @@ Cüzdan kilidini aç.</translation>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">Seçenekleri sıfırlamayı onayla</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Değişikliklerin uygulanması için istemcinin yeniden başlatılması lazımdır.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">İstemci kapanacaktır. Devam etmek istiyor musunuz?</translation>
</message>
<message>
@@ -2129,6 +2297,11 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Gecikme</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">YaÅŸ</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Yönlendirme</translation>
@@ -2308,14 +2481,26 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Son Ä°ÅŸlem</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Adresleri bu eÅŸe iletip iletemeyeceÄŸimiz.</translation>
+ </message>
+ <message>
<source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Adres Aktarımı</translation>
</message>
<message>
<source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
<translation type="unfinished">Adresler Ä°ÅŸlendi</translation>
</message>
<message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Adresler Oran-Sınırlı</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">Kullanıcı Yazılımı</translation>
</message>
@@ -2851,6 +3036,11 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Bu iÅŸlemi oluÅŸturmak ister misiniz?</translation>
</message>
<message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Lütfen işleminizi gözden geçirin. Bu işlemi oluşturabilir ve gönderebilir veya örneğin çevrimdışı bir %1 cüzdanı veya PSBT uyumlu bir donanım cüzdanı gibi kaydedebileceğiniz veya kopyalayabileceğiniz ve ardından imzalayabileceğiniz bir Kısmen İmzalı Bitcoin İşlemi (PSBT) oluşturabilirsiniz.</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Lütfen işleminizi gözden geçirin.</translation>
@@ -2891,14 +3081,10 @@ Cüzdan kilidini aç.</translation>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">%1 tutarından yüksek bir ücret saçma derecede yüksek bir ücret olarak kabul edilir.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Ödeme talebinin geçerlilik süresi bitti.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>Tahmini %n blok içinde doğrulamaya başlanacaktır.</numerusform>
</translation>
</message>
<message>
@@ -2969,14 +3155,6 @@ Cüzdan kilidini aç.</translation>
<translation type="unfinished">Ä°leti:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Bu, kimliği doğrulanmamış bir ödeme talebidir.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Bu, kimliği doğrulanmış bir ödeme talebidir.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Kullanılmış adres listesine eklemek için bu adrese bir etiket girin</translation>
</message>
@@ -2984,14 +3162,6 @@ Cüzdan kilidini aç.</translation>
<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 type="unfinished">Referans için bitcoin: URI'siyle iliştirilmiş işlemle birlikte depolanacak bir ileti. Not: Bu mesaj Bitcoin ağı üzerinden gönderilmeyecektir.</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Şu adrese öde:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Not:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3158,30 +3328,22 @@ Cüzdan kilidini aç.</translation>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">%1 doğrulamalı bir işlem ile çelişti</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/doğrulanmamış, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">bellek alanında</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">bellek alanında değil</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">terk edilmiÅŸ</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/doğrulanmadı</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 doÄŸrulama</translation>
</message>
<message>
@@ -3231,7 +3393,7 @@ Cüzdan kilidini aç.</translation>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n ek blok sonrasında olgunlaşacak</numerusform>
</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_ug.ts b/src/qt/locale/bitcoin_ug.ts
index 08f03f97ee..986af6891b 100644
--- a/src/qt/locale/bitcoin_ug.ts
+++ b/src/qt/locale/bitcoin_ug.ts
@@ -76,6 +76,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
پەقەت «ئەنئەنىۋى(legacy)» تىپتىكى ئادرÛسلا ئىمزانى قوللايدۇ.</translation>
</message>
<message>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished">ئادرÛس كۆچۈر(&amp;C)</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">بەلگىنى كۆچۈر(&amp;L)</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">تەھرىر(&amp;E)</translation>
+ </message>
+ <message>
<source>Export Address List</source>
<translation type="unfinished">ئادرÛس تىزىمىنى چىقار</translation>
</message>
@@ -110,6 +122,33 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation type="unfinished">ئىم ئىبارە سۆزلەشكۈسى</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation type="unfinished">ئىم ئىبارە كىرگۈزۈڭ</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation type="unfinished">ÙŠÛÚ­Ù‰ ئىم ئىبارە</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation type="unfinished">ÙŠÛÚ­Ù‰ ئىم ئىبارەنى تەكرارلاڭ</translation>
+ </message>
+ <message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">ئىم ئىبارە كۆرسەت</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">ھەمياننى شىÙىرلا</translation>
+ </message>
+ </context>
+<context>
<name>QObject</name>
<message numerus="yes">
<source>%n second(s)</source>
@@ -193,6 +232,27 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts
index c1053370a2..88b519b2b3 100644
--- a/src/qt/locale/bitcoin_uk.ts
+++ b/src/qt/locale/bitcoin_uk.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">Клацніть правою кнопкою миші Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð´Ñ€ÐµÑи або мітки</translation>
+ <translation type="unfinished">Клацніть правою кнопкою миші, щоб змінити адреÑу або мітку</translation>
</message>
<message>
<source>Create a new address</source>
@@ -15,7 +15,7 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation type="unfinished">Копіювати виділену адреÑу в буфер обміну</translation>
+ <translation type="unfinished">Скопіюйте поточну вибрану адреÑу в ÑиÑтемний буфер обміну</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -27,19 +27,19 @@
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation type="unfinished">Вилучити вибрану адреÑу з переліку</translation>
+ <translation type="unfinished">Видалити поточну вибрану адреÑу зі ÑпиÑку </translation>
</message>
<message>
<source>Enter address or label to search</source>
- <translation type="unfinished">Введіть адреÑу чи мітку Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ</translation>
+ <translation type="unfinished">Введіть адреÑу або мітку Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation type="unfinished">ЕкÑпортувати дані з поточної вкладки в файл</translation>
+ <translation type="unfinished">ЕкÑпортувати дані з поточної вкладки у файл</translation>
</message>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">&amp;ЭкÑпорт</translation>
+ <translation type="unfinished">&amp;ЕкÑпортувати</translation>
</message>
<message>
<source>&amp;Delete</source>
@@ -67,7 +67,7 @@
</message>
<message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
- <translation type="unfinished">Це ваші адреÑи Bitcoin Ð´Ð»Ñ Ð½Ð°Ð´ÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¿Ð»Ð°Ñ‚ÐµÐ¶Ñ–Ð². Завжди перевірÑйте Ñуму та адреÑу одержувача перед відправленнÑм монет.</translation>
+ <translation type="unfinished">Це ваші біткоїн-адреÑи Ð´Ð»Ñ Ð½Ð°Ð´ÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¿Ð»Ð°Ñ‚ÐµÐ¶Ñ–Ð². Завжди перевірÑйте Ñуму та адреÑу одержувача перед відправленнÑм монет.</translation>
</message>
<message>
<source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
@@ -246,12 +246,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Файл параметрів %1 можу бути пошкоджений або недійÑний.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">Ðебажана винÑткова ÑитуаціÑ</translation>
</message>
<message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <translation type="unfinished">СталаÑÑ ÐºÑ€Ð¸Ñ‚Ð¸Ñ‡Ð½Ð° помилка. %1 більше не може продовжувати безпечно Ñ– завершить роботу.</translation>
+ <translation type="unfinished">СталаÑÑ Ñ„Ð°Ñ‚Ð°Ð»ÑŒÐ½Ð° помилка. %1 більше не може продовжувати безпечно Ñ– завершить роботу.</translation>
</message>
<message>
<source>Internal error</source>
@@ -259,7 +263,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
- <translation type="unfinished">Виникла Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. %1 Ñпробує безпечно продовжити роботу. Можете повідомити про цю неочікувану помилку, Ñк це опиÑано нижче.</translation>
+ <translation type="unfinished">Виникла Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. %1 Ñпробує безпечно продовжити роботу. Це неочікувана помилка, про Ñку можливо повідомити, Ñк це опиÑано нижче.</translation>
</message>
</context>
<context>
@@ -272,7 +276,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
<extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
- <translation type="unfinished">СталаÑÑ ÐºÑ€Ð¸Ñ‚Ð¸Ñ‡Ð½Ð° помилка. Перевірте, чи файл налаштувань доÑтупний Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу, або Ñпробуйте запуÑтити з -nosettings.</translation>
+ <translation type="unfinished">СталаÑÑ ÐºÑ€Ð¸Ñ‚Ð¸Ñ‡Ð½Ð° помилка. Перевірте, чи файл параметрів доÑтупний Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу, або Ñпробуйте запуÑтити з -nosettings.</translation>
</message>
<message>
<source>Error: Specified data directory "%1" does not exist.</source>
@@ -446,11 +450,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>bitcoin-core</name>
<message>
<source>Settings file could not be read</source>
- <translation type="unfinished">Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл налаштувань</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл параметрів</translation>
</message>
<message>
<source>Settings file could not be written</source>
- <translation type="unfinished">Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл налаштувань</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл параметрів</translation>
</message>
<message>
<source>The %s developers</source>
@@ -458,7 +462,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
- <translation type="unfinished">%s пошкоджено. Спробуйте ÑкориÑтатиÑÑ Ñ–Ð½Ñтрументом Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ bitcoin-wallet Ð´Ð»Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð°Ð±Ð¾ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ñ— копії.</translation>
+ <translation type="unfinished">%s пошкоджено. Спробуйте ÑкориÑтатиÑÑ Ñ–Ð½Ñтрументом Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ bitcoin-wallet Ð´Ð»Ñ Ð²Ð¸Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð°Ð±Ð¾ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ñ— копії.</translation>
</message>
<message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
@@ -505,10 +509,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Помилка: ЗаÑтарілі гаманці підтримують тільки адреÑи типів "legacy", "p2sh-segwit" та "bech32"</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">Помилка: Ðе вдалоÑÑ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ñ‚Ð¸ проÑÐ»ÑƒÑ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ…Ñ–Ð´Ð½Ð¸Ñ… підключень (listen повернув помилку: %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">Оцінка коміÑÑ–Ñ— не вдалаÑÑ. Fallbackfee вимкнено. Зачекайте кілька блоків або ввімкніть -fallbackfee.</translation>
</message>
@@ -550,11 +550,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
- <translation type="unfinished">Ð’Ñтановлений розмір ланцюжка блоків Ñ” замалим (меншим за %d МіБ). ВикориÑтовуйте більший розмір.</translation>
+ <translation type="unfinished">Ð’Ñтановлений розмір Ñкороченого блокчейна Ñ” замалим (меншим за %d МіБ). ВикориÑтовуйте більший розмір.</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">Режим Ñкороченого блокчейна неÑуміÑний з -reindex-chainstate. ВикориÑтовуйте натоміÑÑ‚ÑŒ повний -reindex.</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 type="unfinished">ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ ÑкороченнÑ: оÑÑ‚Ð°Ð½Ð½Ñ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð²Ð¼Ñ–Ñту гаманцю не обмежуєтьÑÑ Ð´Ñ–Ñми над Ñкороченими даними. Вам необхідно зробити повторну індекÑацію -reindex (заново завантажити веÑÑŒ блокчейн, Ñкщо викориÑтовуєтьÑÑ ÑкороченнÑ)</translation>
+ <translation type="unfinished">Скорочений блокчейн: оÑÑ‚Ð°Ð½Ð½Ñ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ Ð²Ð¸Ñ…Ð¾Ð´Ð¸Ñ‚ÑŒ за межі Ñкорочених даних. Потрібно перезапуÑтити з -reindex (заново завантажити веÑÑŒ блокчейн, Ñкщо викориÑтовуєтьÑÑ ÑкороченнÑ)</translation>
</message>
<message>
<source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
@@ -598,13 +602,21 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
- <translation type="unfinished">Ðеможливо відтворити блоки. Вам потрібно буде перебудувати базу даних, викориÑтовуючи -reindex-chainstate.</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ блоки. Вам потрібно буде перебудувати базу даних, викориÑтовуючи -reindex-chainstate.</translation>
</message>
<message>
<source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source>
<translation type="unfinished">Вказано невідомий формат "%s" файлу гаманцÑ. Укажіть "bdb" або "sqlite".</translation>
</message>
<message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">ВиÑвлено неÑуміÑний формат бази даних Ñтану блокчейна. ПерезапуÑÑ‚Ñ–Ñ‚ÑŒ з -reindex-chainstate. Це перебудує базу даних Ñтану блокчейна.</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Гаманець уÑпішно Ñтворено. Підтримка гаманців заÑтарілого типу припинÑєтьÑÑ, Ñ– можливіÑÑ‚ÑŒ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð° Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð°ÐºÐ¸Ñ… гаманців буде видалена.</translation>
+ </message>
+ <message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
<translation type="unfinished">ПопередженнÑ: Формат "%s" файлу дампа Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ Ð½Ðµ збігаєтьÑÑ Ð· форматом "%s", що зазначений у командному Ñ€Ñдку.</translation>
</message>
@@ -622,7 +634,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">Вам необхідно перебудувати базу даних з викориÑтаннÑм -reindex Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð²Ð½Ð¾Ð³Ð¾ ланцюжка блоків.</translation>
+ <translation type="unfinished">Вам необхідно перебудувати базу даних з викориÑтаннÑм -reindex Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð²Ð½Ð¾Ð³Ð¾ блокчейна.</translation>
</message>
<message>
<source>%s is set very high!</source>
@@ -657,6 +669,94 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ -txindex, що було почате попередньою верÑією, не вдалоÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ñ‚Ð¸. ПерезапуÑтить попередню верÑÑ–ÑŽ або виконайте повний -reindex.</translation>
</message>
<message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s запитує проÑÐ»ÑƒÑ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ñ€Ñ‚Ñƒ %u . Цей порт вважаєтьÑÑ "поганим", Ñ– тому малоймовірно, що будь-Ñкі інші вузли Bitcoin Core підключатьÑÑ Ð´Ð¾ нього. ДивітьÑÑ doc/p2p-bad-ports.md Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´ÐµÑ‚Ð°Ð»ÑŒÐ½Ð¾Ñ— інформації та повного ÑпиÑку.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Параметр -reindex-chainstate неÑуміÑний з -blockfilterindex. ТимчаÑово вимкніть blockfilterindex під Ñ‡Ð°Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ -reindex-chainstate, або замінить -reindex-chainstate на -reindex Ð´Ð»Ñ Ð¿Ð¾Ð²Ð½Ð¾Ñ— перебудови вÑÑ–Ñ… індекÑів.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Параметр -reindex-chainstate неÑуміÑний з -coinstatsindex. ТимчаÑово вимкніть coinstatsindex під Ñ‡Ð°Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ -reindex-chainstate, або замінить -reindex-chainstate на -reindex Ð´Ð»Ñ Ð¿Ð¾Ð²Ð½Ð¾Ñ— перебудови вÑÑ–Ñ… індекÑів.</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">Параметр -reindex-chainstate неÑуміÑний з -txindex. ТимчаÑово вимкніть txindex під Ñ‡Ð°Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ -reindex-chainstate, або замінить -reindex-chainstate на -reindex Ð´Ð»Ñ Ð¿Ð¾Ð²Ð½Ð¾Ñ— перебудови вÑÑ–Ñ… індекÑів.</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">Блокчейн, що вважаєтьÑÑ Ð´Ñ–Ð¹Ñним: оÑÑ‚Ð°Ð½Ð½Ñ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ Ð²Ð¸Ñ…Ð¾Ð´Ð¸Ñ‚ÑŒ за межі доÑтупних даних про блоки. Зачекайте, доки фонова перевірка блокчейна завантажить більше блоків.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð²Ñтановити визначені з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ– одночаÑно викориÑтовувати addrman Ð´Ð»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð²Ð¸Ñ…Ñ–Ð´Ð½Ð¸Ñ… з'єднань.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ %s: Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ Ð·Ñ– зовнішнім підпиÑувачем, але Ñкомпільовано без підтримки зовнішнього підпиÑуваннÑ</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Помилка: Дані адреÑної книги в гаманці не можна ідентифікувати Ñк належні до перенеÑених гаманців</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">Помилка: Ідентичні деÑкриптори Ñтворено під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑеннÑ. Можливо, гаманець пошкоджено.</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">Помилка: Транзакцію %s в гаманці не можна ідентифікувати Ñк належну до перенеÑених гаманців</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">Помилка: Ðе вдалоÑÑ Ñтворити деÑкриптори Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ заÑтарілого гаманцÑ. Спочатку переконайтеÑÑ, що гаманець розблоковано.</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ñ‚Ð¸ недійÑний файл peers.dat. Будь лаÑка, переміÑÑ‚Ñ–Ñ‚ÑŒ його та повторіть Ñпробу </translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">ÐеÑуміÑні параметри: чітко вказано -dnsseed=1, але -onlynet заборонÑÑ” IPv4/IPv6 з'єднаннÑ</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">Вихідні з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ñ– мережею Tor (-onlynet=onion), але прокÑÑ–-Ñервер Ð´Ð»Ñ Ð´Ð¾Ñтупу до мережі Tor повніÑÑ‚ÑŽ заборонений: -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">Вихідні з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ñ– мережею Tor (-onlynet=onion), але прокÑÑ–-Ñервер Ð´Ð»Ñ Ð´Ð¾Ñтупу до мережі Tor не призначено: не вказано ні -proxy, ні -onion, ані -listenonion</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">ВиÑвлено нерозпізнаний деÑкриптор. Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ %s
+
+Можливо, гаманець було Ñтворено новішою верÑією.
+Спробуйте найновішу верÑÑ–ÑŽ програми.
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">Ðепідтримуваний категорійний рівень Ð¶ÑƒÑ€Ð½Ð°Ð»ÑŽÐ²Ð°Ð½Ð½Ñ -loglevel=%s. ОчікуєтьÑÑ -loglevel=&lt;category&gt;:&lt;loglevel&gt;. ПрипуÑтимі категорії: %s. ПрипуÑтимі рівні: %s.</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+Ðе вдалоÑÑ Ð¾Ñ‡Ð¸Ñтити помилкове перенеÑеннÑ</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Ðе вдалоÑÑ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ резервну копію гаманцÑ.</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ— %s заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ Ð´Ð»Ñ Ð¼ÐµÑ€ÐµÐ¶Ñ– %s у розділі [%s].</translation>
</message>
@@ -737,8 +837,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Помилка Ð·Ñ‡Ð¸Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ñтупного запиÑу з бази даних гаманцÑ</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">Помилка Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð±Ð°Ð·Ð¸ даних Ñтану ланцюжка</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">Помилка: Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ транзакцію "тільки переглÑд" до гаманцÑ-длÑ-переглÑду</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">Помилка: Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ транзакції "тільки переглÑд"</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
@@ -753,6 +857,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Помилка: Контрольна Ñума файлу дампа не збігаєтьÑÑ. ОбчиÑлено %s, очікуєтьÑÑ %s</translation>
</message>
<message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">Помилка: Ðе вдалоÑÑ Ñтворити новий гаманець-длÑ-переглÑду</translation>
+ </message>
+ <message>
<source>Error: Got key that was not hex: %s</source>
<translation type="unfinished">Помилка: Отримано ключ, що не є hex: %s</translation>
</message>
@@ -773,10 +881,38 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Помилка: Ðемає доÑтупних %s адреÑ.</translation>
</message>
<message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">Помилка: Ðе вÑÑ– транзакції "тільки переглÑд" вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">Помилка; Цей гаманець вже викориÑтовує SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">Помилка: Цей гаманець вже Ñ” гаманцем на оÑнові деÑкрипторів</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">Помилка: Ðе вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ð¾Ñ‡Ð°Ñ‚Ð¸ Ð·Ñ‡Ð¸Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²ÑÑ–Ñ… запиÑів бази даних</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">Помилка: Ðе вдалоÑÑ Ð·Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ резервну копію гаманцÑ.</translation>
+ </message>
+ <message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">Помилка: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ð°Ð½Ð°Ð»Ñ–Ð·ÑƒÐ²Ð°Ñ‚Ð¸ верÑÑ–ÑŽ %u Ñк uint32_t</translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">Помилка: Ðе вдалоÑÑ Ð·Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ вÑÑ– запиÑи бази даних</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">Помилка: Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ дані "тільки переглÑд" з адреÑної книги</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
<translation type="unfinished">Помилка: Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾ нового гаманцÑ</translation>
</message>
@@ -850,13 +986,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
- <translation type="unfinished">Вказано некоректну Ñуму Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñƒ -paytxfee: «%s» (повинно бути щонайменше %s)</translation>
+ <translation type="unfinished">Вказано некоректну Ñуму Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° -paytxfee=&lt;amount&gt;: '%s' (повинно бути щонайменше %s)</translation>
</message>
<message>
<source>Invalid netmask specified in -whitelist: '%s'</source>
<translation type="unfinished">Вказано неправильну маÑку підмережі Ð´Ð»Ñ -whitelist: «%s»</translation>
</message>
<message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ñ‚Ð¸ проÑÐ»ÑƒÑ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ…Ñ–Ð´Ð½Ð¸Ñ… підключень (listen повернув помилку %s)</translation>
+ </message>
+ <message>
<source>Loading P2P addresses…</source>
<translation type="unfinished">Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ P2P адреÑ…</translation>
</message>
@@ -889,20 +1029,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðемає доÑтупних адреÑ</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Ðе вказано прокÑÑ–-Ñервер. ВикориÑтовуйте -proxy=&lt;ip&gt; або -proxy=&lt;ip:port&gt;.</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">Бракує доÑтупних деÑкрипторів файлів.</translation>
</message>
<message>
<source>Prune cannot be configured with a negative value.</source>
- <translation type="unfinished">Розмір Ñкороченого ланцюжка блоків не може бути від'ємним.</translation>
- </message>
- <message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">Режим Ñкороченого блокчейна неÑуміÑний з -coinstatsindex.</translation>
+ <translation type="unfinished">Розмір Ñкороченого блокчейна не може бути від'ємним.</translation>
</message>
<message>
<source>Prune mode is incompatible with -txindex.</source>
@@ -1010,7 +1142,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Transaction has too long of a mempool chain</source>
- <translation type="unfinished">Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ñ–Ñ Ð¼Ð°Ñ” занадто довгий ланцюг у пулі</translation>
+ <translation type="unfinished">Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ñ–Ñ Ð¼Ð°Ñ” занадто довгий ланцюг у пулі транзакцій</translation>
</message>
<message>
<source>Transaction must have at least one recipient</source>
@@ -1025,24 +1157,32 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ñ–Ñ Ð·Ð°Ð½Ð°Ð´Ñ‚Ð¾ велика</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð²Ð¸Ð´Ñ–Ð»Ð¸Ñ‚Ð¸ пам'ÑÑ‚ÑŒ Ð´Ð»Ñ -maxsigcachesize: '%s' МіБ</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
- <translation type="unfinished">Ðеможливо прив'ÑзатиÑÑ Ð´Ð¾ %s на цьому комп'ютері (bind повернув помилку: %s)</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð¿Ñ€Ð¸Ð²'ÑзатиÑÑ Ð´Ð¾ %s на цьому комп'ютері (bind повернув помилку: %s)</translation>
</message>
<message>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
- <translation type="unfinished">Ðеможливо прив'Ñзати %s на цьому комп'ютері. %s, ймовірно, вже працює.</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð¿Ñ€Ð¸Ð²'Ñзати %s на цьому комп'ютері. %s, ймовірно, вже працює.</translation>
</message>
<message>
<source>Unable to create the PID file '%s': %s</source>
- <translation type="unfinished">Ðеможливо Ñтворити PID файл '%s' :%s</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ñтворити PID файл '%s' :%s</translation>
+ </message>
+ <message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ UTXO Ð´Ð»Ñ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½ÑŒÐ¾Ð³Ð¾ входу</translation>
</message>
<message>
<source>Unable to generate initial keys</source>
- <translation type="unfinished">Ðе вдаєтьÑÑ Ñтворити початкові ключі</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ñтворити початкові ключі</translation>
</message>
<message>
<source>Unable to generate keys</source>
- <translation type="unfinished">Ðе вдаєтьÑÑ Ñтворити ключі</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ñтворити ключі</translation>
</message>
<message>
<source>Unable to open %s for writing</source>
@@ -1054,7 +1194,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unable to start HTTP server. See debug log for details.</source>
- <translation type="unfinished">Ðеможливо запуÑтити HTTP-Ñервер. Детальніший Ð¾Ð¿Ð¸Ñ Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð¾ в журналі зневадженнÑ.</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити HTTP-Ñервер. Детальніший Ð¾Ð¿Ð¸Ñ Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð¾ в журналі зневадженнÑ.</translation>
+ </message>
+ <message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð²Ð¸Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ гаманець перед перенеÑеннÑм</translation>
</message>
<message>
<source>Unknown -blockfilterindex value %s.</source>
@@ -1077,12 +1221,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ðктивовані невідомі нові правила (versionbit %i)</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">Ðепідтримувана ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ñƒ %s=%s.</translation>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">Ðепідтримуваний глобальний рівень Ð¶ÑƒÑ€Ð½Ð°Ð»ÑŽÐ²Ð°Ð½Ð½Ñ -loglevel=%s. ПрипуÑтимі значеннÑ: %s.</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð±Ð°Ð·Ð¸ даних UTXO</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">Ðепідтримувана ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ñƒ %s=%s.</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
@@ -1194,7 +1338,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Encrypt Wallet…</source>
- <translation type="unfinished">За&amp;шифрувати гаманець…</translation>
+ <translation type="unfinished">&amp;Шифрувати Гаманець...</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
@@ -1206,23 +1350,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Change Passphrase…</source>
- <translation type="unfinished">Змінити парол&amp;ь…</translation>
+ <translation type="unfinished">Змінити парол&amp;ь...</translation>
</message>
<message>
<source>Sign &amp;message…</source>
- <translation type="unfinished">&amp;ПідпиÑати повідомленнÑ…</translation>
+ <translation type="unfinished">&amp;ПідпиÑати повідомленнÑ...</translation>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation type="unfinished">Підтвердіть, що ви Ñ” влаÑником Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ–Ð´Ð¿Ð¸Ñавши його вашою Bitcoin-адреÑою</translation>
+ <translation type="unfinished">Підтвердіть, що Ви Ñ” влаÑником повідомленнÑ, підпиÑавши його Вашою біткоїн-адреÑою</translation>
</message>
<message>
<source>&amp;Verify message…</source>
- <translation type="unfinished">П&amp;еревірити повідомленнÑ…</translation>
+ <translation type="unfinished">П&amp;еревірити повідомленнÑ...</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation type="unfinished">Перевірте Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²Ð¿ÐµÐ²Ð½ÐµÐ½Ð¾ÑÑ‚Ñ–, що воно підпиÑано вказаною Bitcoin-адреÑою</translation>
+ <translation type="unfinished">Перевірте Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²Ð¿ÐµÐ²Ð½ÐµÐ½Ð¾ÑÑ‚Ñ–, що воно підпиÑано вказаною біткоїн-адреÑою</translation>
</message>
<message>
<source>&amp;Load PSBT from file…</source>
@@ -1234,15 +1378,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Close Wallet…</source>
- <translation type="unfinished">Закрити Гаманець…</translation>
+ <translation type="unfinished">Закрити гаманець…</translation>
</message>
<message>
<source>Create Wallet…</source>
- <translation type="unfinished">Створити Гаманець…</translation>
+ <translation type="unfinished">Створити гаманець…</translation>
</message>
<message>
<source>Close All Wallets…</source>
- <translation type="unfinished">Закрити Ð’ÑÑ– Гаманці…</translation>
+ <translation type="unfinished">Закрити вÑÑ– гаманці…</translation>
</message>
<message>
<source>&amp;File</source>
@@ -1341,10 +1485,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Синхронізовано</translation>
</message>
<message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">Завантажити чаÑтково підпиÑану біткоїн-транзакцію (PSBT)</translation>
+ </message>
+ <message>
<source>Load PSBT from &amp;clipboard…</source>
<translation type="unfinished">Завантажити PSBT-транзакцію з &amp;буфера обміну…</translation>
</message>
<message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">Завантажити чаÑтково підпиÑану біткоїн-транзакцію (PSBT) з буфера обміну</translation>
+ </message>
+ <message>
<source>Node window</source>
<translation type="unfinished">Вікно вузла</translation>
</message>
@@ -1377,6 +1529,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Закрити гаманець</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Відновити гаманець…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Відновити гаманець з файлу резервної копії</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Закрити вÑÑ– гаманці</translation>
</message>
@@ -1386,7 +1548,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Mask values</source>
- <translation type="unfinished">&amp;Приховати значеннÑ</translation>
+ <translation type="unfinished">При&amp;ховати значеннÑ</translation>
</message>
<message>
<source>Mask the values in the Overview tab</source>
@@ -1401,6 +1563,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Гаманців немає</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">Файл гаманцÑ</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Завантажити резервну копію гаманцÑ</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Відновити гаманець</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Ðазва гаманцÑ</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Вікно</translation>
</message>
@@ -1428,9 +1610,9 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform>%n активне з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· мережею Bitcoin</numerusform>
- <numerusform>%n активних з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· мережею Bitcoin</numerusform>
- <numerusform>%n активних з'єднань з мережею Bitcoin</numerusform>
+ <numerusform>%n активне з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· мережею Біткоїн.</numerusform>
+ <numerusform>%n активних з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· мережею Біткоїн.</numerusform>
+ <numerusform>%n активних з'єднань з мережею Біткоїн.</numerusform>
</translation>
</message>
<message>
@@ -1454,6 +1636,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Увімкнути мережеву активніÑÑ‚ÑŒ</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Триває Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½Ñ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÑ–Ð² (%1%)…</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Помилка: %1</translation>
</message>
@@ -1716,6 +1902,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">Ðеможливо показати зовнішні підпиÑувачі</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Знайдено забагато зовнішних підпиÑувачів</translation>
+ </message>
</context>
<context>
<name>LoadWalletsActivity</name>
@@ -1756,6 +1946,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Відновити гаманець</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ &lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Помилка Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">ÐŸÐ¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ–Ð´ Ñ‡Ð°Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1786,7 +2004,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Wallet Name</source>
- <translation type="unfinished">Ðазва ГаманцÑ</translation>
+ <translation type="unfinished">Ðазва гаманцÑ</translation>
</message>
<message>
<source>Wallet</source>
@@ -1794,7 +2012,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
- <translation type="unfinished">Зашифруйте гаманець. Гаманець буде зашифрований за допомогою Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð½Ð° ваш вибір.</translation>
+ <translation type="unfinished">Зашифрувати гаманець. Гаманець буде зашифрований за допомогою обраного вами паролÑ.</translation>
</message>
<message>
<source>Encrypt Wallet</source>
@@ -1806,7 +2024,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
- <translation type="unfinished">Вимкнути приватні ключі Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ гаманцÑ. Гаманці з вимкнутими приватними ключами не матимуть приватних ключів Ñ– не можуть мати набір HD або імпортовані приватні ключі. Це ідеально підходить лише Ð´Ð»Ñ Ñ‚Ñ–Ð»ÑŒÐºÐ¸-оглÑд гаманців.</translation>
+ <translation type="unfinished">Вимкнути приватні ключі Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ гаманцÑ. Гаманці з вимкнутими приватними ключами не матимуть приватних ключів Ñ– не можуть мати набір HD-генератор або імпортовані приватні ключі. Це ідеально підходить Ð´Ð»Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ–Ð²-длÑ-переглÑду.</translation>
</message>
<message>
<source>Disable Private Keys</source>
@@ -1814,7 +2032,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
- <translation type="unfinished">Зробіть порожній гаманець. Порожні гаманці Ñпочатку не мають приватних ключів або Ñценаріїв. Пізніше можна імпортувати приватні ключі та адреÑи або вÑтановити HD-наÑіннÑ.</translation>
+ <translation type="unfinished">Створити пуÑтий гаманець. ПуÑÑ‚Ñ– гаманці Ñпочатку не мають приватних ключів або Ñкриптів. Пізніше можна імпортувати приватні ключі та адреÑи або вÑтановити HD-генератор.</translation>
</message>
<message>
<source>Make Blank Wallet</source>
@@ -1822,11 +2040,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Use descriptors for scriptPubKey management</source>
- <translation type="unfinished">ВикориÑтовуйте деÑкриптори Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ scriptPubKey</translation>
+ <translation type="unfinished">ВикориÑтовувати деÑкриптори Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ scriptPubKey</translation>
</message>
<message>
<source>Descriptor Wallet</source>
- <translation type="unfinished">Гаманець на базі деÑкрипторів</translation>
+ <translation type="unfinished">Гаманець на оÑнові деÑкрипторів</translation>
</message>
<message>
<source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
@@ -1842,12 +2060,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Compiled without sqlite support (required for descriptor wallets)</source>
- <translation type="unfinished">Зкомпільовано без підтримки sqlite (потрібно Ð´Ð»Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ–Ð² деÑкрипторів)</translation>
+ <translation type="unfinished">Скомпільовано без підтримки sqlite (потрібно Ð´Ð»Ñ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ–Ð² на оÑнові деÑкрипторів)</translation>
</message>
<message>
<source>Compiled without external signing support (required for external signing)</source>
<extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
- <translation type="unfinished">Скомпільовано без підтримки зовнішнього підпиÑуваннÑ</translation>
+ <translation type="unfinished">Скомпільовано без підтримки зовнішнього підпиÑÑƒÐ²Ð°Ð½Ð½Ñ (потрібно Ð´Ð»Ñ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½ÑŒÐ¾Ð³Ð¾ підпиÑуваннÑ)</translation>
</message>
</context>
<context>
@@ -1886,7 +2104,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>The entered address "%1" is not a valid Bitcoin address.</source>
- <translation type="unfinished">Введена адреÑа "%1" не Ñ” дійÑною Bitcoin адреÑою.</translation>
+ <translation type="unfinished">Введена адреÑа "%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>
@@ -1930,17 +2148,29 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
- <message>
- <source>%1 GB of space available</source>
- <translation type="unfinished">ДоÑтупно %1 ГБ</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>ДоÑтупний проÑÑ‚Ñ–Ñ€: %n ГБ</numerusform>
+ <numerusform>ДоÑтупний проÑÑ‚Ñ–Ñ€: %n ГБ</numerusform>
+ <numerusform>ДоÑтупний проÑÑ‚Ñ–Ñ€: %n ГБ</numerusform>
+ </translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(з %1 ГБ, що потрібно)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(в той чаÑ, Ñк необхідно %n ГБ)</numerusform>
+ <numerusform>(в той чаÑ, Ñк необхідно %n ГБ)</numerusform>
+ <numerusform>(в той чаÑ, Ñк необхідно %n ГБ)</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(%1 ГБ, необхідних Ð´Ð»Ñ Ð¿Ð¾Ð²Ð½Ð¾Ð³Ð¾ блокчейну)</translation>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n ГБ необхідно Ð´Ð»Ñ Ð¿Ð¾Ð²Ð½Ð¾Ð³Ð¾ блокчейну)</numerusform>
+ <numerusform>(%n ГБ необхідно Ð´Ð»Ñ Ð¿Ð¾Ð²Ð½Ð¾Ð³Ð¾ блокчейну)</numerusform>
+ <numerusform>(%n ГБ необхідно Ð´Ð»Ñ Ð¿Ð¾Ð²Ð½Ð¾Ð³Ð¾ блокчейну)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1988,10 +2218,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ОÑкільки це перший запуÑк програми, ви можете обрати, де %1 буде зберігати дані.</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 type="unfinished">ПіÑÐ»Ñ Ð½Ð°Ñ‚Ð¸ÑÐºÐ°Ð½Ð½Ñ ÐºÐ½Ð¾Ð¿ÐºÐ¸ «OK» %1 почне завантажувати та оброблÑти повний ланцюжок блоків %4 (%2 ГБ), починаючи з найбільш ранніх транзакцій у %3, коли було запущено %4.</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">Скоротити міÑце під блоки до</translation>
</message>
@@ -2008,8 +2234,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ð¦Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÐ¾Ð²Ð° ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ñ” дуже вимогливою, Ñ– може виÑвити проблеми з апаратним забезпеченнÑм комп'ютера, Ñкі раніше не були непоміченими. Кожен раз, коли ви запуÑкаєте %1, він буде продовжувати Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ‚Ð°Ð¼, де він зупинивÑÑ.</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">ПіÑÐ»Ñ Ð½Ð°Ñ‚Ð¸ÑÐºÐ°Ð½Ð½Ñ ÐºÐ½Ð¾Ð¿ÐºÐ¸ «OK» %1 почне завантажувати та оброблÑти повний блокчейн %4 (%2 ГБ), починаючи з найбільш ранніх транзакцій у %3, коли було запущено %4.</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 type="unfinished">Якщо ви вирішили обмежити Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð»Ð°Ð½Ñ†ÑŽÐ¶ÐºÐ° блоків (відÑіканнÑ), Ñ–Ñторичні дані повинні бути завантажені та оброблені, але потім можуть бути видалені, щоб зберегти потрібний проÑÑ‚Ñ–Ñ€ диÑка.</translation>
+ <translation type="unfinished">Якщо ви вирішили обмежити обÑÑг Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð±Ð»Ð¾ÐºÑ‡ÐµÐ¹Ð½Ð°, Ñ–Ñторичні дані повинні бути завантажені та оброблені, але потім можуть бути видалені, щоб зберегти потрібний проÑÑ‚Ñ–Ñ€ диÑка.</translation>
</message>
<message>
<source>Use the default data directory</source>
@@ -2054,7 +2284,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">Ðещодавні транзакції ще не відображаютьÑÑ, тому Ð±Ð°Ð»Ð°Ð½Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ Ð¼Ð¾Ð¶Ðµ бути неточним. Ð¦Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð±ÑƒÐ´Ðµ вірною піÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк ваш гаманець завершить Ñинхронізацію з мережею Біткоїн, враховуйте показники нижче.</translation>
+ <translation type="unfinished">Ðещодавні транзакції ще не відображаютьÑÑ, тому Ð±Ð°Ð»Ð°Ð½Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ Ð³Ð°Ð¼Ð°Ð½Ñ†Ñ Ð¼Ð¾Ð¶Ðµ бути неточним. Ð¦Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð±ÑƒÐ´Ðµ вірною піÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк ваш гаманець завершить Ñинхронізацію з мережею Біткоїн (дивітьÑÑ Ð½Ð¸Ð¶Ñ‡Ðµ).</translation>
</message>
<message>
<source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
@@ -2078,11 +2308,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Progress</source>
- <translation type="unfinished">ПрогреÑ</translation>
+ <translation type="unfinished">Перебіг Ñинхронізації</translation>
</message>
<message>
<source>Progress increase per hour</source>
- <translation type="unfinished">ÐŸÑ€Ð¾Ð³Ñ€ÐµÑ Ð·Ð° годину</translation>
+ <translation type="unfinished">ÐŸÑ€Ð¾Ð³Ñ€ÐµÑ Ñинхронізації за годину</translation>
</message>
<message>
<source>Estimated time left until synced</source>
@@ -2098,7 +2328,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
- <translation type="unfinished">Ðевідомо. Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÑ–Ð² (%1, %2%)…</translation>
+ <translation type="unfinished">Ðевідомо. Триває ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÑ–Ð² (%1, %2%)…</translation>
+ </message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Ðевідомо. Триває Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½Ñ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÑ–Ð² (%1, %2%)…</translation>
</message>
</context>
<context>
@@ -2129,7 +2363,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Start %1 on system login</source>
- <translation type="unfinished">&amp;ЗапуÑкати %1 при вході в ÑиÑтему</translation>
+ <translation type="unfinished">ЗапуÑкати %1 при в&amp;ході в ÑиÑтему</translation>
</message>
<message>
<source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
@@ -2137,7 +2371,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Size of &amp;database cache</source>
- <translation type="unfinished">Розмір &amp;кешу бази даних</translation>
+ <translation type="unfinished">Розмір ке&amp;шу бази даних</translation>
</message>
<message>
<source>Number of script &amp;verification threads</source>
@@ -2156,6 +2390,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Згортати заміÑÑ‚ÑŒ закриттÑ. Якщо Ñ†Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°, програма закриєтьÑÑ Ð»Ð¸ÑˆÐµ піÑÐ»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ відповідного пункту в меню.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Параметри, Ñкі задані в цьому вікні, змінені командним Ñ€Ñдком:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Відкрийте %1 файл конфігурації з робочого каталогу.</translation>
</message>
@@ -2185,7 +2423,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain.</source>
- <translation type="unfinished">ÐŸÐ¾Ð²ÐµÑ€Ð½ÐµÐ½Ð½Ñ Ñ†Ñ–Ñ”Ñ— опції вимагає Ð¿ÐµÑ€ÐµÐ·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²ÑŒÐ¾Ð³Ð¾ ланцюжка блоків.</translation>
+ <translation type="unfinished">ÐŸÐ¾Ð²ÐµÑ€Ð½ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ параметра вимагає Ð¿ÐµÑ€ÐµÐ·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²ÑŒÐ¾Ð³Ð¾ блокчейна.</translation>
</message>
<message>
<source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
@@ -2213,7 +2451,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Enable R&amp;PC server</source>
<extracomment>An Options window setting to enable the RPC server.</extracomment>
- <translation type="unfinished">Увімкнути RPC &amp;Ñервер</translation>
+ <translation type="unfinished">Увімкнути RPC Ñе&amp;рвер</translation>
</message>
<message>
<source>W&amp;allet</source>
@@ -2227,7 +2465,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Subtract &amp;fee from amount by default</source>
<extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
- <translation type="unfinished">За замовчуваннÑм віднімати &amp;коміÑÑ–ÑŽ від Ñуми відправленнÑ.</translation>
+ <translation type="unfinished">За замовчуваннÑм віднімати &amp;коміÑÑ–ÑŽ від Ñуми відправленнÑ</translation>
</message>
<message>
<source>Expert</source>
@@ -2235,7 +2473,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Enable coin &amp;control features</source>
- <translation type="unfinished">Ввімкнути &amp;ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ…Ð¾Ð´Ð°Ð¼Ð¸</translation>
+ <translation type="unfinished">Ввімкнути ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð²&amp;ходами</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>
@@ -2243,12 +2481,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
- <translation type="unfinished">&amp;Витрачати непідтверджену решту</translation>
+ <translation type="unfinished">Витрачати непідтверджену &amp;решту</translation>
</message>
<message>
<source>Enable &amp;PSBT controls</source>
<extracomment>An options window setting to enable PSBT controls.</extracomment>
- <translation type="unfinished">Увімкнути елементи ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ &amp;PSBT</translation>
+ <translation type="unfinished">Увімкнути функції &amp;чаÑтково підпиÑаних біткоїн-транзакцій (PSBT)</translation>
</message>
<message>
<source>Whether to show PSBT controls.</source>
@@ -2261,7 +2499,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;External signer script path</source>
- <translation type="unfinished">ШлÑÑ… до Ñкрипту &amp;зовнішнього підпиÑувача</translation>
+ <translation type="unfinished">&amp;ШлÑÑ… до Ñкрипту зовнішнього підпиÑувача</translation>
</message>
<message>
<source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
@@ -2293,7 +2531,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
- <translation type="unfinished">ÐŸÑ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ мережі Bitcoin через SOCKS5 прокÑÑ–.</translation>
+ <translation type="unfinished">ÐŸÑ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ мережі Біткоїн через SOCKS5 прокÑÑ–.</translation>
</message>
<message>
<source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
@@ -2325,7 +2563,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Show tray icon</source>
- <translation type="unfinished">&amp;Показувати піктограму у ÑиÑтемному треї</translation>
+ <translation type="unfinished">Показувати &amp;піктограму у ÑиÑтемному треї</translation>
</message>
<message>
<source>Show only a tray icon after minimizing the window.</source>
@@ -2333,11 +2571,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Minimize to the tray instead of the taskbar</source>
- <translation type="unfinished">Мінімізувати &amp;у трей</translation>
+ <translation type="unfinished">Мінімізувати у &amp;трей</translation>
</message>
<message>
<source>M&amp;inimize on close</source>
- <translation type="unfinished">Згортати заміÑÑ‚ÑŒ закритт&amp;Ñ</translation>
+ <translation type="unfinished">Зго&amp;ртати заміÑÑ‚ÑŒ закриттÑ</translation>
</message>
<message>
<source>&amp;Display</source>
@@ -2392,17 +2630,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">найбільш подібний "%1"</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Параметри, Ñкі задані в цьому вікні, змінені командним Ñ€Ñдком або у файлі конфігурації:</translation>
- </message>
- <message>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;СкаÑувати</translation>
</message>
<message>
<source>Compiled without external signing support (required for external signing)</source>
<extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
- <translation type="unfinished">Скомпільовано без підтримки зовнішнього підпиÑуваннÑ</translation>
+ <translation type="unfinished">Скомпільовано без підтримки зовнішнього підпиÑÑƒÐ²Ð°Ð½Ð½Ñ (потрібно Ð´Ð»Ñ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½ÑŒÐ¾Ð³Ð¾ підпиÑуваннÑ)</translation>
</message>
<message>
<source>default</source>
@@ -2414,14 +2648,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">ÐŸÑ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ ÑÐºÐ¸Ð´Ð°Ð½Ð½Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñ–Ð²</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Ð”Ð»Ñ Ð·Ð°ÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð¼Ñ–Ð½ необхідно перезапуÑтити клієнта.</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished"> Поточні параметри будуть збережені в "%1".</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">Клієнт буде закрито. Продовжити?</translation>
</message>
<message>
@@ -2432,7 +2674,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<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>
<extracomment>Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</extracomment>
- <translation type="unfinished">Файл конфігурації викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð²ÐºÐ°Ð·ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¸Ñ… параметрів кориÑтувача, що перекривають наÑтройки графічного інтерфейÑу кориÑтувача. Крім того, будь-Ñкі параметри командного Ñ€Ñдка замінÑÑ‚ÑŒ цей конфігураційний файл.</translation>
+ <translation type="unfinished">Файл конфігурації викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð²ÐºÐ°Ð·ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¸Ñ… параметрів, що перевизначають параметри графічного інтерфейÑу. Крім того, будь-Ñкі параметри командного Ñ€Ñдка перевизначать цей конфігураційний файл.</translation>
</message>
<message>
<source>Continue</source>
@@ -2460,6 +2702,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ параметр "%1", %2.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2471,7 +2720,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Watch-only:</source>
- <translation type="unfinished">Тільки ÑпоÑтереженнÑ:</translation>
+ <translation type="unfinished">Тільки переглÑд:</translation>
</message>
<message>
<source>Available:</source>
@@ -2511,7 +2760,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Your current balance in watch-only addresses</source>
- <translation type="unfinished">Ваш поточний Ð±Ð°Ð»Ð°Ð½Ñ Ð² адреÑах Ð´Ð»Ñ ÑпоÑтереженнÑ</translation>
+ <translation type="unfinished">Ваш поточний Ð±Ð°Ð»Ð°Ð½Ñ Ð² адреÑах "тільки переглÑд"</translation>
</message>
<message>
<source>Spendable:</source>
@@ -2523,15 +2772,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unconfirmed transactions to watch-only addresses</source>
- <translation type="unfinished">Ðепідтверджені транзакції на адреÑи Ð´Ð»Ñ ÑпоÑтереженнÑ</translation>
+ <translation type="unfinished">Ðепідтверджені транзакції на адреÑи "тільки переглÑд"</translation>
</message>
<message>
<source>Mined balance in watch-only addresses that has not yet matured</source>
- <translation type="unfinished">Ð‘Ð°Ð»Ð°Ð½Ñ Ð²Ð¸Ð´Ð¾Ð±ÑƒÑ‚Ð¸Ñ… монет, що не доÑÑгли завершеноÑÑ‚Ñ–, на адреÑах Ð´Ð»Ñ ÑпоÑтереженнÑ</translation>
+ <translation type="unfinished">Ð‘Ð°Ð»Ð°Ð½Ñ Ð²Ð¸Ð´Ð¾Ð±ÑƒÑ‚Ð¸Ñ… монет, що не доÑÑгли завершеноÑÑ‚Ñ–, на адреÑах "тільки переглÑд"</translation>
</message>
<message>
<source>Current total balance in watch-only addresses</source>
- <translation type="unfinished">Поточний Ñукупний Ð±Ð°Ð»Ð°Ð½Ñ Ð² адреÑах Ð´Ð»Ñ ÑпоÑтереженнÑ</translation>
+ <translation type="unfinished">Поточний Ñукупний Ð±Ð°Ð»Ð°Ð½Ñ Ð² адреÑах "тільки переглÑд"</translation>
</message>
<message>
<source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
@@ -2611,7 +2860,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message>
<source>Partially Signed Transaction (Binary)</source>
<extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
- <translation type="unfinished">ЧаÑтково підпиÑана Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ñ–Ñ (Binary)</translation>
+ <translation type="unfinished">ЧаÑтково підпиÑана біткоїн-Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ñ–Ñ (бінарний файл)</translation>
</message>
<message>
<source>PSBT saved to disk.</source>
@@ -2623,7 +2872,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Unable to calculate transaction fee or total transaction amount.</source>
- <translation type="unfinished">Ðеможливо розрахувати коміÑÑ–ÑŽ за транзакцію або загальну Ñуму транзакції.</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ñ€Ð¾Ð·Ñ€Ð°Ñ…ÑƒÐ²Ð°Ñ‚Ð¸ коміÑÑ–ÑŽ за транзакцію або загальну Ñуму транзакції.</translation>
</message>
<message>
<source>Pays transaction fee: </source>
@@ -2723,6 +2972,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">УчаÑник</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">ТриваліÑÑ‚ÑŒ</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">ÐапрÑмок</translation>
@@ -2923,29 +3177,32 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Whether we relay addresses to this peer.</source>
- <extracomment>Tooltip text for the Address Relay field in the peer details area.</extracomment>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">Чи ретранÑлювати адреÑи цьому учаÑнику.</translation>
</message>
<message>
<source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished">РетранÑÐ»ÑŽÐ²Ð°Ð½Ð½Ñ Ð°Ð´Ñ€ÐµÑ</translation>
</message>
<message>
- <source>Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Processed field in the peer details area.</extracomment>
- <translation type="unfinished">Загальна кількіÑÑ‚ÑŒ оброблених Ð°Ð´Ñ€ÐµÑ Ð·Ð° винÑтком пропущених через Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡Ð°Ñтоти.</translation>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Загальна кількіÑÑ‚ÑŒ отриманих від цього учаÑника адреÑ, що були оброблені (за винÑтком адреÑ, пропущених через Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‚ÐµÐ¼Ð¿Ñƒ).</translation>
</message>
<message>
- <source>Addresses Processed</source>
- <translation type="unfinished">ÐÐ´Ñ€ÐµÑ Ð¾Ð±Ñ€Ð¾Ð±Ð»ÐµÐ½Ð¾</translation>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Загальна кількіÑÑ‚ÑŒ отриманих від цього учаÑника адреÑ, що були пропущені (не оброблені) через Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‚ÐµÐ¼Ð¿Ñƒ.</translation>
</message>
<message>
- <source>Total number of addresses dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area.</extracomment>
- <translation type="unfinished">Загальна кількіÑÑ‚ÑŒ адреÑ, пропущених через Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡Ð°Ñтоти.</translation>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">ÐÐ´Ñ€ÐµÑ Ð¾Ð±Ñ€Ð¾Ð±Ð»ÐµÐ½Ð¾</translation>
</message>
<message>
<source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
<translation type="unfinished">ÐÐ´Ñ€ÐµÑ Ð¿Ñ€Ð¾Ð¿ÑƒÑ‰ÐµÐ½Ð¾</translation>
</message>
<message>
@@ -2954,7 +3211,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<source>Node window</source>
- <translation type="unfinished">Вікно вузлів</translation>
+ <translation type="unfinished">Вікно вузла</translation>
</message>
<message>
<source>Current block height</source>
@@ -3252,7 +3509,7 @@ For more information on using this console, type %6.
</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 type="unfinished">Ðеобов'Ñзкове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ð° додаток до запиту платежу, котре буде показане під Ñ‡Ð°Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ. Примітка: Це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ðµ буде відправлено з платежем через мережу Bitcoin.</translation>
+ <translation type="unfinished">Ðеобов'Ñзкове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ð° додаток до запиту платежу, Ñке буде показане під Ñ‡Ð°Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ. Примітка: це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ðµ буде відправлено з платежем через мережу Біткоїн.</translation>
</message>
<message>
<source>An optional label to associate with the new receiving address.</source>
@@ -3581,7 +3838,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Copy amount</source>
- <translation type="unfinished">Копіювати Ñуму</translation>
+ <translation type="unfinished">Скопіювати Ñуму</translation>
</message>
<message>
<source>Copy fee</source>
@@ -3722,7 +3979,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Watch-only balance:</source>
- <translation type="unfinished">Ð‘Ð°Ð»Ð°Ð½Ñ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ ÑпоÑтереженнÑ:</translation>
+ <translation type="unfinished">Ð‘Ð°Ð»Ð°Ð½Ñ "тільки переглÑд":</translation>
</message>
<message>
<source>The recipient address is not valid. Please recheck.</source>
@@ -3752,10 +4009,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">КоміÑÑ–Ñ Ð±Ñ–Ð»ÑŒÑˆÐ°, ніж %1, вважаєтьÑÑ Ð°Ð±Ñурдно виÑокою.</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Запит платежу проÑтрочено.</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -3805,7 +4058,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>The Bitcoin address to send the payment to</source>
- <translation type="unfinished">ÐдреÑа Bitcoin Ð´Ð»Ñ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð»Ð°Ñ‚ÐµÐ¶Ñƒ</translation>
+ <translation type="unfinished">Біткоїн-адреÑа Ð´Ð»Ñ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð»Ð°Ñ‚ÐµÐ¶Ñƒ</translation>
</message>
<message>
<source>Paste address from clipboard</source>
@@ -3836,28 +4089,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">ПовідомленнÑ:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Цей запит платежу не є автентифікованим.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Цей запит платежу є автентифікованим.</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">Введіть мітку Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— адреÑи Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ—Ñ— в ÑпиÑок викориÑтаних адреÑ</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 type="unfinished">ПовідомленнÑ, що було додане до bitcoin:URI та буде збережено разом з транзакцією Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ð´ÐºÐ¸. Примітка: Це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ðµ буде відправлено в мережу Bitcoin.</translation>
- </message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Отримувач:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Ðотатка:</translation>
+ <translation type="unfinished">ПовідомленнÑ, що було додане до bitcoin:URI та буде збережено разом з транзакцією Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ð´ÐºÐ¸. Примітка: це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ðµ буде відправлено в мережу Біткоїн.</translation>
</message>
</context>
<context>
@@ -4036,30 +4273,32 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">конфліктує з транзакцією із %1 підтвердженнÑми</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/не підтверджено, %1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">у пулі транзакцій</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/не підтверджено, в пулі транзакцій</translation>
</message>
<message>
- <source>not in memory pool</source>
- <translation type="unfinished">не в пулі транзакцій</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/не підтверджено, не в пулі транзакцій</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">відкинуто</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/не підтверджено</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 підтверджень</translation>
</message>
<message>
@@ -4096,7 +4335,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>watch-only</source>
- <translation type="unfinished">тільки ÑпоÑтереженнÑ</translation>
+ <translation type="unfinished">тільки переглÑд</translation>
</message>
<message>
<source>label</source>
@@ -4172,7 +4411,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</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 type="unfinished">Згенеровані монети Ñтануть доÑтупні Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ–ÑÐ»Ñ %1 підтверджень. Коли ви згенерували цей блок, його було відправлено в мережу Ð´Ð»Ñ Ð²Ð½ÐµÑÐµÐ½Ð½Ñ Ð´Ð¾ ланцюжку блоків. Якщо блок не буде додано до ланцюжку блоків, його ÑÑ‚Ð°Ñ‚ÑƒÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚ÑŒÑÑ Ð½Ð° «не підтверджено», Ñ– згенеровані монети неможливо буде витратити. Таке чаÑом траплÑєтьÑÑ, Ñкщо хтоÑÑŒ згенерував інший блок на декілька Ñекунд раніше.</translation>
+ <translation type="unfinished">Згенеровані монети Ñтануть доÑтупні Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ–ÑÐ»Ñ %1 підтверджень. Коли ви згенерували цей блок, його було відправлено в мережу Ð´Ð»Ñ Ð¿Ñ€Ð¸Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð´Ð¾ блокчейна. Якщо блок не буде додано до блокчейна, його ÑÑ‚Ð°Ñ‚ÑƒÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚ÑŒÑÑ Ð½Ð° «не підтверджено», Ñ– згенеровані монети неможливо буде витратити. Таке чаÑом траплÑєтьÑÑ, Ñкщо хтоÑÑŒ згенерував інший блок на декілька Ñекунд раніше.</translation>
</message>
<message>
<source>Debug information</source>
@@ -4274,7 +4513,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>watch-only</source>
- <translation type="unfinished">тільки ÑпоÑтереженнÑ</translation>
+ <translation type="unfinished">тільки переглÑд</translation>
</message>
<message>
<source>(n/a)</source>
@@ -4298,7 +4537,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Whether or not a watch-only address is involved in this transaction.</source>
- <translation type="unfinished">Чи було залучено адреÑу Ð´Ð»Ñ ÑпоÑÑ‚ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð² цій транзакції.</translation>
+ <translation type="unfinished">Чи було залучено адреÑу "тільки переглÑд" в цій транзакції.</translation>
</message>
<message>
<source>User-defined intent/purpose of the transaction.</source>
@@ -4427,7 +4666,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</message>
<message>
<source>Watch-only</source>
- <translation type="unfinished">Тільки ÑпоÑтереженнÑ:</translation>
+ <translation type="unfinished">Тільки переглÑд</translation>
</message>
<message>
<source>Date</source>
@@ -4494,7 +4733,7 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Unable to decode PSBT from clipboard (invalid base64)</source>
- <translation type="unfinished">Ðе вдаєтьÑÑ Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ñ‚Ð¸ PSBT-транзакцію з буфера обміну (неприпуÑтимий base64)</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ñ‚Ð¸ PSBT-транзакцію з буфера обміну (неприпуÑтимий base64)</translation>
</message>
<message>
<source>Load Transaction Data</source>
@@ -4510,7 +4749,7 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Unable to decode PSBT</source>
- <translation type="unfinished">Ðе вдаєтьÑÑ Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ñ‚Ð¸ PSBT-транзакцію</translation>
+ <translation type="unfinished">Ðе вдалоÑÑ Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ñ‚Ð¸ PSBT-транзакцію</translation>
</message>
</context>
<context>
@@ -4585,7 +4824,7 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation type="unfinished">ЕкÑпортувати дані з поточної вкладки в файл</translation>
+ <translation type="unfinished">ЕкÑпортувати дані з поточної вкладки у файл</translation>
</message>
<message>
<source>Backup Wallet</source>
diff --git a/src/qt/locale/bitcoin_ur.ts b/src/qt/locale/bitcoin_ur.ts
index 54e090a69f..0c23d8b6ec 100644
--- a/src/qt/locale/bitcoin_ur.ts
+++ b/src/qt/locale/bitcoin_ur.ts
@@ -285,9 +285,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">%1ابھی تک سلامتی سے باÛر Ù†Ûیں نکلا…</translation>
</message>
<message>
+ <source>unknown</source>
+ <translation type="unfinished">نامعلوم</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation type="unfinished">رقم</translation>
</message>
+ <message>
+ <source>Unroutable</source>
+ <translation type="unfinished">ناقابل استعمال</translation>
+ </message>
+ <message>
+ <source>Internal</source>
+ <translation type="unfinished">اندرونی</translation>
+ </message>
+ <message>
+ <source>Address Fetch</source>
+ <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
+ <translation type="unfinished">Ù¾ØªÛ Ø¨Ø§Ø²ÛŒØ§Ùت کریں۔</translation>
+ </message>
+ <message>
+ <source>%1 ms</source>
+ <translation type="unfinished">ملی سیکنڈز %1</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
@@ -465,6 +486,66 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Create Wallet…</source>
<translation type="unfinished">والیٹ بنائیں…</translation>
</message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">تمام والیٹس بند کردیں</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation type="unfinished">اور Ùائل</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation type="unfinished">اور ترتیبات</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation type="unfinished">اور مدد</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation type="unfinished">ٹیبز ٹول بار</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished"> '%1%' Ûیڈرز Ú©ÛŒ مطابقت پذیری</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">نیٹ ورک Ú©Û’ ساتھ ÛÙ… Ø¢ÛÙ†Ú¯ ÛÙˆ کر</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">ڈسک پر بلاکس کو ترتیب دینا</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">ڈسک پر بلاکس کو پراسیس کرنا</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">ڈسک پر بلاکس Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û ØªØ±ØªÛŒØ¨ دینا</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">ساتھیوں سے منسلک کرنے</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation type="unfinished">ادائیگی کی درخواست کریں: ( کوئیک رسپانس ( کیو۔آر ) کوڈ اور بٹ کوائن ( یونیورسل ادائیگیوں کا نظام) کے ذریعے سے</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation type="unfinished">استعمال Ø´Ø¯Û Ø¨Ú¾ÛŒØ¬Ù†Û’ والے پتے اور لیبلز Ú©ÛŒ ÙÛرست دکھائیں۔</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation type="unfinished">استعمال Ø´Ø¯Û ÙˆØµÙˆÙ„ کرنے والے پتوں اور لیبلز Ú©ÛŒ ÙÛرست دکھائیں۔</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation type="unfinished">اور کمانڈ لائن اختیارات</translation>
+ </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
@@ -473,9 +554,122 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</translation>
</message>
<message>
+ <source>%1 behind</source>
+ <translation type="unfinished">'%1'پیچھے</translation>
+ </message>
+ <message>
+ <source>Catching up…</source>
+ <translation type="unfinished">پکڑنا</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation type="unfinished">آخری موصول Ø´Ø¯Û 1 '%1' Ù¾ÛÙ„Û’ تیار کیا گیا تھا۔</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation type="unfinished">اس Ú©Û’ بعد Ú©ÛŒ لین دین ابھی نظر Ù†Ûیں آئے گی۔</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">نقص</translation>
</message>
+ <message>
+ <source>Warning</source>
+ <translation type="unfinished">انتباÛ</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation type="unfinished">معلومات</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation type="unfinished">سب سے نیا</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">جزوی طور پر دستخط Ø´Ø¯Û Ø¨Ù¹ کوائن ٹرانزیکشن لوڈ کریں۔</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">کلپ بورڈ سے جزوی طور پر دستخط Ø´Ø¯Û Ø¨Ù¹ کوائن ٹرانزیکشن لوڈ کریں۔</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">نوڈ ونڈو</translation>
+ </message>
+ <message>
+ <source>Open node debugging and diagnostic console</source>
+ <translation type="unfinished">نوڈ ڈیبگنگ اور تشخیصی کنسول کھولیں۔</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">اور بھیجنے والے پتے</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">اور پتے وصول کرنا</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI</source>
+ <translation type="unfinished">بٹ کوائن کا یو۔آر۔آئی۔ کھولیں</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <translation type="unfinished">والیٹ کھولیں</translation>
+ </message>
+ <message>
+ <source>Open a wallet</source>
+ <translation type="unfinished">والیٹ کھولیں</translation>
+ </message>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">والیٹ بند کریں</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">تمام والیٹس بند کریں</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation type="unfinished">Ù…Ù…Ú©Ù†Û Ø¨Ù¹ کوائن کمانڈ لائن اختیارات Ú©Û’ ساتھ ÙÛرست حاصل کرنے Ú©Û’ لیے %1 مدد کا پیغام دکھائیں۔</translation>
+ </message>
+ <message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">قدروں کو چھپائیں</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">Ø¬Ø§Ø¦Ø²Û Ù¹ÛŒØ¨ میں اقدار Ú©Ùˆ ماسک کریں۔</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">Ù¾ÛÙ„Û’ سے Ø·Û’ Ø´Ø¯Û ÙˆØ§Ù„ÛŒÙ¹</translation>
+ </message>
+ <message>
+ <source>No wallets available</source>
+ <translation type="unfinished">کوئی والیٹ دستیاب Ù†Ûیں Ûیں۔</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">والیٹ کا نام</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">اور ونڈو</translation>
+ </message>
+ <message>
+ <source>Zoom</source>
+ <translation type="unfinished">بغور Ø¬Ø§Ø¦Ø²Û Ù„ÛŒÙ†Ø§</translation>
+ </message>
+ <message>
+ <source>Main Window</source>
+ <translation type="unfinished">مین ونڈو</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation type="unfinished">'%1'کلائنٹ</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
@@ -485,42 +679,477 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">مزید کارروائی کے لیے کلک کریں۔</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">پیئرز ٹیب دکھائیں۔</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">نیٹ ورک Ú©ÛŒ سرگرمی Ú©Ùˆ غیر Ùعال کریں۔</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">نیٹ ورک Ú©ÛŒ سرگرمی Ú©Ùˆ Ùعال کریں۔</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">خرابی:%1</translation>
</message>
- </context>
+ <message>
+ <source>Warning: %1</source>
+ <translation type="unfinished">1%1 انتباÛ</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation type="unfinished">1%1' تاریخ۔
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation type="unfinished">1%1' مقدار
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation type="unfinished">1%1' والیٹ
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation type="unfinished">1 %1'قسم
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation type="unfinished">1%1'لیبل
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation type="unfinished">1%1' پتÛ
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation type="unfinished">بھیجی گئی ٹرانزیکشن</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation type="unfinished">آنے والی ٹرانزیکشن</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished">Ø¯Ø±Ø¬Û Ø¨Ù†Ø¯ÛŒ کا تعین کرنے والی ایچ۔ڈی کلیدی جنریشن &lt;b&gt;Ùعال&lt;/b&gt; ÛÛ’</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">Ø¯Ø±Ø¬Û Ø¨Ù†Ø¯ÛŒ کا تعین کرنے والی ایچ۔ ÚˆÛŒ کلیدی جنریشن&lt;b&gt; غیر Ùعال&lt;/b&gt; ÛÛ’</translation>
+ </message>
+ <message>
+ <source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">نجی کلید &lt;b&gt;غیر Ùعال &lt;b/&gt;ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">اصل پیغام:</translation>
+ </message>
+</context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">رقم ظاÛر کرنے Ú©Û’ لیے یونٹ۔ دوسری اکائی Ú©Ùˆ منتخب کرنے Ú©Û’ لیے Ú©Ù„Ú© کریں۔</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Coin Selection</source>
+ <translation type="unfinished">سکے کا انتخاب</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">مقدار:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">بائٹس:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation type="unfinished">رقم:</translation>
</message>
<message>
+ <source>Fee:</source>
+ <translation type="unfinished">Ùیس:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">Ù†Û Ûونے Ú©Û’ برابر</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">Ùیس Ú©Û’ بعد:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">تبدیلی:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation type="unfinished">سب کو غیر منتخب کریں</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation type="unfinished">ٹری موڈ</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation type="unfinished">ÙÛرست موڈ</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation type="unfinished">رقم</translation>
</message>
<message>
+ <source>Received with label</source>
+ <translation type="unfinished">لیبل Ú©Û’ ساتھ موصول Ûوا۔</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation type="unfinished">پتے Ú©Û’ ساتھ موصول Ûوا۔</translation>
+ </message>
+ <message>
<source>Date</source>
<translation type="unfinished">تاریخ</translation>
</message>
<message>
+ <source>Confirmations</source>
+ <translation type="unfinished">تصدیقات</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">تصدیق شدÛ</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">رقم کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">ایڈریس کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">کاپی اور لیبل</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">کاپی اور رقم</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">غیر خرچ Ø´Ø¯Û Ø¢Ø¤Ù¹ پٹ بند کریں</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">غیر خرچ Ø´Ø¯Û Ú©Ú¾ÙˆÙ„ÛŒÚº</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">مقدار کاپی کریں</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Ùیس کاپی کریں</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Ùیس Ú©Û’ بعد کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">بائٹس کاپی کریں</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">باقی Ø´Ø¯Û Ú©Ø§Ù¾ÛŒ کریں</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">تبدیلی کاپی کریں</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation type="unfinished">مقÙÙ„'%1</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation type="unfinished">جی Ûاں</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation type="unfinished">Ù†Ûیں</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished">ÛŒÛ Ù„ÛŒØ¨Ù„ سرخ ÛÙˆ جاتا ÛÛ’ اگر کوئی وصول Ú©Ù†Ù†Ø¯Û Ù…ÙˆØ¬ÙˆØ¯Û Ú©Ù… سے Ú©Ù… مقرر Ú©Ø±Ø¯Û Ø­Ø¯ سے Ú©Ù… رقم وصول کرتا ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation type="unfinished">مختل٠ÛÙˆ سکتے Ûیں%1 +/- ساتوشی ÙÛŒ ان پٹ۔</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(کوئی لیبل Ù†Ûیں)</translation>
</message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation type="unfinished">%1 (%2)سے تبدیل کریں</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation type="unfinished">تبدیلی</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletActivity</name>
+ <message>
+ <source>Create Wallet</source>
+ <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
+ <translation type="unfinished">والیٹ بنائیں</translation>
+ </message>
+ <message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">والیٹ بنانا &lt;b&gt; %1&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Create wallet failed</source>
+ <translation type="unfinished">والیٹ بنانا ناکام Ûوگیا۔</translation>
+ </message>
+ <message>
+ <source>Create wallet warning</source>
+ <translation type="unfinished">والیٹ بنانے کےلئے انتباÛ</translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">دستخط کنندگان Ú©ÛŒ ÙÛرست Ù†Ûیں بن سکتی</translation>
+ </message>
+ </context>
+<context>
+ <name>OpenWalletActivity</name>
+ <message>
+ <source>Open wallet failed</source>
+ <translation type="unfinished">والیٹ کھولنا ناکام ÛÙˆ گیا</translation>
+ </message>
+ <message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">والیٹ کھولنے Ú©ÛŒ انتباÛ</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">Ù¾ÛÙ„Û’ سے Ø·Û’ Ø´Ø¯Û ÙˆØ§Ù„ÛŒÙ¹</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
+ <translation type="unfinished">والیٹ کھولیں</translation>
+ </message>
</context>
<context>
+ <name>WalletController</name>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">والیٹ بند کریں</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">والیٹ Ú©Ùˆ Ø²ÛŒØ§Ø¯Û Ø¯ÛŒØ± تک بند کرنے Ú©Û’ نتیجے میں اگر کانٹ چھانٹ Ú©Ùˆ Ùعال کیا جاتا ÛÛ’ تو پوری چین Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û ÛÙ… Ø¢ÛÙ†Ú¯ کرنا Ù¾Ú‘ سکتا ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">تمام والیٹس بند کریں</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">کیا آپ واقعی تمام والیٹس بند کرنا چاÛتے Ûیں؟</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletDialog</name>
+ <message>
+ <source>Create Wallet</source>
+ <translation type="unfinished">والیٹ بنائیں</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <translation type="unfinished">والیٹ کا نام</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation type="unfinished">والیٹ</translation>
+ </message>
+ <message>
+ <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
+ <translation type="unfinished">والیٹ Ú©Ùˆ Ø®ÙÛŒÛ Ú©Ø±ÛŒÚºÛ” والیٹ Ú©Ùˆ آپ Ú©ÛŒ پسند Ú©Û’ پاسÙریز Ú©Û’ ساتھ Ø®ÙÛŒÛ Ú©ÛŒØ§ جائے گا۔</translation>
+ </message>
+ <message>
+ <source>Encrypt Wallet</source>
+ <translation type="unfinished">والیٹ Ú©Ùˆ Ø®ÙÛŒÛ Ú©Ø±ÛŒÚºÛ”</translation>
+ </message>
+ <message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">اعلی درجے کے اختیارات</translation>
+ </message>
+ <message>
+ <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
+ <translation type="unfinished">اس والیٹ Ú©Û’ لیے نجی چابیوں Ú©Ùˆ غیر Ùعال کریں۔ غیر Ùعال نجی چابیوں والے والیٹ میں کوئی نجی چابیاں Ù†Ûیں ÛÙˆÚº Ú¯ÛŒ اور اس میں HD بیج یا درآمد Ø´Ø¯Û Ù†Ø¬ÛŒ چابیاں Ù†Ûیں ÛÙˆ سکتیں۔ ÛŒÛ ØµØ±Ù Ø¯ÛŒÚ©Ú¾Ù†Û’ والے والیٹ Ú©Û’ لیے مثالی ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Disable Private Keys</source>
+ <translation type="unfinished">نجی چابیاں غیر Ùعال کریں۔</translation>
+ </message>
+ <message>
+ <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
+ <translation type="unfinished">ایک خالی والیٹ بنائیں۔ خالی والیٹ میں ابتدائی طور پر نجی چابیاں یا اسکرپٹ Ù†Ûیں Ûوتے Ûیں۔ نجی چابیاں اور پتے درآمد کیے جا سکتے Ûیں، یا بعد میں ایک HD بیج سیٹ کیا جا سکتا ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">خالی والیٹ بنائیں</translation>
+ </message>
+ <message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">ScriptPubKeys کے انتظام کے لیے وضاحت کنندگان کا استعمال کریں۔</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">وضاحتی والیٹ</translation>
+ </message>
+ <message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">بیرونی دستخط کرنے والا Ø¢Ù„Û Ø§Ø³ØªØ¹Ù…Ø§Ù„ کریں جیسے Ûارڈ ویئر والیٹ۔ Ù¾ÛÙ„Û’ والیٹ Ú©ÛŒ ترجیحات میں بیرونی دستخط Ú©Ù†Ù†Ø¯Û Ø§Ø³Ú©Ø±Ù¾Ù¹ Ú©Ùˆ ترتیب دیں۔</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">بیرونی دستخط کنندÛ</translation>
+ </message>
+ <message>
+ <source>Create</source>
+ <translation type="unfinished">بنائیں</translation>
+ </message>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished"> SQliteسپورٹ کے بغیر مرتب کیا گیا (ڈسکرپٹر والیٹس کے لیے درکار)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">بیرونی دستخطی معاونت کے بغیر مرتب کیا گیا (بیرونی دستخط کے لیے درکار)</translation>
+ </message>
+</context>
+<context>
<name>EditAddressDialog</name>
<message>
+ <source>Edit Address</source>
+ <translation type="unfinished">ایڈریس میں ترمیم کریں۔</translation>
+ </message>
+ <message>
<source>&amp;Label</source>
<translation type="unfinished">Ú†Ù¹</translation>
</message>
<message>
+ <source>The label associated with this address list entry</source>
+ <translation type="unfinished">اس ایڈریس لسٹ Ú©Û’ اندراج سے ÙˆØ§Ø¨Ø³ØªÛ Ù„ÛŒØ¨Ù„</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation type="unfinished">اس ایڈریس لسٹ Ú©Û’ اندراج سے ÙˆØ§Ø¨Ø³ØªÛ Ù¾ØªÛÛ” اس میں صر٠ایڈریس بھیجنے Ú©Û’ لیے ترمیم Ú©ÛŒ جا سکتی ÛÛ’Û”</translation>
+ </message>
+ <message>
<source>&amp;Address</source>
<translation type="unfinished">پتÛ</translation>
</message>
- </context>
+ <message>
+ <source>New sending address</source>
+ <translation type="unfinished">نیا بھیجنے کا پتÛ</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation type="unfinished">وصول Ú©Ù†Ù†Ø¯Û Ø§ÛŒÚˆØ±ÛŒØ³ میں ترمیم کریں۔</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation type="unfinished">بھیجنے کے پتے میں ترمیم کریں۔</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">والیٹ Ú©Ùˆ غیر مقÙÙ„ Ù†Ûیں کیا جا سکا۔</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation type="unfinished">نئی کلیدی نسل ناکام Ûوگئی۔</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>A new data directory will be created.</source>
+ <translation type="unfinished">ایک نئی ڈیٹا ڈائرکٹری بنائی جائے گی۔</translation>
+ </message>
+ <message>
+ <source>name</source>
+ <translation type="unfinished">نام</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation type="unfinished">پاتھ Ù¾ÛÙ„Û’ سے موجود ÛÛ’ØŒ اور ڈائرکٹری Ù†Ûیں ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation type="unfinished">ÛŒÛاں ڈیٹا ڈائرکٹری Ù†Ûیں بن سکتی۔</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
+ <message>
+ <source>Bitcoin</source>
+ <translation type="unfinished">بٹ کوائن</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
<message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
@@ -530,32 +1159,710 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</translation>
</message>
<message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished">والیٹ بھی اس ڈائرکٹری میں محÙوظ کیا جائے گا۔</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">نقص</translation>
</message>
+ <message>
+ <source>Welcome</source>
+ <translation type="unfinished">خوش آمدید</translation>
+ </message>
+ <message>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">بلاک چین اسٹوریج کو محدود کریں۔</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
+ <translation type="unfinished">اس ترتیب Ú©Ùˆ واپس کرنے Ú©Û’ لیے پورے بلاکچین Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û ÚˆØ§Ø¤Ù† لوڈ کرنے Ú©ÛŒ ضرورت ÛÛ’Û” Ù¾ÛÙ„Û’ پوری چین Ú©Ùˆ ڈاؤن لوڈ کرنا اور بعد میں اسے کاٹنا تیز تر ÛÛ’Û” Ú©Ú†Ú¾ جدید خصوصیات Ú©Ùˆ غیر Ùعال کرتا ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source> GB</source>
+ <translation type="unfinished">جی بی</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 type="unfinished">اگر آپ Ù†Û’ بلاک چین اسٹوریج Ú©Ùˆ محدود کرنے کا انتخاب کیا ÛÛ’ (کاٹنا)ØŒ تو تاریخی ڈیٹا Ú©Ùˆ ابھی بھی ڈاؤن لوڈ اور پروسیس کیا جانا چاÛیے، لیکن آپ Ú©Û’ ڈسک Ú©Û’ استعمال Ú©Ùˆ Ú©Ù… رکھنے Ú©Û’ لیے اسے بعد میں حذ٠کر دیا جائے گا۔</translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation type="unfinished">Ù¾ÛÙ„Û’ سے Ø·Û’ Ø´Ø¯Û ÚˆÛŒÙ¹Ø§ ڈائرکٹری استعمال کریں۔</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation type="unfinished">اپنی مرضی کے مطابق ڈیٹا ڈائرکٹری کا استعمال کریں:</translation>
+ </message>
+</context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation type="unfinished">ورژن</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished">تقریبآ %1</translation>
+ </message>
+ <message>
+ <source>Command-line options</source>
+ <translation type="unfinished">کمانڈ لائن کے اختیارات</translation>
+ </message>
+</context>
+<context>
+ <name>ShutdownWindow</name>
+ <message>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation type="unfinished">جب تک ÛŒÛ ÙˆÙ†ÚˆÙˆ غائب Ù†Û Ûوجائے کمپیوٹر Ú©Ùˆ بند Ù†Û Ú©Ø±ÛŒÚºÛ”</translation>
+ </message>
+</context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">Ùارم</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 type="unfinished">ÛÙˆ سکتا ÛÛ’ Ø­Ø§Ù„ÛŒÛ Ù„ÛŒÙ† دین ابھی تک نظر Ù†Û Ø¢Ø¦Û’ØŒ اور اس ÙˆØ¬Û Ø³Û’ آپ Ú©Û’ والیٹ کا بیلنس غلط ÛÙˆ سکتا ÛÛ’Û” ÛŒÛ Ù…Ø¹Ù„ÙˆÙ…Ø§Øª درست ÛÙˆÚº Ú¯ÛŒ جب آپ Ú©Û’ والیٹ Ù†Û’ بٹ کوائن نیٹ ورک Ú©Û’ ساتھ مطابقت پذیری مکمل کر Ù„ÛŒ Ûو، جیسا Ú©Û Ø°ÛŒÙ„ میں تÙصیل ÛÛ’Û”</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 type="unfinished">ایسے بٹ کوائنز خرچ کرنے Ú©ÛŒ کوشش کرنا جو ابھی تک ظاÛر Ù†Û Ûونے والے لین دین سے متاثر ÛÙˆÚº نیٹ ورک Ú©Û’ ذریعے قبول Ù†Ûیں کیا جائے گا۔</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation type="unfinished">باقی بلاکس کی تعداد</translation>
+ </message>
+ <message>
+ <source>Unknown…</source>
+ <translation type="unfinished">نامعلوم</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">حساب لگانا</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">آخری بلاک کا وقت</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation type="unfinished">پیش رÙت</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation type="unfinished">ÙÛŒ Ú¯Ú¾Ù†Ù¹Û Ù¾ÛŒØ´ رÙت میں اضاÙÛ</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation type="unfinished">مطابقت پذیر Ûونے میں تخمینی وقت باقی ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">چھپائیں</translation>
+ </message>
</context>
<context>
+ <name>OpenURIDialog</name>
+ <message>
+ <source>Open bitcoin URI</source>
+ <translation type="unfinished">بٹ کوائن URI کھولیں۔</translation>
+ </message>
+ <message>
+ <source>URI:</source>
+ <translation type="unfinished">URI</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
+ <translation type="unfinished">کلپ بورڈ سے Ù¾ØªÛ Ú†Ø³Ù¾Ø§Úº کریں۔</translation>
+ </message>
+</context>
+<context>
<name>OptionsDialog</name>
<message>
+ <source>Options</source>
+ <translation type="unfinished">اختیارات</translation>
+ </message>
+ <message>
+ <source>&amp;Main</source>
+ <translation type="unfinished">اور مرکزی</translation>
+ </message>
+ <message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">کٹائی Ú©Ùˆ Ùعال کرنا لین دین Ú©Ùˆ Ø°Ø®ÛŒØ±Û Ú©Ø±Ù†Û’ Ú©Û’ لیے درکار ڈسک Ú©ÛŒ Ø¬Ú¯Û Ú©Ùˆ نمایاں طور پر Ú©Ù… کرتا ÛÛ’Û” تمام بلاکس اب بھی مکمل طور پر درست Ûیں۔ اس ترتیب Ú©Ùˆ واپس کرنے Ú©Û’ لیے پورے بلاکچین Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û ÚˆØ§Ø¤Ù† لوڈ کرنے Ú©ÛŒ ضرورت ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Size of &amp;database cache</source>
+ <translation type="unfinished">ڈیٹا بیس کیشے کا سائز</translation>
+ </message>
+ <message>
+ <source>Number of script &amp;verification threads</source>
+ <translation type="unfinished">اسکرپٹ اور تصدیقی دھاگوں کی تعداد</translation>
+ </message>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation type="unfinished">پراکسی کا 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 type="unfinished">ÛŒÛ Ø¯Ú©Ú¾Ø§ØªØ§ ÛÛ’ Ú©Û Ú©ÛŒØ§ ÙراÛÙ… Ú©Ø±Ø¯Û ÚˆÛŒÙالٹ SOCKS5 پراکسی اس نیٹ ورک Ú©ÛŒ قسم Ú©Û’ ذریعے ساتھی تک Ù¾ÛÙ†Ú†Ù†Û’ Ú©Û’ لیے استعمال Ûوتی ÛÛ’Û”</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 type="unfinished">ونڈو بند Ûونے پر ایپلیکیشن سے باÛر نکلنے Ú©Û’ بجائے چھوٹا کریں۔ جب ÛŒÛ Ø¢Ù¾Ø´Ù† Ùعال ÛÙˆ جائے گا تو مینو میں ایگزٹ Ú©Ùˆ منتخب کرنے Ú©Û’ بعد ÛÛŒ ایپلیکیشن بند ÛÙˆ جائے گی۔</translation>
+ </message>
+ <message>
+ <source>Open Configuration File</source>
+ <translation type="unfinished">ترتیب والی Ùائل کھولیں۔</translation>
+ </message>
+ <message>
+ <source>Reset all client options to default.</source>
+ <translation type="unfinished">کلائنٹ Ú©Û’ تمام اختیارات Ú©Ùˆ ÚˆÛŒÙالٹ پر Ø¯ÙˆØ¨Ø§Ø±Û ØªØ±ØªÛŒØ¨ دیں۔</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation type="unfinished">اور Ø¯ÙˆØ¨Ø§Ø±Û ØªØ±ØªÛŒØ¨ دینے Ú©Û’ اختیارات</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation type="unfinished">اور نیٹ ورک</translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <translation type="unfinished">جی بی</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">اس ترتیب Ú©Ùˆ واپس کرنے Ú©Û’ لیے پورے بلاکچین Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û ÚˆØ§Ø¤Ù† لوڈ کرنے Ú©ÛŒ ضرورت ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Expert</source>
+ <translation type="unfinished">ماÛر</translation>
+ </message>
+ <message>
+ <source>Enable coin &amp;control features</source>
+ <translation type="unfinished">سکے اور کنٹرول Ú©ÛŒ خصوصیات Ú©Ùˆ Ùعال کریں۔</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 type="unfinished">اگر آپ غیر Ù…ØµØ¯Ù‚Û ØªØ¨Ø¯ÛŒÙ„ÛŒ Ú©Û’ اخراجات Ú©Ùˆ غیر Ùعال کرتے Ûیں، تو کسی لین دین Ú©ÛŒ تبدیلی Ú©Ùˆ اس وقت تک استعمال Ù†Ûیں کیا جا سکتا جب تک Ú©Û Ø§Ø³ لین دین Ú©ÛŒ Ú©Ù… از Ú©Ù… ایک تصدیق Ù†Û ÛÙˆÛ” اس سے ÛŒÛ Ø¨Ú¾ÛŒ متاثر Ûوتا ÛÛ’ Ú©Û Ø¢Ù¾ Ú©Û’ بیلنس کا حساب کیسے لیا جاتا ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>&amp;Spend unconfirmed change</source>
+ <translation type="unfinished">اور غیر Ù…ØµØ¯Ù‚Û ØªØ¨Ø¯ÛŒÙ„ÛŒ خرچ کریں۔</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">اور ونڈو</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">بیرونی دستخطی معاونت کے بغیر مرتب کیا گیا (بیرونی دستخط کے لیے درکار)</translation>
+ </message>
+ <message>
+ <source>default</source>
+ <translation type="unfinished">Ù¾ÛÙ„Û’ سے Ø·Û’ شدÛ</translation>
+ </message>
+ <message>
+ <source>none</source>
+ <translation type="unfinished">کوئی Ù†Ûیں</translation>
+ </message>
+ <message>
+ <source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
+ <translation type="unfinished">اختیارات Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û ØªØ±ØªÛŒØ¨ دینے Ú©ÛŒ تصدیق کریں۔</translation>
+ </message>
+ <message>
+ <source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
+ <translation type="unfinished">تبدیلیوں Ú©Ùˆ چالو کرنے Ú©Û’ لیے کلائنٹ Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کرنا ضروری ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
+ <translation type="unfinished">کلائنٹ Ú©Ùˆ بند کر دیا جائے گا۔ کیا آپ Ø¢Ú¯Û’ بڑھنا چاÛتے Ûیں؟</translation>
+ </message>
+ <message>
+ <source>Configuration options</source>
+ <extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
+ <translation type="unfinished">Ú©Ù†Ùیگریشن Ú©Û’ اختیارات</translation>
+ </message>
+ <message>
<source>Error</source>
<translation type="unfinished">نقص</translation>
</message>
+ <message>
+ <source>This change would require a client restart.</source>
+ <translation type="unfinished">اس تبدیلی Ú©Ùˆ کلائنٹ Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کرنے Ú©ÛŒ ضرورت Ûوگی۔</translation>
+ </message>
+ <message>
+ <source>The supplied proxy address is invalid.</source>
+ <translation type="unfinished">ÙراÛÙ… Ú©Ø±Ø¯Û Ù¾Ø±Ø§Ú©Ø³ÛŒ Ù¾ØªÛ ØºÙ„Ø· ÛÛ’Û”</translation>
+ </message>
+</context>
+<context>
+ <name>OverviewPage</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">Ùارم</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 type="unfinished">ظاÛر Ú©ÛŒ گئی معلومات پرانی ÛÙˆ سکتی ÛÛ’Û” کنکشن قائم Ûونے Ú©Û’ بعد آپ کا والیٹ خود بخود بٹ کوائن نیٹ ورک Ú©Û’ ساتھ ÛÙ… Ø¢ÛÙ†Ú¯ Ûوجاتا ÛÛ’ØŒ لیکن ÛŒÛ Ø¹Ù…Ù„ ابھی مکمل Ù†Ûیں Ûوا ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Watch-only:</source>
+ <translation type="unfinished">صر٠دیکھنے کے لیے:</translation>
+ </message>
+ <message>
+ <source>Available:</source>
+ <translation type="unfinished">دستیاب:</translation>
+ </message>
+ <message>
+ <source>Your current spendable balance</source>
+ <translation type="unfinished">آپ کا Ù…ÙˆØ¬ÙˆØ¯Û Ù‚Ø§Ø¨Ù„ خرچ بیلنس</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation type="unfinished">زیر التواء</translation>
+ </message>
+ <message>
+ <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
+ <translation type="unfinished">Ú©Ù„ ٹرانزیکشنز جن Ú©ÛŒ تصدیق Ûونا باقی ÛÛ’ØŒ اور ابھی تک قابل خرچ بیلنس میں شمار Ù†Ûیں Ûوتے </translation>
+ </message>
+ <message>
+ <source>Immature:</source>
+ <translation type="unfinished">خام</translation>
+ </message>
+ <message>
+ <source>Mined balance that has not yet matured</source>
+ <translation type="unfinished">کان Ú©Ù†ÛŒ کا توازن جو ابھی Ù¾Ø®ØªÛ Ù†Ûیں Ûوا ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation type="unfinished">بیلنس</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation type="unfinished">Ú©Ù„:</translation>
+ </message>
+ <message>
+ <source>Your current total balance</source>
+ <translation type="unfinished">آپ کا Ú©Ù„ Ù…ÙˆØ¬ÙˆØ¯Û Ø¨ÛŒÙ„Ù†Ø³</translation>
+ </message>
+ <message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation type="unfinished">صر٠دیکھنے والے ایڈریسز میں آپ کا Ù…ÙˆØ¬ÙˆØ¯Û Ø¨ÛŒÙ„Ù†Ø³</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation type="unfinished">قابل خرچ:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation type="unfinished">Ø­Ø§Ù„ÛŒÛ Ù„ÛŒÙ† دین</translation>
+ </message>
+ <message>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation type="unfinished">صر٠دیکھنے والے پتوں پر غیر تصدیق Ø´Ø¯Û Ù„ÛŒÙ† دین</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation type="unfinished">صر٠دیکھنے Ú©Û’ پتوں میں Ú©Ù„ Ù…ÙˆØ¬ÙˆØ¯Û Ø¨ÛŒÙ„Ù†Ø³</translation>
+ </message>
+ <message>
+ <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
+ <translation type="unfinished">Ø¬Ø§Ø¦Ø²Û Ù¹ÛŒØ¨ Ú©Û’ لیے پرائیویسی موڈ Ú©Ùˆ Ùعال کر دیا گیا ÛÛ’Û” اقدار Ú©Ùˆ Ûٹانے Ú©Û’ لیے، سیٹنگز-&gt;ماسک ویلیوز Ú©Ùˆ غیر چیک کریں۔</translation>
+ </message>
+</context>
+<context>
+ <name>PSBTOperationsDialog</name>
+ <message>
+ <source>Copy to Clipboard</source>
+ <translation type="unfinished">کلپ بورڈ پر کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>Save…</source>
+ <translation type="unfinished">محÙوظ کریں۔</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished">بند کریں</translation>
+ </message>
+ <message>
+ <source>Failed to load transaction: %1</source>
+ <translation type="unfinished">لین دین لوڈ کرنے میں ناکام:%1</translation>
+ </message>
+ <message>
+ <source>Failed to sign transaction: %1</source>
+ <translation type="unfinished">لین دین پر دستخط کرنے میں ناکام:%1</translation>
+ </message>
+ <message>
+ <source>Could not sign any more inputs.</source>
+ <translation type="unfinished">مزید ان پٹ پر دستخط Ù†Ûیں ÛÙˆ سکے۔</translation>
+ </message>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">لین دین کا ڈیٹا محÙوظ کریں۔</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">کل رقم</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">یا</translation>
+ </message>
+ <message>
+ <source>Transaction still needs signature(s).</source>
+ <translation type="unfinished">لین دین Ú©Ùˆ ابھی بھی دستخط Ú©ÛŒ ضرورت ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>(But this wallet cannot sign transactions.)</source>
+ <translation type="unfinished">(لیکن ÛŒÛ ÙˆØ§Ù„ÛŒÙ¹ لین دین پر دستخط Ù†Ûیں کر سکتا۔)</translation>
+ </message>
+ <message>
+ <source>Transaction status is unknown.</source>
+ <translation type="unfinished">لین دین Ú©ÛŒ حیثیت نامعلوم ÛÛ’Û”</translation>
+ </message>
+</context>
+<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation type="unfinished">ادائیگی کی درخواست کی خرابی۔</translation>
+ </message>
+ <message>
+ <source>Cannot process payment request because BIP70 is not supported.
+Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
+If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
+ <translation type="unfinished">ادائیگی Ú©ÛŒ درخواست پر کارروائی Ù†Ûیں Ú©ÛŒ جا سکتی Ú©ÛŒÙˆÙ†Ú©Û BIP70 تعاون یاÙØªÛ Ù†Ûیں ÛÛ’Û” BIP70 میں سیکورٹی Ú©ÛŒ وسیع خامیوں Ú©ÛŒ ÙˆØ¬Û Ø³Û’ ÛŒÛ Ù¾Ø±Ø²ÙˆØ± Ù…Ø´ÙˆØ±Û Ø¯ÛŒØ§ جاتا ÛÛ’ Ú©Û ÙˆØ§Ù„ÛŒÙ¹ Ú©Ùˆ تبدیل کرنے Ú©Û’ لیے کسی بھی تاجر Ú©ÛŒ Ûدایات Ú©Ùˆ نظر انداز کر دیا جائے۔ اگر آپ Ú©Ùˆ ÛŒÛ Ø®Ø±Ø§Ø¨ÛŒ موصول ÛÙˆ رÛÛŒ ÛÛ’ تو آپ Ú©Ùˆ مرچنٹ سے BIP21 مطابقت پذیر URI ÙراÛÙ… کرنے Ú©ÛŒ درخواست کرنی چاÛیے۔</translation>
+ </message>
</context>
<context>
<name>PeerTableModel</name>
<message>
+ <source>User Agent</source>
+ <extracomment>Title of Peers Table column which contains the peer's User Agent string.</extracomment>
+ <translation type="unfinished">صار٠ایجنٹ</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <extracomment>Title of Peers Table column which indicates the current latency of the connection with the peer.</extracomment>
+ <translation type="unfinished">پنگ</translation>
+ </message>
+ <message>
+ <source>Peer</source>
+ <extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
+ <translation type="unfinished">Ùریق</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment>
+ <translation type="unfinished">بھیجا</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have received from the peer.</extracomment>
+ <translation type="unfinished">موصول Ûوا۔</translation>
+ </message>
+ <message>
<source>Address</source>
<extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
<translation type="unfinished">پتÛ</translation>
</message>
+ <message>
+ <source>Type</source>
+ <extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment>
+ <translation type="unfinished">قسم</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment>
+ <translation type="unfinished">نیٹ ورک</translation>
+ </message>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">اور تصویر محÙوظ کریں…</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation type="unfinished">اور تصویر کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation type="unfinished">کیو آر Ú©ÙˆÚˆ محÙوظ کریں۔</translation>
+ </message>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>&amp;Information</source>
+ <translation type="unfinished">اور معلومات</translation>
+ </message>
+ <message>
+ <source>Startup time</source>
+ <translation type="unfinished">آغاز کا وقت</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished">نیٹ ورک</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished">نام</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation type="unfinished">رابطوں کی تعداد</translation>
+ </message>
+ <message>
+ <source>Block chain</source>
+ <translation type="unfinished">بلاک چین</translation>
+ </message>
+ <message>
+ <source>Current number of transactions</source>
+ <translation type="unfinished">لین دین Ú©ÛŒ Ù…ÙˆØ¬ÙˆØ¯Û ØªØ¹Ø¯Ø§Ø¯</translation>
+ </message>
+ <message>
+ <source>Memory usage</source>
+ <translation type="unfinished">استعمال یاد داشت</translation>
+ </message>
+ <message>
+ <source>Wallet: </source>
+ <translation type="unfinished">والیٹ</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation type="unfinished">(کوئی Ù†Ûیں)</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation type="unfinished">موصول Ûوا۔</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation type="unfinished">بھیجا</translation>
+ </message>
+ <message>
+ <source>&amp;Peers</source>
+ <translation type="unfinished">اور Ùریق</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation type="unfinished">Ù…Ù…Ù†ÙˆØ¹Û Ùریقوں</translation>
+ </message>
+ <message>
+ <source>Select a peer to view detailed information.</source>
+ <translation type="unfinished">تÙصیلی معلومات دیکھنے Ú©Û’ لیے Ùریق کا انتخاب کریں۔</translation>
+ </message>
+ <message>
+ <source>Starting Block</source>
+ <translation type="unfinished">شروع Ûونے والا بلاک</translation>
+ </message>
+ <message>
+ <source>Synced Blocks</source>
+ <translation type="unfinished">مطابقت پذیر بلاکس</translation>
+ </message>
+ <message>
+ <source>User Agent</source>
+ <translation type="unfinished">صار٠ایجنٹ</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">نوڈ ونڈو</translation>
+ </message>
+ <message>
+ <source>Current block height</source>
+ <translation type="unfinished">Ù…ÙˆØ¬ÙˆØ¯Û Ø¨Ù„Ø§Ú© Ú©ÛŒ اونچائی</translation>
+ </message>
+ <message>
+ <source>Decrease font size</source>
+ <translation type="unfinished">Ùونٹ کا سائز Ú©Ù… کریں۔</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation type="unfinished">Ùونٹ سائز میں اضاÙÛ Ú©Ø±ÛŒÚº</translation>
+ </message>
+ <message>
+ <source>Permissions</source>
+ <translation type="unfinished">اجازتیں</translation>
+ </message>
+ <message>
+ <source>Services</source>
+ <translation type="unfinished">خدمات</translation>
+ </message>
+ <message>
+ <source>Connection Time</source>
+ <translation type="unfinished">کنکشن کا وقت</translation>
+ </message>
+ <message>
+ <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
+ <translation type="unfinished">اس Ùریق Ú©ÛŒ جانب سے ابتدائی درستگی Ú©ÛŒ جانچ پڑتال کرنے والا ایک نیا بلاک موصول Ûونے Ú©Û’ بعد گزرا Ûوا وقت۔</translation>
+ </message>
+ <message>
+ <source>Last Block</source>
+ <translation type="unfinished">آخری بلاک</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation type="unfinished">آخری بھیجا۔</translation>
+ </message>
+ <message>
+ <source>Last Receive</source>
+ <translation type="unfinished">آخری موصول</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">آخری بلاک کا وقت</translation>
+ </message>
+ <message>
+ <source>Totals</source>
+ <translation type="unfinished">Ú©Ù„</translation>
+ </message>
+ <message>
+ <source>Clear console</source>
+ <translation type="unfinished">کنسول صا٠کریں۔</translation>
+ </message>
+ <message>
+ <source>In:</source>
+ <translation type="unfinished">میں:</translation>
+ </message>
+ <message>
+ <source>Out:</source>
+ <translation type="unfinished">باÛر:</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">ایڈریس کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>&amp;Disconnect</source>
+ <translation type="unfinished">اور منقطع کریں۔</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation type="unfinished">نیٹ ورک Ú©ÛŒ سرگرمی غیر Ùعال ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished">جی Ûاں</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished">Ù†Ûیں</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation type="unfinished">Ú©Ùˆ</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation type="unfinished">سے</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation type="unfinished">کے لیے پابندی</translation>
+ </message>
+ <message>
+ <source>Never</source>
+ <translation type="unfinished">کبھی Ù†Ûیں</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation type="unfinished">نامعلوم</translation>
+ </message>
+</context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Amount:</source>
+ <translation type="unfinished">اور رقم</translation>
+ </message>
+ <message>
+ <source>&amp;Label:</source>
+ <translation type="unfinished">اور لیبل</translation>
+ </message>
+ <message>
+ <source>&amp;Message:</source>
+ <translation type="unfinished">اور پیغام</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 type="unfinished">ادائیگی Ú©ÛŒ درخواست Ú©Û’ ساتھ منسلک کرنے Ú©Û’ لیے ایک اختیاری پیغام، جو درخواست Ú©Û’ کھلنے پر ظاÛر Ûوگا۔ نوٹ: پیغام بٹ کوائن نیٹ ورک پر ادائیگی Ú©Û’ ساتھ Ù†Ûیں بھیجا جائے گا۔</translation>
+ </message>
+ <message>
+ <source>An optional label to associate with the new receiving address.</source>
+ <translation type="unfinished">نئے وصول Ú©Ù†Ù†Ø¯Û Ù¾ØªÛ’ Ú©Û’ ساتھ منسلک کرنے Ú©Û’ لیے ایک اختیاری لیبل۔</translation>
+ </message>
+ <message>
+ <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
+ <translation type="unfinished">درخواست کرنے Ú©Û’ لیے ایک اختیاری رقم۔ کسی مخصوص رقم Ú©ÛŒ درخواست Ù†Û Ú©Ø±Ù†Û’ Ú©Û’ لیے اسے خالی یا صÙر Ú†Ú¾ÙˆÚ‘ دیں۔</translation>
+ </message>
+ <message>
+ <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
+ <translation type="unfinished">وصول کرنے والے نئے پتے Ú©Û’ ساتھ منسلک کرنے Ú©Û’ لیے ایک اختیاری لیبل (آپ Ú©ÛŒ طر٠سے رسید Ú©ÛŒ شناخت Ú©Û’ لیے استعمال کیا جاتا ÛÛ’)Û” ÛŒÛ Ø§Ø¯Ø§Ø¦ÛŒÚ¯ÛŒ Ú©ÛŒ درخواست Ú©Û’ ساتھ بھی منسلک ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>An optional message that is attached to the payment request and may be displayed to the sender.</source>
+ <translation type="unfinished">ایک اختیاری پیغام جو ادائیگی Ú©ÛŒ درخواست Ú©Û’ ساتھ منسلک ÛÛ’ اور بھیجنے والے Ú©Ùˆ دکھایا جا سکتا ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>&amp;Create new receiving address</source>
+ <translation type="unfinished">اور وصول کرنے کا نیا Ù¾ØªÛ Ø¨Ù†Ø§Ø¦ÛŒÚº</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation type="unfinished">صاÙ</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">ایڈریس کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">کاپی اور لیبل</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">کاپی اور رقم</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">والیٹ Ú©Ùˆ غیر مقÙÙ„ Ù†Ûیں کیا جا سکا۔</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>Request payment to …</source>
+ <translation type="unfinished">ادائیگی کی درخواست کریں…</translation>
+ </message>
+ <message>
+ <source>Address:</source>
+ <translation type="unfinished">پتÛ:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation type="unfinished">رقم:</translation>
</message>
<message>
+ <source>Label:</source>
+ <translation type="unfinished">لیبل</translation>
+ </message>
+ <message>
+ <source>Message:</source>
+ <translation type="unfinished">پیغام</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">پرس:</translation>
</message>
@@ -563,6 +1870,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Copy &amp;Address</source>
<translation type="unfinished">کاپی پتÛ</translation>
</message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">اور تصویر محÙوظ کریں…</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -575,24 +1886,219 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">لیبل</translation>
</message>
<message>
+ <source>Message</source>
+ <translation type="unfinished">پیغام</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(کوئی لیبل Ù†Ûیں)</translation>
</message>
- </context>
+ <message>
+ <source>Requested</source>
+ <translation type="unfinished">درخواست کی۔</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
+ <source>Send Coins</source>
+ <translation type="unfinished">سکے بھیجیں۔</translation>
+ </message>
+ <message>
+ <source>Coin Control Features</source>
+ <translation type="unfinished">سکوں کے کنٹرول کی خصوصیات</translation>
+ </message>
+ <message>
+ <source>automatically selected</source>
+ <translation type="unfinished">خود بخود منتخب</translation>
+ </message>
+ <message>
<source>Insufficient funds!</source>
<translation type="unfinished">ناکاÙÛŒ Ùنڈز</translation>
</message>
<message>
+ <source>Quantity:</source>
+ <translation type="unfinished">مقدار:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">بائٹس:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation type="unfinished">رقم:</translation>
</message>
<message>
+ <source>Fee:</source>
+ <translation type="unfinished">Ùیس:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">Ùیس Ú©Û’ بعد:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">تبدیلی:</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 type="unfinished">اگر ÛŒÛ Ùعال ÛÛ’ØŒ لیکن تبدیلی کا Ù¾ØªÛ Ø®Ø§Ù„ÛŒ یا غلط ÛÛ’ØŒ تبدیلی Ú©Ùˆ نئے پیدا Ú©Ø±Ø¯Û Ù¾ØªÛ’ پر بھیج دیا جائے گا۔</translation>
+ </message>
+ <message>
+ <source>Transaction Fee:</source>
+ <translation type="unfinished">ٹرانزیکشن Ùیس:</translation>
+ </message>
+ <message>
+ <source>Warning: Fee estimation is currently not possible.</source>
+ <translation type="unfinished">انتباÛ: Ùیس کا ØªØ®Ù…ÛŒÙ†Û ÙÛŒ الحال ممکن Ù†Ûیں ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation type="unfinished">ÙÛŒ کلو بائٹ(kb)</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">چھپائیں</translation>
+ </message>
+ <message>
+ <source>Recommended:</source>
+ <translation type="unfinished">تجویز کردÛ:</translation>
+ </message>
+ <message>
+ <source>Custom:</source>
+ <translation type="unfinished">اپنی مرضی کے مطابق:</translation>
+ </message>
+ <message>
+ <source>Send to multiple recipients at once</source>
+ <translation type="unfinished">ایک ساتھ متعدد وصول کنندگان کو بھیجیں۔</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">Ù†Û Ûونے Ú©Û’ برابر</translation>
+ </message>
+ <message>
+ <source>Choose…</source>
+ <translation type="unfinished">منتخب کریں…</translation>
+ </message>
+ <message>
+ <source>Hide transaction fee settings</source>
+ <translation type="unfinished">لین دین Ú©ÛŒ Ùیس Ú©ÛŒ ترتیبات چھپائیں۔</translation>
+ </message>
+ <message>
+ <source>A too low fee might result in a never confirming transaction (read the tooltip)</source>
+ <translation type="unfinished">بÛت Ú©Ù… Ùیس Ú©Û’ نتیجے میں کبھی بھی تصدیق Ù†Û Ûونے والی لین دین ÛÙˆ سکتی ÛÛ’ (ٹول ٹپ پڑھیں)</translation>
+ </message>
+ <message>
+ <source>Confirmation time target:</source>
+ <translation type="unfinished">تصدیقی وقت کا ÛدÙ:</translation>
+ </message>
+ <message>
<source>Balance:</source>
<translation type="unfinished">بیلنس:</translation>
</message>
+ <message>
+ <source>Confirm the send action</source>
+ <translation type="unfinished">بھیجنے کی کارروائی کی تصدیق کریں۔</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">مقدار کاپی کریں</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">رقم کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Ùیس کاپی کریں</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">Ùیس Ú©Û’ بعد کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">بائٹس کاپی کریں</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">باقی Ø´Ø¯Û Ú©Ø§Ù¾ÛŒ کریں</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">تبدیلی کاپی کریں</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">Ù¾ÛÙ„Û’ اپنے Ûارڈویئر والیٹ Ú©Ùˆ جوڑیں۔</translation>
+ </message>
+ <message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">وصول کنندگان Ú©ÛŒ ÙÛرست کا Ø¬Ø§Ø¦Ø²Û Ù„ÛŒÙ†Û’ Ú©Û’ لیے "تÙصیلات دکھائیں..." پر Ú©Ù„Ú© کریں۔</translation>
+ </message>
+ <message>
+ <source>Sign failed</source>
+ <translation type="unfinished">دستخط ناکام Ûوگیا</translation>
+ </message>
+ <message>
+ <source>External signer not found</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">بیرونی دستخط Ú©Ù†Ù†Ø¯Û Ù†Ûیں ملا</translation>
+ </message>
+ <message>
+ <source>External signer failure</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">بیرونی دستخط Ú©Ù†Ù†Ø¯Û Ú©ÛŒ ناکامی۔</translation>
+ </message>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">لین دین کا ڈیٹا محÙوظ کریں۔</translation>
+ </message>
+ <message>
+ <source>External balance:</source>
+ <translation type="unfinished">بیرونی توازن:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">یا</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
+ <translation type="unfinished">Ø¨Ø±Ø§Û Ú©Ø±Ù…ØŒ اپنے لین دین کا Ø¬Ø§Ø¦Ø²Û Ù„ÛŒÚºÛ”</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation type="unfinished">ٹرانزیکشن Ùیس</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">کل رقم</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation type="unfinished">سکے بھیجنے کی تصدیق کریں۔</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation type="unfinished">وصول Ú©Ù†Ù†Ø¯Û Ú©Ø§ Ù¾ØªÛ Ø¯Ø±Ø³Øª Ù†Ûیں ÛÛ’Û” Ø¨Ø±Ø§Û Ú©Ø±Ù… Ø¯ÙˆØ¨Ø§Ø±Û Ú†ÛŒÚ© کریں۔</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation type="unfinished">ادا کرنے Ú©ÛŒ رقم 0 سے Ø²ÛŒØ§Ø¯Û Ûونی چاÛیے۔</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation type="unfinished">رقم آپ Ú©Û’ بیلنس سے Ø²ÛŒØ§Ø¯Û ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation type="unfinished">ڈپلیکیٹ Ù¾ØªÛ Ù…Ù„Ø§: پتے صر٠ایک بار استعمال کیے جائیں۔</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation type="unfinished">لین دین Ú©ÛŒ تخلیق ناکام ÛÙˆ گئی!</translation>
+ </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -601,16 +2107,150 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</translation>
</message>
<message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation type="unfinished">انتباÛ: غلط بٹ کوائن ایڈریس</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation type="unfinished">انتباÛ: نامعلوم تبدیلی کا پتÛ</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation type="unfinished">اپنی مرضی کے مطابق ایڈریس کی تبدیلی کی تصدیق کریں۔</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 type="unfinished">آپ Ù†Û’ تبدیلی Ú©Û’ لیے جو Ù¾ØªÛ Ù…Ù†ØªØ®Ø¨ کیا ÛÛ’ ÙˆÛ Ø§Ø³ والیٹ کا Ø­ØµÛ Ù†Ûیں ÛÛ’Û” آپ Ú©Û’ والیٹ میں موجود کوئی بھی یا تمام Ùنڈز اس پتے پر بھیجے جا سکتے Ûیں۔ کیا آپ Ú©Ùˆ یقین ÛÛ’ØŸ</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(کوئی لیبل Ù†Ûیں)</translation>
</message>
</context>
<context>
+ <name>SendCoinsEntry</name>
+ <message>
+ <source>&amp;Label:</source>
+ <translation type="unfinished">اور لیبل</translation>
+ </message>
+ <message>
+ <source>Choose previously used address</source>
+ <translation type="unfinished">Ù¾ÛÙ„Û’ استعمال Ø´Ø¯Û Ù¾ØªÛ Ú©Ø§ انتخاب کریں۔</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to send the payment to</source>
+ <translation type="unfinished">ادائیگی بھیجنے Ú©Û’ لیے بٹ کوائن کا پتÛ</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation type="unfinished">کلپ بورڈ سے Ù¾ØªÛ Ú†Ø³Ù¾Ø§Úº کریں۔</translation>
+ </message>
+ <message>
+ <source>Remove this entry</source>
+ <translation type="unfinished">اس اندراج Ú©Ùˆ Ûٹا دیں۔</translation>
+ </message>
+ <message>
+ <source>The amount to send in the selected unit</source>
+ <translation type="unfinished">منتخب یونٹ میں بھیجی جانے والی رقم</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 type="unfinished">بھیجی جانے والی رقم سے Ùیس کاٹی جائے گی۔ وصول Ú©Ù†Ù†Ø¯Û Ú©Ùˆ اس سے Ú©Ù… بٹ کوائنز موصول ÛÙˆÚº Ú¯Û’ جو آپ رقم Ú©Û’ خانے میں داخل کریں Ú¯Û’Û” اگر متعدد وصول کنندگان Ú©Ùˆ منتخب کیا جاتا ÛÛ’ØŒ تو Ùیس Ú©Ùˆ برابر تقسیم کیا جاتا ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Use available balance</source>
+ <translation type="unfinished">دستیاب بیلنس استعمال کریں۔</translation>
+ </message>
+ <message>
+ <source>Message:</source>
+ <translation type="unfinished">پیغام</translation>
+ </message>
+ <message>
+ <source>Enter a label for this address to add it to the list of used addresses</source>
+ <translation type="unfinished">استعمال Ø´Ø¯Û Ù¾ØªÙˆÚº Ú©ÛŒ ÙÛرست میں شامل کرنے Ú©Û’ لیے اس پتے Ú©Û’ لیے ایک لیبل درج کریں۔</translation>
+ </message>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ <message>
+ <source>Signatures - Sign / Verify a Message</source>
+ <translation type="unfinished">دستخط - ایک پیغام پر دستخط / تصدیق کریں۔</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 type="unfinished">آپ ÛŒÛ Ø«Ø§Ø¨Øª کرنے Ú©Û’ لیے اپنے پتوں Ú©Û’ ساتھ پیغامات/معاÛدوں پر دستخط کر سکتے Ûیں Ú©Û Ø¢Ù¾ ان پر بھیجے گئے بٹ کوائنز وصول کر سکتے Ûیں۔ Ûوشیار رÛیں Ú©Û Ú©Ø³ÛŒ بھی مبÛÙ… یا بے ترتیب پر دستخط Ù†Û Ú©Ø±ÛŒÚºØŒ Ú©ÛŒÙˆÙ†Ú©Û Ùریب دÛÛŒ Ú©Û’ حملے آپ Ú©Ùˆ اپنی شناخت پر دستخط کرنے Ú©Û’ لیے Ø¯Ú¾ÙˆÚ©Û Ø¯ÛŒÙ†Û’ Ú©ÛŒ کوشش کر سکتے Ûیں۔ صر٠مکمل تÙصیلی بیانات پر دستخط کریں جن سے آپ اتÙاق کرتے Ûیں۔</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to sign the message with</source>
+ <translation type="unfinished">پیغام پر دستخط کرنے Ú©Û’ لیے بٹ کوائن کا پتÛ</translation>
+ </message>
+ <message>
+ <source>Choose previously used address</source>
+ <translation type="unfinished">Ù¾ÛÙ„Û’ استعمال Ø´Ø¯Û Ù¾ØªÛ Ú©Ø§ انتخاب کریں۔</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation type="unfinished">کلپ بورڈ سے Ù¾ØªÛ Ú†Ø³Ù¾Ø§Úº کریں۔</translation>
+ </message>
+ <message>
+ <source>Enter the message you want to sign here</source>
+ <translation type="unfinished">ÙˆÛ Ù¾ÛŒØºØ§Ù… درج کریں جس پر آپ دستخط کرنا چاÛتے Ûیں۔</translation>
+ </message>
+ <message>
+ <source>Signature</source>
+ <translation type="unfinished">دستخط</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation type="unfinished">درج کیا گیا Ù¾ØªÛ ØºÙ„Ø· ÛÛ’Û”</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation type="unfinished">Ø¨Ø±Ø§Û Ú©Ø±Ù… Ù¾ØªÛ Ú†ÛŒÚ© کریں اور Ø¯ÙˆØ¨Ø§Ø±Û Ú©ÙˆØ´Ø´ کریں۔</translation>
+ </message>
+ <message>
+ <source>No error</source>
+ <translation type="unfinished">کوئی غلطی Ù†Ûیں۔</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation type="unfinished">پیغام پر دستخط ناکام ÛÙˆ گئے۔</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation type="unfinished">دستخط Ú©Ùˆ ÚˆÛŒ Ú©ÙˆÚˆ Ù†Ûیں کیا جا سکا۔</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation type="unfinished">Ø¨Ø±Ø§Û Ú©Ø±Ù… دستخط چیک کریں اور Ø¯ÙˆØ¨Ø§Ø±Û Ú©ÙˆØ´Ø´ کریں۔</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation type="unfinished">پیغام Ú©ÛŒ تصدیق ناکام ÛÙˆ گئی۔</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation type="unfinished">پیغام Ú©ÛŒ تصدیق ÛÙˆ گئی۔</translation>
+ </message>
+</context>
+<context>
<name>TransactionDesc</name>
<message>
<source>Date</source>
<translation type="unfinished">تاریخ</translation>
</message>
+ <message>
+ <source>From</source>
+ <translation type="unfinished">سے</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished">نامعلوم</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation type="unfinished">Ú©Ùˆ</translation>
+ </message>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
@@ -619,6 +2259,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</translation>
</message>
<message>
+ <source>Transaction fee</source>
+ <translation type="unfinished">ٹرانزیکشن Ùیس</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation type="unfinished">پیغام</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation type="unfinished">رقم</translation>
</message>
@@ -630,6 +2278,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">تاریخ</translation>
</message>
<message>
+ <source>Type</source>
+ <translation type="unfinished">قسم</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">لیبل</translation>
</message>
@@ -641,15 +2293,39 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>TransactionView</name>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">ایڈریس کاپی کریں۔</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">کاپی اور لیبل</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">کاپی اور رقم</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">لین دین اور شناخت Ú©ÛŒ تÙصیلات(ID) کاپی کریں۔</translation>
+ </message>
+ <message>
<source>Comma separated file</source>
<extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
<translation type="unfinished">کوما سے الگ Ùائل</translation>
</message>
<message>
+ <source>Confirmed</source>
+ <translation type="unfinished">تصدیق شدÛ</translation>
+ </message>
+ <message>
<source>Date</source>
<translation type="unfinished">تاریخ</translation>
</message>
<message>
+ <source>Type</source>
+ <translation type="unfinished">قسم</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">لیبل</translation>
</message>
@@ -674,6 +2350,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation type="unfinished">سکے بھیجیں۔</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">Ù¾ÛÙ„Û’ سے Ø·Û’ Ø´Ø¯Û ÙˆØ§Ù„ÛŒÙ¹</translation>
+ </message>
+</context>
+<context>
<name>WalletView</name>
<message>
<source>&amp;Export</source>
diff --git a/src/qt/locale/bitcoin_uz.ts b/src/qt/locale/bitcoin_uz.ts
new file mode 100644
index 0000000000..31614bbdea
--- /dev/null
+++ b/src/qt/locale/bitcoin_uz.ts
@@ -0,0 +1,225 @@
+<TS version="2.1" language="uz">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation type="unfinished">Manzil yoki yorliqni o'zgartirish uchun o'ng tugmani bosing</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation type="unfinished">Yangi manzil yaratish</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation type="unfinished">Yangi</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation type="unfinished">Belgilangan manzilni tizim hotirasiga saqlash</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation type="unfinished">&amp;Ko'chirmoq</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation type="unfinished">Yo&amp;pish</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">Tanlangan manzilni ro'yhatdan o'chiring</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">Qidirish uchun manzil yoki yorliqni kiriting</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Joriy ichki oynaning ichidagi malumotlarni faylga yuklab olish</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation type="unfinished">o'chirish</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">Tangalarni jo'natish uchun addressni tanlash</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">Tangalarni qabul qilib olish uchun manzilni tanlang</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation type="unfinished">tanlamoq</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation type="unfinished">Yuboriladigan manzillar</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation type="unfinished">Qabul qilinadigan manzillar</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 type="unfinished">Quyidagilar to'lovlarni yuborish uchun Bitcoin manzillaringizdir. Har doim yuborishdan oldin yuborilayotgan tangalar sonini va qabul qiluvchi manzilni tekshirib ko'ring.</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Bular to'lovlarni qabul qilishingiz uchun sizning Bitcoin manzillaringizdir. Yangi qabul qiluvchi manzil yaratish uchun qabul qilish varag'idagi ''Yangi qabul qilish manzilini yaratish'' ustiga bosing. Faqat 'legacy' turdagi manzillar bilan xisobga kirish mumkin.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished">&amp;manzildan nusxa olish</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">Yorliqni ko'chirish</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">O'zgartirmoq</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">Manzil ro'yhatini yuklab olish</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Vergul bilan ajratilgan fayl</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject</name>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>BitcoinGUI</name>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(sufficient to restore backups %n day(s) old)</source>
+ <extracomment>Explanatory text on the capability of the current prune target.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Vergul bilan ajratilgan fayl</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Joriy ichki oynaning ichidagi malumotlarni faylga yuklab olish</translation>
+ </message>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_uz@Cyrl.ts b/src/qt/locale/bitcoin_uz@Cyrl.ts
index 0d9895fcee..a6f342ddad 100644
--- a/src/qt/locale/bitcoin_uz@Cyrl.ts
+++ b/src/qt/locale/bitcoin_uz@Cyrl.ts
@@ -70,6 +70,12 @@
<translation type="unfinished">Улар тўловларни жўнатиш учун Ñизнинг Bitcoin манзилларингиз. Доимо тангаларни жўнатишдан олдин Ñумма ва қабул қилувчи манзилни текшириб кўринг. </translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Улар тўловларни қабул қилиш учун Ñизнинг Bitcoin манзилларингиз. Янги манзилларни Ñратиш учун қабул қилиш варағидаги "Янги қабул қилиш манзилини Ñратиш" уÑтига боÑинг.
+Фақат 'legacy' туридаги манзиллар билан ҳиÑобга кириш мумкин.</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">Манзилдан &amp;нуÑха олиш</translation>
</message>
@@ -86,6 +92,11 @@
<translation type="unfinished">Манзил рўйхатини ÑкÑпорт қилиш</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Вергул билан ажратилган файл</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
<translation type="unfinished">Манзил рўйхатини %1.га Ñақлашда хатолик юз берди. Яна уриниб кўринг.</translation>
@@ -118,23 +129,27 @@
</message>
<message>
<source>Enter passphrase</source>
- <translation type="unfinished">Махфий Ñузни киритинг</translation>
+ <translation type="unfinished">Махфий Ñўзни киритинг</translation>
</message>
<message>
<source>New passphrase</source>
- <translation type="unfinished">Янги махфий Ñуз</translation>
+ <translation type="unfinished">Янги махфий Ñўз</translation>
</message>
<message>
<source>Repeat new passphrase</source>
- <translation type="unfinished">Янги махфий Ñузни такрорланг</translation>
+ <translation type="unfinished">Янги махфий Ñўзни такрорланг</translation>
+ </message>
+ <message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">Махфий Ñўзни кўрÑатиш</translation>
</message>
<message>
<source>Encrypt wallet</source>
- <translation type="unfinished">Ҳамённи қодлаш</translation>
+ <translation type="unfinished">Ҳамённи шифрлаш</translation>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation type="unfinished">Ушбу операциÑни амалга ошириш учун ҳамённи қулфдан чиқариш парол Ñўзини талаб қилади.</translation>
+ <translation type="unfinished">Ушбу операциÑни амалга ошириш учун ҳамённи қулфдан чиқариш махфий Ñўзини талаб қилади.</translation>
</message>
<message>
<source>Unlock wallet</source>
@@ -158,7 +173,19 @@
</message>
<message>
<source>Wallet encrypted</source>
- <translation type="unfinished">Ҳамёни кодланган</translation>
+ <translation type="unfinished">Ҳамён шифрланган</translation>
+ </message>
+ <message>
+ <source>Wallet to be encrypted</source>
+ <translation type="unfinished">Шифрланадиган ҳамён</translation>
+ </message>
+ <message>
+ <source>Your wallet is about to be encrypted. </source>
+ <translation type="unfinished">Ҳамёнингиз шифрланиш арафаÑида.</translation>
+ </message>
+ <message>
+ <source>Your wallet is now encrypted. </source>
+ <translation type="unfinished">Ҳамёнингиз Ñнди шифрланади.</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>
@@ -664,6 +691,27 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
@@ -806,10 +854,12 @@
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">ТаÑдиқлаш танловларини рад қилиш</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">Ўзгаришлар амалга ошиши учун мижозни қайта ишга тушириш талаб қилинади.</translation>
</message>
<message>
@@ -1379,10 +1429,6 @@
<source>Message:</source>
<translation type="unfinished">Хабар</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Тўлов олувчи:</translation>
- </message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
@@ -1411,10 +1457,12 @@
<name>TransactionDesc</name>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/таÑдиқланмади</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 таÑдиқлашлар</translation>
</message>
<message>
@@ -1638,6 +1686,11 @@
<translation type="unfinished">Ўтказмалар тарихини ÑкÑпорт қилиш</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Вергул билан ажратилган файл</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation type="unfinished">ТаÑдиқланди</translation>
</message>
diff --git a/src/qt/locale/bitcoin_uz@Latn.ts b/src/qt/locale/bitcoin_uz@Latn.ts
index d18d84231f..4f244827f0 100644
--- a/src/qt/locale/bitcoin_uz@Latn.ts
+++ b/src/qt/locale/bitcoin_uz@Latn.ts
@@ -14,6 +14,10 @@
<translation type="unfinished">&amp;Yangi</translation>
</message>
<message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation type="unfinished">Tanlangan manzilni tizim buferiga nusxalash</translation>
+ </message>
+ <message>
<source>&amp;Copy</source>
<translation type="unfinished">&amp;Nusxalash</translation>
</message>
@@ -22,14 +26,86 @@
<translation type="unfinished">Yo&amp;pish</translation>
</message>
<message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">Ro'yxatdan hozir tanlangan manzilni o'chiring</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">Qidirish uchun manzil yoki yorliqni kiriting</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Joriy yorliqdagi ma'lumotlarni faylga eksport qilish</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;Eksport</translation>
+ </message>
+ <message>
<source>&amp;Delete</source>
<translation type="unfinished">&amp;O'chirish</translation>
</message>
<message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">Coin yuborish uchun manzilni tanlang</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">Coinlarni qabul qilish uchun manzilni tanlang</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation type="unfinished">&amp;Tanlash</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation type="unfinished">Manzillarni yuborish</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation type="unfinished">Qabul qilish manzillari</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 type="unfinished">Quyida to'lovlarni jo'natish uchun Bitcoin manzillaringiz. Coinlarni yuborishdan oldin har doim miqdor va qabul qilish manzilini tekshiring.</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">Bular to'lovlarni qabul qilish uchun mo'ljallangan Bitkoin manzillar. Yangi manzillar yaratish uchun 'Yangi qabul qilish manzili yaratish' tugmasini ishlating.
+Kirish faqat 'legacy' turidagi manzillar uchun.</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation type="unfinished">&amp;Manzillarni nusxalash</translation>
</message>
- </context>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">Nusxalash &amp;Yorliq</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;Tahrirlash</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">Manzillar ro'yxatini eksport qilish</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Vergul yordamida ajratilgan fayl</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
+ <translation type="unfinished">Manzillarni ro'yxatini %1 ga saqlashda xatolik yuzaga keldi. Iltimos, qayta urinib ko'ring</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">Eksport qilish amalga oshmadi</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
<message>
@@ -40,9 +116,184 @@
<source>Address</source>
<translation type="unfinished">Manzil</translation>
</message>
- </context>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(Yorliqlar mavjud emas)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation type="unfinished">Parollar dialogi</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation type="unfinished">Parolni kiriting</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation type="unfinished">Yangi parol</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation type="unfinished">Yangi parolni qaytadan kirgizing</translation>
+ </message>
+ <message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">Parolni ko'rsatish</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">Hamyonni shifrlash</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation type="unfinished">Bu operatsiya uchun hamyoningiz paroli kerak bo'ladi.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation type="unfinished">Hamyonni qulfdan chiqarish</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation type="unfinished">Parolni almashtirish</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation type="unfinished">Hamyon shifrlanishini tasdiqlang</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 type="unfinished">Eslatma: Agar hamyoningizni shifrlasangiz va parolni unutib qo'ysangiz, siz &lt;b&gt;BARCHA BITCOINLARINGIZNI YO'QOTASIZ&lt;/b&gt;! </translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished">Haqiqatan ham hamyoningizni shifrlamoqchimisiz?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished">Hamyon shifrlangan</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase for 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 type="unfinished">Hamyon uchun yangi maxfiy so'zni kiriting. &lt;br/&gt;Iltimos, &lt;b&gt;10 va undan ortiq istalgan&lt;/b&gt; yoki &lt;b&gt;8 va undan ortiq so'zlardan&lt;/b&gt; iborat maxfiy so'zdan foydalaning.</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase for the wallet.</source>
+ <translation type="unfinished">Hamyonning oldingi va yangi maxfiy so'zlarini kiriting</translation>
+ </message>
+ <message>
+ <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation type="unfinished">Shuni yodda tutingki, hamyonni shifrlash kompyuterdagi virus yoki zararli dasturlar sizning bitcoinlaringizni o'g'irlashidan to'liq himoyalay olmaydi.</translation>
+ </message>
+ <message>
+ <source>Wallet to be encrypted</source>
+ <translation type="unfinished">Hamyon shifrlanmoqda</translation>
+ </message>
+ <message>
+ <source>Your wallet is about to be encrypted. </source>
+ <translation type="unfinished">Hamyon shifrlanish arafasida</translation>
+ </message>
+ <message>
+ <source>Your wallet is now encrypted. </source>
+ <translation type="unfinished">Hamyoningiz shifrlangan</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 type="unfinished">ESLATMA: Siz eski hamyoningiz joylashgan fayldan yaratgan kopiyalaringizni yangi shifrlangan hamyon fayliga almashtirishingiz lozim. Maxfiylik siyosati tufayli, yangi shifrlangan hamyondan foydalanishni boshlashingiz bilanoq eski nusxalar foydalanishga yaroqsiz holga keltiriladi.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation type="unfinished">Hamyon shifrlanishi muvaffaqiyatsiz amalga oshdi</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation type="unfinished">Ichki xatolik tufayli hamyon shifrlanishi amalga oshmadi.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">Kiritilgan maxfiy so'zlar bir-biriga mos kelmayapti.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation type="unfinished">Hamyonni qulfdan chiqarib bo'lmadi</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation type="unfinished">Noto'g'ri maxfiy so'z kiritildi</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished">Hamyon uchun kiritilgan maxfiy so'z yangisiga almashtirildi.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished">Eslatma: Caps Lock tugmasi yoniq!</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>Banned Until</source>
+ <translation type="unfinished">gacha kirish taqiqlanadi</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">qo'shimcha istisno</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">Fatal xatolik yuz berdi. %1 xavfsiz ravishda davom eta olmaydi va tizimni tark etadi. </translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">Ichki xatolik</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Ichki xatolik yuzaga keldi. %1 xavfsiz protsessni davom ettirishga harakat qiladi. Bu kutilmagan xato boʻlib, uni quyida tavsiflanganidek xabar qilish mumkin.</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
+ <message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Sozlamalarni asliga qaytarishni xohlaysizmi yoki o'zgartirishlar saqlanmasinmi?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Fatal xatolik yuz berdi. Sozlamalar fayli tahrirlashga yaroqliligini tekshiring yoki -nosettings bilan davom etishga harakat qiling.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation type="unfinished">Xatolik. Belgilangan "%1" mavjud emas.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">Xatolik. %1 ni tahlil qilish imkonsiz.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">Xatolik: %1</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 hali tizimni xavfsiz ravishda tark etgani yo'q...</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished">noma'lum</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Miqdor</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
@@ -87,33 +338,1208 @@
</message>
</context>
<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Sozlamalar fayli o'qishga yaroqsiz</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Sozlamalar fayli yaratish uchun yaroqsiz</translation>
+ </message>
+ <message>
+ <source>Unable to start HTTP server. See debug log for details.</source>
+ <translation type="unfinished">HTTP serverni ishga tushirib bo'lmadi. Tafsilotlar uchun disk raskadrovka jurnaliga qarang.</translation>
+ </message>
+ <message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">Bloklar tekshirilmoqda…</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)…</source>
+ <translation type="unfinished">Hamyon(lar) tekshirilmoqda…</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation type="unfinished">Hamyonni qayta yozish kerak: bajarish uchun 1%s ni qayta ishga tushiring</translation>
+ </message>
+</context>
+<context>
<name>BitcoinGUI</name>
+ <message>
+ <source>&amp;Overview</source>
+ <translation type="unfinished">&amp;Umumiy ko'rinish</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation type="unfinished">Hamyonning umumiy ko'rinishini ko'rsatish</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation type="unfinished">&amp;Tranzaksiyalar</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation type="unfinished">Tranzaksiyalar tarixini ko'rib chiqish</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation type="unfinished">Chi&amp;qish</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation type="unfinished">Dasturni tark etish</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation type="unfinished">&amp;%1 haqida</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation type="unfinished">%1 haqida axborotni ko'rsatish</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation type="unfinished">&amp;Qt haqida</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation type="unfinished">&amp;Qt haqidagi axborotni ko'rsatish</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation type="unfinished">%1 konfiguratsiya sozlamalarini o'zgartirish</translation>
+ </message>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Yangi hamyon yaratish</translation>
+ </message>
+ <message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Kichraytirish</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Hamyon</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">Mobil tarmoq faoliyati o'chirilgan</translation>
+ </message>
+ <message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation type="unfinished">Proksi &lt;b&gt;yoqildi&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation type="unfinished">Bitkoin manziliga coinlarni yuborish</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation type="unfinished">Hamyon nusxasini boshqa joyga</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation type="unfinished">Hamyon shifrlanishi uchun ishlatilgan maxfiy so'zni almashtirish</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation type="unfinished">&amp;Yuborish</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation type="unfinished">&amp;Qabul qilish</translation>
+ </message>
+ <message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;Sozlamalar...</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;Hamyonni shifrlash...</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">Hamyonga tegishli bo'lgan maxfiy so'zlarni shifrlash</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;Hamyon nusxasi...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;Maxfiy so'zni o'zgartirish...</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">Kirish &amp;xabarlashish</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">Bitkoin manzillarga ega ekaningizni tasdiqlash uchun xabarni signlang</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;Xabarni tasdiqlash</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">Xabar belgilangan Bitkoin manzillari bilan imzolanganligiga ishonch hosil qilish uchun ularni tasdiqlang</translation>
+ </message>
+ <message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;PSBT ni fayldan yuklash...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">&amp;URL manzilni ochish</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">Hamyonni yopish</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">Hamyonni yaratish...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">Barcha hamyonlarni yopish...</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation type="unfinished">&amp;Fayl</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation type="unfinished">&amp;Sozlamalar</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation type="unfinished">&amp;Yordam</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation type="unfinished">Yorliqlar menyusi</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Sarlavhalar sinxronlashtirilmoqda (%1%)...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Internet bilan sinxronlash...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Diskdagi bloklarni indekslash</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Diskdagi bloklarni protsesslash</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Diskdagi bloklarni qayta indekslash...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Pirlarga ulanish...</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation type="unfinished">To'lovlarni so'rash(QR kolar va bitkoin yaratish: URL manzillar)</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation type="unfinished">Manzillar va yorliqlar ro'yxatini ko'rsatish</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation type="unfinished">Qabul qilish manzillari va yorliqlar ro'yxatini ko'rsatish</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation type="unfinished">&amp;Command-line sozlamalari</translation>
+ </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>Tranzaksiya tarixining %n blok(lar)i qayta ishlandi.</numerusform>
<numerusform />
</translation>
</message>
+ <message>
+ <source>%1 behind</source>
+ <translation type="unfinished">%1 yonida</translation>
+ </message>
+ <message>
+ <source>Catching up…</source>
+ <translation type="unfinished">Yetkazilmoqda...</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation type="unfinished">%1 oldin oxirgi marta blok qabul qilingan edi.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation type="unfinished">Shundan keyingi operatsiyalar hali ko'rinmaydi.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Xatolik</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation type="unfinished">Eslatma</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation type="unfinished">Informatsiya</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation type="unfinished">Hozirgi kunda</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">Qisman signlangan Bitkoin tranzaksiyasini yuklash</translation>
+ </message>
+ <message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">&amp;Nusxalanganlar dan PSBT ni yuklash</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">Nusxalanganlar qisman signlangan Bitkoin tranzaksiyalarini yuklash</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">Node oynasi</translation>
+ </message>
+ <message>
+ <source>Open node debugging and diagnostic console</source>
+ <translation type="unfinished">Node debuglash va tahlil konsolini ochish</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">&amp;Yuborish manzillari</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">&amp;Qabul qilish manzillari</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI</source>
+ <translation type="unfinished">Bitkoinni ochish: URI</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <translation type="unfinished">Hamyonni ochish</translation>
+ </message>
+ <message>
+ <source>Open a wallet</source>
+ <translation type="unfinished">Hamyonni ochish</translation>
+ </message>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">Hamyonni yopish</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">Barcha hamyonlarni yopish</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation type="unfinished">Yozilishi mumkin bo'lgan command-line sozlamalar ro'yxatini olish uchun %1 yordam xabarini ko'rsatish</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">Umumiy ko'rinish menyusidagi qiymatlarni maskirovka qilish</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">standart hamyon</translation>
+ </message>
+ <message>
+ <source>No wallets available</source>
+ <translation type="unfinished">Hamyonlar mavjud emas</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">Hamyon nomi</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;Oyna</translation>
+ </message>
+ <message>
+ <source>Zoom</source>
+ <translation type="unfinished">Kattalashtirish</translation>
+ </message>
+ <message>
+ <source>Main Window</source>
+ <translation type="unfinished">Asosiy Oyna</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation type="unfinished">%1 mijoz </translation>
+ </message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Yashirish</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">Ko'&amp;rsatish</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>Bitkoin tarmog'iga %n aktiv ulanishlar.</numerusform>
<numerusform />
</translation>
</message>
+ <message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Ko'proq sozlamalar uchun bosing.</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Pirlar oynasini ko'rsatish</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">Ijtimoiy tarmoq faoliyatini cheklash</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">Ijtimoiy tarmoq faoliyatini yoqish</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">Xatolik: %1</translation>
+ </message>
+ <message>
+ <source>Warning: %1</source>
+ <translation type="unfinished">Ogohlantirish: %1</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation type="unfinished">Sana: %1</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation type="unfinished">Miqdor: %1
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation type="unfinished">Hamyon: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation type="unfinished">Tip: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation type="unfinished">Yorliq: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation type="unfinished">Manzil: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation type="unfinished">Yuborilgan tranzaksiya</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation type="unfinished">Kelayotgan tranzaksiya</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD kalit yaratish &lt;b&gt;imkonsiz&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD kalit yaratish &lt;b&gt;imkonsiz&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">Maxfiy kalit &lt;b&gt;o'chiq&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 type="unfinished">Hamyon &lt;b&gt;shifrlangan&lt;/b&gt; va hozircha &lt;b&gt;ochiq&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 type="unfinished">Hamyon &lt;b&gt;shifrlangan&lt;/b&gt; va hozirda&lt;b&gt;qulflangan&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">Asl xabar:</translation>
+ </message>
+</context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">Miqdorlarni ko'rsatish birligi. Boshqa birlik tanlash uchun bosing.</translation>
+ </message>
+</context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Coin Selection</source>
+ <translation type="unfinished">Coin tanlash</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">Miqdor:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">Baytlar:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Miqdor:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">Narx:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">To'lovdan keyin:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">O'zgartirish:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation type="unfinished">hammasini(hech qaysini) tanlash</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation type="unfinished">Daraxt rejimi</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation type="unfinished">Ro'yxat rejimi</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Miqdor</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation type="unfinished">Yorliq orqali qabul qilingan</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation type="unfinished">Manzil orqali qabul qilingan</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Sana</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation type="unfinished">Tasdiqlar</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">Tasdiqlangan</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Qiymatni nusxalash</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Manzilni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Yorliqni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">&amp;Miqdorni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Tranzaksiya &amp;IDsi ni va chiquvchi indeksni nusxalash</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">Sarflanmagan miqdorlarni q&amp;ulflash</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">Sarflanmaqan tranzaksiyalarni &amp;qulfdan chiqarish</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">Miqdorni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Narxni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">'To'lovdan keyin' ni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Baytlarni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">'Dust' larni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">O'zgarishni nusxalash</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation type="unfinished">(%1 qulflangan)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation type="unfinished">ha</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation type="unfinished">yo'q</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished">Agar qabul qiluvchi joriy 'dust' chegarasidan kichikroq miqdor olsa, bu yorliq qizil rangga aylanadi</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation type="unfinished">Har bir kiruvchi +/- %1 satoshiga farq qilishi mumkin.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(Yorliqlar mavjud emas)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation type="unfinished">%1(%2) dan o'zgartirish</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation type="unfinished">(o'zgartirish)</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletActivity</name>
+ <message>
+ <source>Create Wallet</source>
+ <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
+ <translation type="unfinished">Hamyon yaratish</translation>
+ </message>
+ <message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">Hamyon yaratilmoqda &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Create wallet failed</source>
+ <translation type="unfinished">Hamyon yaratilishi amalga oshmadi</translation>
+ </message>
+ <message>
+ <source>Create wallet warning</source>
+ <translation type="unfinished">Hamyon yaratish ogohlantirishi</translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">Signerlarni ro'yxat shakliga keltirib bo'lmaydi</translation>
+ </message>
</context>
<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">Hamyonni yuklash</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">Hamyonlar yuklanmoqda...</translation>
+ </message>
+</context>
+<context>
+ <name>OpenWalletActivity</name>
+ <message>
+ <source>Open wallet failed</source>
+ <translation type="unfinished">Hamyonni ochib bo'lmaydi</translation>
+ </message>
+ <message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">Hamyonni ochish ogohlantirishi</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">standart hamyon</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
+ <translation type="unfinished">Hamyonni ochish</translation>
+ </message>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">Hamyonni ochish &lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
+<context>
+ <name>WalletController</name>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">Hamyonni yopish</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">Ushbu hamyonni&lt;i&gt;%1&lt;/i&gt; yopmoqchi ekaningizga ishonchingiz komilmi?</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">Agar 'pruning' funksiyasi o'chirilgan bo'lsa, hamyondan uzoq vaqt foydalanmaslik butun zanjirnni qayta sinxronlashga olib kelishi mumkin.</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">Barcha hamyonlarni yopish</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">Hamma hamyonlarni yopmoqchimisiz?</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletDialog</name>
+ <message>
+ <source>Create Wallet</source>
+ <translation type="unfinished">Hamyon yaratish</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <translation type="unfinished">Hamyon nomi</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation type="unfinished">Hamyon</translation>
+ </message>
+ <message>
+ <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
+ <translation type="unfinished">Hamyonni shifrlash. Hamyon siz tanlagan maxfiy so'z bilan shifrlanadi</translation>
+ </message>
+ <message>
+ <source>Encrypt Wallet</source>
+ <translation type="unfinished">Hamyonni shifrlash</translation>
+ </message>
+ <message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">Qo'shimcha sozlamalar</translation>
+ </message>
+ <message>
+ <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
+ <translation type="unfinished">Ushbu hamyon uchun maxfiy kalitlarni o'chirish. Maxfiy kalitsiz hamyonlar maxfiy kalitlar yoki import qilingan maxfiy kalitlar, shuningdek, HD seedlarga ega bo'la olmaydi.</translation>
+ </message>
+ <message>
+ <source>Disable Private Keys</source>
+ <translation type="unfinished">Maxfiy kalitlarni faolsizlantirish</translation>
+ </message>
+ <message>
+ <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
+ <translation type="unfinished">Bo'sh hamyon yaratish. Bo'sh hamyonlarga keyinchalik maxfiy kalitlar yoki manzillar import qilinishi mumkin, yana HD seedlar ham o'rnatilishi mumkin.</translation>
+ </message>
+ <message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">Bo'sh hamyon yaratish</translation>
+ </message>
+ <message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">scriptPubKey yaratishda izohlovchidan foydalanish</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">Izohlovchi hamyon</translation>
+ </message>
+ <message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Uskuna hamyoni kabi tashqi signing qurilmasidan foydalaning. Avval hamyon sozlamalarida tashqi signer skriptini sozlang.</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">Tashqi signer</translation>
+ </message>
+ <message>
+ <source>Create</source>
+ <translation type="unfinished">Yaratmoq</translation>
+ </message>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished">Sqlite yordamisiz tuzilgan (deskriptor hamyonlari uchun talab qilinadi)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Tashqi signing yordamisiz tuzilgan (tashqi signing uchun zarur)</translation>
+ </message>
+</context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation type="unfinished">Manzilni tahrirlash</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation type="unfinished">&amp;Yorliq</translation>
+ </message>
+ <message>
+ <source>The label associated with this address list entry</source>
+ <translation type="unfinished">Bu manzillar roʻyxati yozuvi bilan bogʻlangan yorliq</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation type="unfinished">Bu manzillar roʻyxati yozuvi bilan bogʻlangan yorliq. Bu faqat manzillarni yuborish uchun o'zgartirilishi mumkin.</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation type="unfinished">&amp;Manzil</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation type="unfinished">Yangi jo'natish manzili</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation type="unfinished">Qabul qiluvchi manzilini tahrirlash</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation type="unfinished">Yuboruvchi manzilini tahrirlash</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation type="unfinished">%1 manzil Bitcoin da mavjud manzil emas</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 type="unfinished">Yuboruvchi(%1manzil) va qabul qiluvchi(%2manzil) bir xil bo'lishi mumkin emas</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation type="unfinished">Kiritilgan %1manzil allaqachon %2yorlig'i bilan manzillar kitobida</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">Hamyonni ochish imkonsiz</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation type="unfinished">Yangi kalit yaratilishi amalga oshmadi.</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>A new data directory will be created.</source>
+ <translation type="unfinished">Yangi ma'lumot manzili yaratiladi.</translation>
+ </message>
+ <message>
+ <source>name</source>
+ <translation type="unfinished">nom</translation>
+ </message>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation type="unfinished">Manzil allaqachon yaratilgan. %1 ni qo'shing, agar yangi manzil yaratmoqchi bo'lsangiz.</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation type="unfinished">Ushbu manzil allaqachon egallangan.</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation type="unfinished">Ma'lumotlar bu yerda saqlanishi mumkin emas.</translation>
+ </message>
+</context>
+<context>
<name>Intro</name>
+ <message>
+ <source>Bitcoin</source>
+ <translation type="unfinished">Bitkoin</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation type="unfinished">Kamida %1 GB ma'lumot bu yerda saqlanadi va vaqtlar davomida o'sib boradi</translation>
+ </message>
+ <message>
+ <source>Approximately %1 GB of data will be stored in this directory.</source>
+ <translation type="unfinished">Bu katalogda %1 GB ma'lumot saqlanadi</translation>
+ </message>
<message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(%n kun oldingi zaxira nusxalarini tiklash uchun etarli)</numerusform>
<numerusform />
</translation>
</message>
+ <message>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation type="unfinished"> Bitcoin blok zanjirining%1 nusxasini yuklab oladi va saqlaydi</translation>
+ </message>
+ <message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished">Hamyon ham ushbu katalogda saqlanadi.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation type="unfinished">Xatolik: Belgilangan %1 ma'lumotlar katalogini yaratib bo'lmaydi</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Xatolik</translation>
+ </message>
+ <message>
+ <source>Welcome</source>
+ <translation type="unfinished">Xush kelibsiz</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation type="unfinished">%1 ga xush kelibsiz</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 type="unfinished">Birinchi marta dastur ishga tushirilganda, siz %1 o'z ma'lumotlarini qayerda saqlashini tanlashingiz mumkin</translation>
+ </message>
+ <message>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">Blok zanjiri xotirasini bungacha cheklash:</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
+ <translation type="unfinished">Bu sozlamani qaytarish butun blok zanjirini qayta yuklab olishni talab qiladi. Avval to'liq zanjirni yuklab olish va keyinroq kesish kamroq vaqt oladi. Ba'zi qo'shimcha funksiyalarni cheklaydi.</translation>
+ </message>
+ <message>
+ <source> GB</source>
+ <translation type="unfinished">GB</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 type="unfinished">Ushbu dastlabki sinxronlash juda qiyin va kompyuteringiz bilan ilgari sezilmagan apparat muammolarini yuzaga keltirishi mumkin. Har safar %1 ni ishga tushirganingizda, u yuklab olish jarayonini qayerda to'xtatgan bo'lsa, o'sha yerdan boshlab davom ettiradi.</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 type="unfinished">Agar siz blok zanjirini saqlashni cheklashni tanlagan bo'lsangiz (pruning), eski ma'lumotlar hali ham yuklab olinishi va qayta ishlanishi kerak, ammo diskdan kamroq foydalanish uchun keyin o'chiriladi.</translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation type="unfinished">Standart ma'lumotlar katalogidan foydalanish</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation type="unfinished">O'zingiz xohlagan ma'lumotlar katalogidan foydalanish:</translation>
+ </message>
+</context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation type="unfinished">versiya</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished">%1 haqida</translation>
+ </message>
+ <message>
+ <source>Command-line options</source>
+ <translation type="unfinished">Command-line sozlamalari</translation>
+ </message>
+</context>
+<context>
+ <name>ShutdownWindow</name>
+ <message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 yopilmoqda...</translation>
+ </message>
+ <message>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation type="unfinished">Bu oyna paydo bo'lmagunicha kompyuterni o'chirmang.</translation>
+ </message>
+</context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">Forma</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 type="unfinished">So'nggi tranzaksiyalar hali ko'rinmasligi mumkin, shuning uchun hamyoningiz balansi noto'g'ri ko'rinishi mumkin. Sizning hamyoningiz bitkoin tarmog'i bilan sinxronlashni tugatgandan so'ng, quyida batafsil tavsiflanganidek, bu ma'lumot to'g'rilanadi.</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 type="unfinished">Hali ko'rsatilmagan tranzaksiyalarga bitkoinlarni sarflashga urinish tarmoq tomonidan qabul qilinmaydi.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation type="unfinished">qolgan bloklar soni</translation>
+ </message>
+ <message>
+ <source>Unknown…</source>
+ <translation type="unfinished">Noma'lum...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">hisoblanmoqda...</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">Oxirgi bloklash vaqti</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation type="unfinished">O'sish</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation type="unfinished">Harakatning soatiga o'sishi</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation type="unfinished">Sinxronizatsiya yakunlanishiga taxminan qolgan vaqt</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">Yashirmoq</translation>
+ </message>
+ <message>
+ <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
+ <translation type="unfinished">%1 sinxronlanmoqda. U pirlardan sarlavhalar va bloklarni yuklab oladi va ularni blok zanjirining uchiga yetguncha tasdiqlaydi.</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Noma'lum. Sarlavhalarni sinxronlash(%1, %2%)...</translation>
+ </message>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
+ <message>
+ <source>Open bitcoin URI</source>
+ <translation type="unfinished">Bitkoin URI sini ochish</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
+ <translation type="unfinished">Manzilni qo'shib qo'yish</translation>
+ </message>
+</context>
+<context>
+ <name>OptionsDialog</name>
+ <message>
+ <source>Options</source>
+ <translation type="unfinished">Sozlamalar</translation>
+ </message>
+ <message>
+ <source>&amp;Main</source>
+ <translation type="unfinished">&amp;Asosiy</translation>
+ </message>
+ <message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation type="unfinished">%1 ni sistemaga kirilishi bilanoq avtomatik ishga tushirish.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation type="unfinished">%1 ni sistemaga kirish paytida &amp;ishga tushirish</translation>
+ </message>
+ <message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Do'kon tranzaksiyalari katta xotira talab qilgani tufayli pruning ni yoqish sezilarli darajada xotirada joy kamayishiga olib keladi. Barcha bloklar hali ham to'liq tasdiqlangan. Bu sozlamani qaytarish butun blok zanjirini qayta yuklab olishni talab qiladi.</translation>
+ </message>
+ <message>
+ <source>Size of &amp;database cache</source>
+ <translation type="unfinished">&amp;Ma'lumotlar bazasi hajmi</translation>
+ </message>
+ <message>
+ <source>Number of script &amp;verification threads</source>
+ <translation type="unfinished">Skriptni &amp;tekshirish thread lari soni</translation>
+ </message>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation type="unfinished">Proksi IP manzili (masalan: 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 type="unfinished">Taqdim etilgan standart SOCKS5 proksi-serveridan ushbu tarmoq turi orqali pirlar bilan bog‘lanish uchun foydalanilganini ko'rsatadi.</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 type="unfinished">Oyna yopilganda dasturdan chiqish o'rniga minimallashtirish. Ushbu parametr yoqilganda, dastur faqat menyuda Chiqish ni tanlagandan keyin yopiladi.</translation>
+ </message>
+ <message>
+ <source>Open the %1 configuration file from the working directory.</source>
+ <translation type="unfinished">%1 konfiguratsion faylini ishlash katalogidan ochish.</translation>
+ </message>
+ <message>
+ <source>Open Configuration File</source>
+ <translation type="unfinished">Konfiguratsion faylni ochish</translation>
+ </message>
+ <message>
+ <source>Reset all client options to default.</source>
+ <translation type="unfinished">Barcha mijoz sozlamalarini asl holiga qaytarish.</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation type="unfinished">Sozlamalarni &amp;qayta o'rnatish</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation type="unfinished">&amp;Internet tarmog'i</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation type="unfinished">&amp;Blok xotirasini bunga kesish:</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Bu sozlamani qaytarish butun blok zanjirini qayta yuklab olishni talab qiladi.</translation>
+ </message>
+ <message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">Ma'lumotlar bazasi keshining maksimal hajmi. Kattaroq kesh tezroq sinxronlashtirishga hissa qo'shishi mumkin, ya'ni foyda kamroq sezilishi mumkin.</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Skriptni tekshirish ip lari sonini belgilang. </translation>
+ </message>
+ <message>
+ <source>(0 = auto, &lt;0 = leave that many cores free)</source>
+ <translation type="unfinished">(0 = avtomatik, &lt;0 = bu yadrolarni bo'sh qoldirish)</translation>
+ </message>
+ <message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Bu sizga yoki uchinchi tomon vositasiga command-line va JSON-RPC buyruqlari orqali node bilan bog'lanish imkonini beradi.</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">R&amp;PC serverni yoqish</translation>
+ </message>
+ <message>
+ <source>W&amp;allet</source>
+ <translation type="unfinished">H&amp;amyon</translation>
+ </message>
+ <message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Chegirma to'lovini standart qilib belgilash kerakmi yoki yo'qmi?</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Standart bo'yicha chegirma belgilash</translation>
+ </message>
+ <message>
+ <source>Expert</source>
+ <translation type="unfinished">Ekspert</translation>
+ </message>
+ <message>
+ <source>Enable coin &amp;control features</source>
+ <translation type="unfinished">Tangalarni &amp;nazorat qilish funksiyasini yoqish</translation>
+ </message>
+ <message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">&amp;PSBT nazoratini yoqish</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">PSBT boshqaruvlarini ko'rsatish kerakmi?</translation>
+ </message>
+ <message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">Tashqi Signer(masalan: hamyon apparati)</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">&amp;Tashqi signer skripti yo'li</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;Oyna</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Tashqi signing yordamisiz tuzilgan (tashqi signing uchun zarur)</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Xatolik</translation>
+ </message>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">Forma</translation>
+ </message>
</context>
<context>
<name>PeerTableModel</name>
@@ -124,14 +1550,124 @@
</message>
</context>
<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">Node oynasi</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">Oxirgi bloklash vaqti</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;Manzilni nusxalash</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Manzilni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Yorliqni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">&amp;Miqdorni nusxalash</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">Hamyonni ochish imkonsiz</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Miqdor:</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">Hamyon</translation>
+ </message>
+ </context>
+<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation type="unfinished">Sana</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">Yorliq</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(Yorliqlar mavjud emas)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">Miqdor:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">Baytlar:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">Miqdor:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">Narx:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">To'lovdan keyin:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">O'zgartirish:</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">Yashirmoq</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">Miqdorni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">Qiymatni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">Narxni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">'To'lovdan keyin' ni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">Baytlarni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">'Dust' larni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">O'zgarishni nusxalash</translation>
+ </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -139,9 +1675,35 @@
<numerusform />
</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(Yorliqlar mavjud emas)</translation>
+ </message>
+</context>
+<context>
+ <name>SendCoinsEntry</name>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation type="unfinished">Manzilni qo'shib qo'yish</translation>
+ </message>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation type="unfinished">Manzilni qo'shib qo'yish</translation>
+ </message>
</context>
<context>
<name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Sana</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished">noma'lum</translation>
+ </message>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
@@ -149,17 +1711,54 @@
<numerusform />
</translation>
</message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">Miqdor</translation>
+ </message>
</context>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation type="unfinished">Sana</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">Yorliq</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(Yorliqlar mavjud emas)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;Manzilni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">&amp;Yorliqni nusxalash</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">&amp;Miqdorni nusxalash</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">Vergul yordamida ajratilgan fayl</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">Tasdiqlangan</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">Sana</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">Yorliq</translation>
</message>
@@ -167,5 +1766,38 @@
<source>Address</source>
<translation type="unfinished">Manzil</translation>
</message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">Eksport qilish amalga oshmadi</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">Yangi hamyon yaratish</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Xatolik</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">standart hamyon</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;Eksport</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Joriy yorliqdagi ma'lumotlarni faylga eksport qilish</translation>
+ </message>
</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_vi.ts b/src/qt/locale/bitcoin_vi.ts
index 8dd11d884f..63f5ed473e 100644
--- a/src/qt/locale/bitcoin_vi.ts
+++ b/src/qt/locale/bitcoin_vi.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation type="unfinished">Nhấp chuột phải để sửa địa chỉ hoặc nhãn</translation>
+ <translation type="unfinished">Nhấn chuột phải để sửa địa chỉ hoặc nhãn</translation>
</message>
<message>
<source>Create a new address</source>
@@ -15,88 +15,41 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation type="unfinished">Sao chép các địa chỉ đã được chá»n vào bá»™ nhá»› tạm thá»i của hệ thống</translation>
+ <translation type="unfinished">Sao chép địa chỉ được chá»n vào bá»™ nhá»› tạm</translation>
</message>
<message>
<source>&amp;Copy</source>
<translation type="unfinished">&amp;Sao chép</translation>
</message>
<message>
- <source>C&amp;lose</source>
- <translation type="unfinished">Ä&amp;óng lại</translation>
- </message>
- <message>
<source>Delete the currently selected address from the list</source>
- <translation type="unfinished">Xóa địa chỉ Ä‘ang chá»n từ danh sách</translation>
+ <translation type="unfinished">Xoá địa chỉ được chá»n khá»i danh sách</translation>
</message>
<message>
- <source>Export the data in the current tab to a file</source>
- <translation type="unfinished">Xuất dữ liệu trong thẻ hiện tại ra file</translation>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">Nhập địa chỉ hoặc nhãn để tìm kiếm</translation>
</message>
<message>
<source>&amp;Export</source>
<translation type="unfinished">&amp;Xuất</translation>
</message>
<message>
- <source>&amp;Delete</source>
- <translation type="unfinished">&amp;Xóa</translation>
- </message>
- <message>
<source>Choose the address to send coins to</source>
- <translation type="unfinished">Chá»n địa chỉ để gá»­i coins đến</translation>
- </message>
- <message>
- <source>Choose the address to receive coins with</source>
- <translation type="unfinished">Chá»n địa chỉ để nhận coins vá»›i</translation>
- </message>
- <message>
- <source>C&amp;hoose</source>
- <translation type="unfinished">C&amp;há»n</translation>
+ <translation type="unfinished">Chá»n địa chỉ để gá»­i coin đến</translation>
</message>
<message>
<source>Sending addresses</source>
- <translation type="unfinished">Äịa chỉ Ä‘ang gá»­i</translation>
- </message>
- <message>
- <source>Receiving addresses</source>
- <translation type="unfinished">Äịa chỉ Ä‘ang nhậ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 type="unfinished">Äây là những địa chỉ Ä‘ang thá»±c hiện thanh toán. Luôn kiểm tra số lượng và địa chỉ nhận trÆ°á»›c khi gá»­i coins.</translation>
- </message>
- <message>
- <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
-Signing is only possible with addresses of the type 'legacy'.</source>
- <translation type="unfinished">Äây là các địa chỉ Bitcoin của bạn để nhận thanh toán. Sá»­ dụng nút 'Tạo địa chỉ nhận má»›i' trong tab nhận để tạo các địa chỉ má»›i. Chỉ có thể gán địa chỉ vá»›i các địa chỉ thuá»™c loại 'kế thừa'.</translation>
+ <translation type="unfinished">Äang gá»­i địa chỉ</translation>
</message>
<message>
- <source>&amp;Copy Address</source>
- <translation type="unfinished">&amp;Copy Äịa Chỉ</translation>
- </message>
- <message>
- <source>Copy &amp;Label</source>
- <translation type="unfinished">Copy &amp;Nhãn</translation>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;Chỉnh sửa</translation>
</message>
<message>
<source>Export Address List</source>
- <translation type="unfinished">Xuất List Äịa Chỉ</translation>
- </message>
- <message>
- <source>Comma separated file</source>
- <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
- <translation type="unfinished">Tệp tách dấu phẩy</translation>
+ <translation type="unfinished">Xuất danh sách địa chỉ</translation>
</message>
- <message>
- <source>There was an error trying to save the address list to %1. Please try again.</source>
- <extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
- <translation type="unfinished">Có lỗi khi đang save list địa chỉ đến %1. Vui lòng thử lại.</translation>
- </message>
- <message>
- <source>Exporting Failed</source>
- <translation type="unfinished">Xuất Thất Bại</translation>
- </message>
-</context>
+ </context>
<context>
<name>AddressTableModel</name>
<message>
@@ -109,46 +62,46 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(không nhãn)</translation>
+ <translation type="unfinished">(không có nhãn)</translation>
</message>
</context>
<context>
<name>AskPassphraseDialog</name>
<message>
<source>Passphrase Dialog</source>
- <translation type="unfinished">Log Cụm Mật Khẩu</translation>
+ <translation type="unfinished">Hộp thoại cụm mật khẩu</translation>
</message>
<message>
<source>Enter passphrase</source>
- <translation type="unfinished">Nhập cụm mật khẩu</translation>
+ <translation type="unfinished">Nhập mật khẩu</translation>
</message>
<message>
<source>New passphrase</source>
- <translation type="unfinished">Cụm mật khẩu mới</translation>
+ <translation type="unfinished">Mật khẩu mới</translation>
</message>
<message>
<source>Repeat new passphrase</source>
- <translation type="unfinished">Lặp lại cụm mật khẩu mới</translation>
+ <translation type="unfinished">Nhập lại mật khẩu</translation>
</message>
<message>
<source>Show passphrase</source>
- <translation type="unfinished">Hiện cụm từ mật khẩu</translation>
+ <translation type="unfinished">Hiện mật khẩu</translation>
</message>
<message>
<source>Encrypt wallet</source>
- <translation type="unfinished">Ví mã hóa</translation>
+ <translation type="unfinished">Mã hoá ví</translation>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation type="unfinished">Quá trình này cần cụm mật khẩu của bạn để mở khóa ví.</translation>
+ <translation type="unfinished">Hoạt động này cần mật khẩu ví của bạn để mở khoá ví.</translation>
</message>
<message>
<source>Unlock wallet</source>
- <translation type="unfinished">Mở khóa ví</translation>
+ <translation type="unfinished">Mở khoá ví</translation>
</message>
<message>
<source>Change passphrase</source>
- <translation type="unfinished">Äổi cụm mật khẩu</translation>
+ <translation type="unfinished">Äổi mật khẩu</translation>
</message>
<message>
<source>Confirm wallet encryption</source>
@@ -156,459 +109,337 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">Cảnh báo: Nếu bạn mã hóa ví và mất cụm mật khẩu, bạn sẽ &lt;b&gt;MẤT TẤT CẢ BITCOIN&lt;/b&gt;!</translation>
+ <translation type="unfinished">Cảnh báo: Nếu bạn mã hóa ví và mất cụm mật khẩu, bạn sẽ &lt;b&gt;MẤT TẤT CẢ CÃC BITCOIN&lt;/b&gt;!</translation>
</message>
<message>
<source>Are you sure you wish to encrypt your wallet?</source>
- <translation type="unfinished">Bạn có chắc bạn muốn mã hóa ví của mình?</translation>
+ <translation type="unfinished">Bạn có chắc chắn muốn mã hoá ví không?</translation>
</message>
<message>
<source>Wallet encrypted</source>
- <translation type="unfinished">Ví đã được mã hóa</translation>
+ <translation type="unfinished">Äã mã hoá ví</translation>
</message>
<message>
<source>Enter the new passphrase for 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 type="unfinished">Nhập cụm từ mật khẩu má»›i cho ví Ä‘iện tá»­. Hãy sá»­ dụng cụm mật khẩu vá»›i mÆ°á»i hoặc nhiá»u hÆ¡n các ký tá»± ngẫu nhiên, hoặc nhiá»u hÆ¡n tám từ.</translation>
+ <translation type="unfinished">Nhập cụm mật khẩu má»›i cho ví.&lt;br/&gt;Vui lòng sá»­ dụng cụm mật khẩu gồm &lt;b&gt;mÆ°á»i ký tá»± ngẫu nhiên trở lên&lt;/b&gt;, hoặc &lt;b&gt;tám từ trở lên&lt;/b&gt;.</translation>
</message>
<message>
<source>Enter the old passphrase and new passphrase for the wallet.</source>
- <translation type="unfinished">Nhập cụm mật khẩu cũ và mật khẩu mới cho ví.</translation>
+ <translation type="unfinished">Nhập mật khẩu cũ và mật khẩu mới cho ví.</translation>
</message>
<message>
<source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
- <translation type="unfinished">Xin lÆ°u ý rằng mật mã hóa ví của bạn không thể bảo vệ hoàn toàn bitcoin của bạn khá»i đánh cắp bởi các phẩn má»m gián Ä‘iệp nhiá»…m vào máy tính của bạn.</translation>
+ <translation type="unfinished">Xin lÆ°u ý rằng mã hoá ví của bạn không thể bảo vá» hoàn toàn Bitcoin của bạn khá»i việc bị đánh cắp má»›i các phần má»m gián Ä‘iệp nhiá»…m vào máy tính của bạn.</translation>
</message>
<message>
<source>Wallet to be encrypted</source>
- <translation type="unfinished">Ví sẽ được mã hóa</translation>
+ <translation type="unfinished">Ví sẽ được mã hoá</translation>
</message>
<message>
<source>Your wallet is about to be encrypted. </source>
- <translation type="unfinished">Ví của bạn sẽ được mã hóa.</translation>
+ <translation type="unfinished">Ví của bạn sẽ được mã hoá.</translation>
</message>
<message>
<source>Your wallet is now encrypted. </source>
- <translation type="unfinished">Ví của bạn đã được mã hóa.</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 type="unfinished">QUAN TRỌNG: Bất cứ backup nào bạn từng làm trước đây từ ví của bạn nên được thay thế tạo mới, file mã hóa ví. Vì lý do bảo mật, các backup trước đây của các ví chưa mã hóa sẽ bị vô tác dụng ngay khi bạn bắt đầu sử dụng mới, ví đã được mã hóa.</translation>
+ <translation type="unfinished">Ví của bạn đã được mã hoá.</translation>
</message>
<message>
<source>Wallet encryption failed</source>
- <translation type="unfinished">Quá trình mã hóa ví thất bại</translation>
+ <translation type="unfinished">Mã hoá ví thất bại</translation>
</message>
<message>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
- <translation type="unfinished">Quá trình mã hóa ví thất bại do một lỗi nội tại. Ví của bạn vẫn chưa được mã hóa.</translation>
+ <translation type="unfinished">Mã hoá ví thất bại do lỗi nội bộ. Ví của bạn vẫn chưa được mã hoá.</translation>
</message>
<message>
<source>The supplied passphrases do not match.</source>
- <translation type="unfinished">Cụm mật khẩu được cung cấp không đúng.</translation>
- </message>
- <message>
- <source>Wallet unlock failed</source>
- <translation type="unfinished">Mở khóa ví thất bại</translation>
- </message>
- <message>
- <source>The passphrase entered for the wallet decryption was incorrect.</source>
- <translation type="unfinished">Cụm mật khẩu đã nhập để giải mã ví không đúng.</translation>
- </message>
- <message>
- <source>Wallet passphrase was successfully changed.</source>
- <translation type="unfinished">Cụm mật khẩu thay đổi thành công.</translation>
- </message>
- <message>
- <source>Warning: The Caps Lock key is on!</source>
- <translation type="unfinished">Cảnh báo: chữ Viết Hoa đang bật!</translation>
+ <translation type="unfinished">Mật khẩu đã nhập không đúng.</translation>
</message>
-</context>
+ </context>
<context>
- <name>BanTableModel</name>
+ <name>BitcoinApplication</name>
<message>
- <source>Banned Until</source>
- <translation type="unfinished">Cấm Äến</translation>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">Tệp cài đặt %1 có thể bị hư hại hoặc không hợp lệ.</translation>
</message>
-</context>
-<context>
- <name>BitcoinApplication</name>
<message>
<source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
<translation type="unfinished">Lỗi nghiêm trong. %1 không thể tiếp tục và sẽ thoát ra</translation>
</message>
- </context>
-<context>
- <name>QObject</name>
- <message>
- <source>Error: Specified data directory "%1" does not exist.</source>
- <translation type="unfinished">Error: Xác định data directory "%1" không tồn tại.</translation>
- </message>
<message>
- <source>Error: Cannot parse configuration file: %1.</source>
- <translation type="unfinished">Lỗi: không thể phân giải tệp cài đặt cấu hình: %1.</translation>
- </message>
- <message>
- <source>Amount</source>
- <translation type="unfinished">Số lượng</translation>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">Äã xảy ra lá»—i ná»™i bá»™. %1 sẽ cố gắng tiếp tục má»™t cách an toàn. Äây là má»™t lá»—i không mong muốn có thể được báo cáo nhÆ° mô tả bên dÆ°á»›i.</translation>
</message>
+</context>
+<context>
+ <name>QObject</name>
<message>
- <source>Enter a Bitcoin address (e.g. %1)</source>
- <translation type="unfinished">Nhập một Bitcoin address (e.g. %1)</translation>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">Bạn muốn đặt lại cài đặt vỠgiá trị mặc định hay hủy bỠmà không thực hiện thay đổi?</translation>
</message>
<message>
- <source>%1 h</source>
- <translation type="unfinished">%1 giá»</translation>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">Äã xảy ra lá»—i nghiêm trá»ng. Kiểm tra xem tệp cài đặt có thể ghi được không hoặc thá»­ chạy vá»›i -nosettings.</translation>
</message>
<message>
- <source>%1 m</source>
- <translation type="unfinished">%1 phút</translation>
+ <source>Error: %1</source>
+ <translation type="unfinished">Lá»—i: %1</translation>
</message>
<message>
- <source>%1 s</source>
- <translation type="unfinished">%1 giây</translation>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 vẫn chưa thoát ra một cách an toàn…</translation>
</message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%ngiây</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nphút</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%ngiá»</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nngày</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%ntuần</numerusform>
</translation>
</message>
- <message>
- <source>%1 and %2</source>
- <translation type="unfinished">%1 và %2</translation>
- </message>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nnăm</numerusform>
</translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
- <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
- <translation type="unfinished">Dá»± toán phí không thành công. Fallbackfee bị vô hiệu hóa. Äợi sau má»™t vài khối hoặc kích hoạt -fallbackfee.</translation>
- </message>
- <message>
- <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
- <translation type="unfinished">Äây là phí giao dịch tối Ä‘a bạn phải trả (ngoài phí thông thÆ°á»ng) để Æ°u tiên việc tránh chi xài má»™t phần (partial spend) so vá»›i việc lá»±a chá»n đồng coin thông thÆ°á»ng.</translation>
- </message>
- <message>
- <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
- <translation type="unfinished">Cảnh báo: các khóa riêng tư được tìm thấy trong ví {%s} với khóa riêng tư không kích hoạt</translation>
- </message>
- <message>
- <source>A fatal internal error occurred, see debug.log for details</source>
- <translation type="unfinished">Lá»—i nghiêm trá»ng xảy ra, xem debug.log để biết chi tiết</translation>
- </message>
- <message>
- <source>Cannot set -peerblockfilters without -blockfilterindex.</source>
- <translation type="unfinished">Không thể đặt -peerblockfilters mà không có -blockfilterindex.</translation>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">Không thể Ä‘á»c tệp cài đặt</translation>
</message>
<message>
- <source>Cannot write to data directory '%s'; check permissions.</source>
- <translation type="unfinished">Không thể ghi vào thÆ° mục dữ liệu '%s'; kiểm tra lại quyá»n.</translation>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">Không thể ghi tệp cài đặt</translation>
</message>
<message>
- <source>Config setting for %s only applied on %s network when in [%s] section.</source>
- <translation type="unfinished">Cài dặt thuộc tính cho %s chỉ có thể áp dụng cho mạng %s trong khi [%s] .</translation>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">Lá»—i khi Ä‘á»c%s! Dữ liệu giao dịch có thể bị thiếu hoặc không chính xác. Äang quét lại ví.</translation>
</message>
<message>
- <source>Could not find asmap file %s</source>
- <translation type="unfinished">Không tìm thấy tệp asmap %s</translation>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">peers.dat (%s) không hợp lệ hoặc bị há»ng. Nếu bạn cho rằng đây là lá»—i, vui lòng báo cáo cho %s. Äể giải quyết vấn Ä‘á» này, bạn có thể di chuyển tệp (%s) ra khá»i (đổi tên, di chuyển hoặc xóa) để tạo tệp má»›i vào lần bắt đầu tiếp theo.</translation>
</message>
<message>
- <source>Could not parse asmap file %s</source>
- <translation type="unfinished">Không Ä‘á»c được tệp asmap %s</translation>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">Chế Ä‘á»™ rút gá»n không tÆ°Æ¡ng thích vá»›i -reindex-chainstate. Sá»­ dụng -reindex ở chế Ä‘á»™ đầy đủ.</translation>
</message>
<message>
- <source>Disk space is too low!</source>
- <translation type="unfinished">Ổ đĩa còn quá ít</translation>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">Chỉ mục khối db chứa má»™t 'txindex' kế thừa. Äể xóa dung lượng ổ Ä‘Ä©a bị chiếm dụng, hãy chạy -reindex đầy đủ, nếu không, hãy bá» qua lá»—i này. Thông báo lá»—i này sẽ không được hiển thị lại.</translation>
</message>
<message>
- <source>Error loading %s: Private keys can only be disabled during creation</source>
- <translation type="unfinished">Lỗi tải %s: Khóa riêng tư chỉ có thể không kích hoạt trong suốt quá trình tạo.</translation>
- </message>
- <message>
- <source>Error: Disk space is low for %s</source>
- <translation type="unfinished">Lá»—i: ÄÄ©a trống ít quá cho %s</translation>
- </message>
- <message>
- <source>Error: Keypool ran out, please call keypoolrefill first</source>
- <translation type="unfinished">Lá»—i: Keypool đã hết, vui lòng gá»i keypoolrefill trÆ°á»›c</translation>
- </message>
- <message>
- <source>Failed to rescan the wallet during initialization</source>
- <translation type="unfinished">Lỗi quét lại ví trong xuất quá trình khởi tạo</translation>
- </message>
- <message>
- <source>Failed to verify database</source>
- <translation type="unfinished">Lỗi xác nhận dữ liệu</translation>
+ <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
+ <translation type="unfinished">Äây là phí giao dịch tối Ä‘a bạn phải trả (ngoài phí thông thÆ°á»ng) để Æ°u tiên việc tránh chi xài má»™t phần (partial spend) so vá»›i việc lá»±a chá»n đồng coin thông thÆ°á»ng.</translation>
</message>
<message>
- <source>Insufficient funds</source>
- <translation type="unfinished">Không đủ tiá»n</translation>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">Tìm thấy định dạng cÆ¡ sở dữ liệu trạng thái chuá»—i không được há»— trợ. Vui lòng khá»i Ä‘á»™ng lại vá»›i -reindex-chainstate. Việc này sẽ tái thiết lập cÆ¡ sở dữ liệu trạng thái chuá»—i.</translation>
</message>
<message>
- <source>Invalid P2P permission: '%s'</source>
- <translation type="unfinished">Quyá»n P2P không hợp lệ: '%s'</translation>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">Ví đã được tạo thành công. Loại ví Legacy đang bị phản đối và việc hỗ trợ mở các ví Legacy mới sẽ bị loại bỠtrong tương lai</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">Không có máy chủ proxy nào được chỉ định. Sử dụng -proxy =&lt;ip&gt; hoặc -proxy =&lt;ip:port&gt;.</translation>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">Không thể đặt -forcednsseed thành true khi đặt -dnsseed thành false.</translation>
</message>
<message>
- <source>Section [%s] is not recognized.</source>
- <translation type="unfinished">Mục [%s] không được nhìn nhận.</translation>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">Không thể hoàn tất nâng cấp -txindex được bắt đầu bởi phiên bản trước. Khởi động lại với phiên bản trước đó hoặc chạy -reindex đầy đủ.</translation>
</message>
<message>
- <source>Specified -walletdir "%s" does not exist</source>
- <translation type="unfinished">Thư mục ví được nêu -walletdir "%s" không tồn tại</translation>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s yêu cầu lắng nghe trên cổng %u. Cổng này được coi là "xấu" và do đó không có khả năng bất kỳ ngang hàng Bitcoin Core nào kết nối với nó. Xem doc/p2p-bad-ports.md để biết chi tiết và danh sách đầy đủ.</translation>
</message>
<message>
- <source>Specified -walletdir "%s" is a relative path</source>
- <translation type="unfinished">Chỉ định -walletdir "%s" là Ä‘Æ°á»ng dẫn tÆ°Æ¡ng đối</translation>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">reindex-chainstate tùy chá»n không tÆ°Æ¡ng thích vá»›i -blockfilterindex. Vui lòng tạp thá»i vô hiệu hóa blockfilterindex trong khi sá»­ dụng -reindex-chainstate, hoặc thay thế -reindex-chainstate bởi -reindex để tái thiết lập đẩy đủ tất cả các chỉ số.</translation>
</message>
<message>
- <source>Specified -walletdir "%s" is not a directory</source>
- <translation type="unfinished">Chỉ định -walletdir "%s" không phải là một thư mục</translation>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">reindex-chainstate tùy chá»n không tÆ°Æ¡ng thích vá»›i -coinstatsindex. Vui lòng tạp thá»i vô hiệu hóa coinstatsindex trong khi sá»­ dụng -reindex-chainstate, hoặc thay thế -reindex-chainstate bởi -reindex để tái thiết lập đẩy đủ tất cả các chỉ số.</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.</source>
- <translation type="unfinished">Thư mục chứa các khối được chỉ ra "%s" không tồn tại</translation>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">reindex-chainstate tùy chá»n không tÆ°Æ¡ng thích vá»›i -txindex. Vui lòng tạp thá»i vô hiệu hóa txindex trong khi sá»­ dụng -reindex-chainstate, hoặc thay thế -reindex-chainstate bởi -reindex để tái thiết lập đẩy đủ tất cả các chỉ số.</translation>
</message>
<message>
- <source>The wallet will avoid paying less than the minimum relay fee.</source>
- <translation type="unfinished">Wallet sẽ hủy thanh toán nhỠhơn phí relay.</translation>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">Giả sá»­ hợp lệ: lần đồng bá»™ ví gần nhất vượt ra ngoài dữ liệu khả dụng của khối. Bạn cần phải chá» quá trình xác thá»±c ná»n tảng của chuối để tải vá» nhiá»u khối hÆ¡n.</translation>
</message>
<message>
- <source>This is the minimum transaction fee you pay on every transaction.</source>
- <translation type="unfinished">Äây là minimum transaction fee bạn pay cho má»—i transaction.</translation>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">Không thể cung cấp các kết nối cụ thể và yêu cầu addrman tìm các kết nối gửi đi cùng một lúc.</translation>
</message>
<message>
- <source>This is the transaction fee you will pay if you send a transaction.</source>
- <translation type="unfinished">Äây là transaction fee bạn sẽ pay nếu gá»­i transaction.</translation>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">Lá»—i khi tải %s: Ví ngÆ°á»i ký bên ngoài Ä‘ang được tải mà không có há»— trợ ngÆ°á»i ký bên ngoài được biên dịch</translation>
</message>
<message>
- <source>Transaction amounts must not be negative</source>
- <translation type="unfinished">Transaction amounts phải không âm</translation>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">Không thể đổi tên tệp ngang hàng không hợp lệ. Vui lòng di chuyển hoặc xóa nó và thử lại.</translation>
</message>
<message>
- <source>Transaction has too long of a mempool chain</source>
- <translation type="unfinished">Transaction có chuỗi mempool chain quá dài</translation>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">Äầu vào không được tìm thấy hoặc đã được sá»­ dụng</translation>
</message>
<message>
- <source>Transaction must have at least one recipient</source>
- <translation type="unfinished">Transaction phải có ít nhất má»™t ngÆ°á»i nhận</translation>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">Lắng nghe những kết nối thất bại sắp xảy ra (lắng nghe lỗi được trả vỠ%s)</translation>
</message>
<message>
- <source>Unable to create the PID file '%s': %s</source>
- <translation type="unfinished">Không thể tạo tệp PID '%s': %s</translation>
+ <source>Missing amount</source>
+ <translation type="unfinished">Số tiá»n còn thiếu</translation>
</message>
<message>
- <source>Unable to generate initial keys</source>
- <translation type="unfinished">Không thể tạo khóa ban đầu</translation>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">Thiếu dữ liệu giải quyết để ước tính quy mô giao dịch</translation>
</message>
<message>
- <source>Unable to generate keys</source>
- <translation type="unfinished">Không thể tạo khóa</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">Không có địa chỉ</translation>
</message>
<message>
- <source>Unknown -blockfilterindex value %s.</source>
- <translation type="unfinished">Không rõ giá trị -blockfilterindex %s.</translation>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">Chỉ số đầu ra thay đổi giao dịch nằm ngoài phạm vi</translation>
</message>
<message>
- <source>Unknown address type '%s'</source>
- <translation type="unfinished">Không biết địa chỉ kiểu '%s'</translation>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">Giao dịch cần thay đổi địa chỉ, nhưng chúng tôi không thể tạo địa chỉ đó.</translation>
</message>
<message>
- <source>Unknown change type '%s'</source>
- <translation type="unfinished">Không biết thay đổi kiểu '%s'</translation>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">Không có khả năng để phân bổ bộ nhớ cho -maxsigcachesize: '%s' MiB</translation>
</message>
<message>
- <source>Unknown network specified in -onlynet: '%s'</source>
- <translation type="unfinished">Unknown network được xác định trong -onlynet: '%s'</translation>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">Không thể parse -maxuploadtarget '%s</translation>
</message>
</context>
<context>
<name>BitcoinGUI</name>
<message>
- <source>&amp;Overview</source>
- <translation type="unfinished">&amp;Tổng quan</translation>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;Thu nhá»</translation>
</message>
<message>
- <source>Show general overview of wallet</source>
- <translation type="unfinished">Hiển thị tổng quan ví</translation>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;Mã hóa ví…</translation>
</message>
<message>
- <source>&amp;Transactions</source>
- <translation type="unfinished">&amp;Các Giao Dịch</translation>
- </message>
- <message>
- <source>Browse transaction history</source>
- <translation type="unfinished">Trình duyệt lịch sử giao dịch</translation>
- </message>
- <message>
- <source>E&amp;xit</source>
- <translation type="unfinished">T&amp;hoát</translation>
- </message>
- <message>
- <source>Quit application</source>
- <translation type="unfinished">Äóng ứng dụng</translation>
- </message>
- <message>
- <source>&amp;About %1</source>
- <translation type="unfinished">&amp;Khoảng %1</translation>
- </message>
- <message>
- <source>Show information about %1</source>
- <translation type="unfinished">Hiện thông tin khoảng %1</translation>
- </message>
- <message>
- <source>About &amp;Qt</source>
- <translation type="unfinished">Vá» &amp;Qt</translation>
- </message>
- <message>
- <source>Show information about Qt</source>
- <translation type="unfinished">Hiện thông tin vỠQt</translation>
- </message>
- <message>
- <source>Modify configuration options for %1</source>
- <translation type="unfinished">Sửa đổi tùy chỉnh cấu hình cho %1</translation>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">Mã hóa private key thuộc vỠví của bạn</translation>
</message>
<message>
- <source>Create a new wallet</source>
- <translation type="unfinished">Tạo một ví mới</translation>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;Thay dổi Passphrase…</translation>
</message>
<message>
- <source>Wallet:</source>
- <translation type="unfinished">Ví tiá»n</translation>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">Äăng ký lá»i nhắn vá»›i địa chỉ Bitcoin của bạn để chứng minh quyá»n sở hữu chúng</translation>
</message>
<message>
- <source>Network activity disabled.</source>
- <extracomment>A substring of the tooltip.</extracomment>
- <translation type="unfinished">Hoạt động mạng được vô hiệu.</translation>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;Xác minh tin nhắn…</translation>
</message>
<message>
- <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
- <translation type="unfinished">Proxy là &lt;b&gt; cho phép &lt;/b&gt;: %1</translation>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">Xác minh lá»i nhắn để chắc chắn đã được đăng ký vá»›i địa chỉ Bitcoin xác định</translation>
</message>
<message>
- <source>Send coins to a Bitcoin address</source>
- <translation type="unfinished">Gửi coin đến một địa chỉ Bitcoin</translation>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">Äóng ví…</translation>
</message>
<message>
- <source>Backup wallet to another location</source>
- <translation type="unfinished">Backup ví đến một địa chỉ khác</translation>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">Tạo ví…</translation>
</message>
<message>
- <source>Change the passphrase used for wallet encryption</source>
- <translation type="unfinished">Thay đổi cụm mật khẩu cho ví đã mã hóa</translation>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">Äóng tất cả các ví…</translation>
</message>
<message>
- <source>&amp;Send</source>
- <translation type="unfinished">&amp;Gá»­i</translation>
+ <source>&amp;File</source>
+ <translation type="unfinished">&amp;Tệp</translation>
</message>
<message>
- <source>&amp;Receive</source>
- <translation type="unfinished">&amp;Nhận</translation>
+ <source>&amp;Settings</source>
+ <translation type="unfinished">&amp;Cài đặt</translation>
</message>
<message>
- <source>Encrypt the private keys that belong to your wallet</source>
- <translation type="unfinished">Mã hóa private key thuộc vỠví của bạn</translation>
+ <source>&amp;Help</source>
+ <translation type="unfinished">&amp;Giúp đỡ</translation>
</message>
<message>
- <source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation type="unfinished">Äăng ký lá»i nhắn vá»›i địa chỉ Bitcoin của bạn để chứng minh quyá»n sở hữu chúng</translation>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">Äồng bá»™ hóa tiêu Ä‘á» (%1%)...</translation>
</message>
<message>
- <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation type="unfinished">Xác minh lá»i nhắn để chắc chắn đã được đăng ký vá»›i địa chỉ Bitcoin xác định</translation>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">Äồng bá»™ hóa vá»›i network...</translation>
</message>
<message>
- <source>Tabs toolbar</source>
- <translation type="unfinished">Các thanh công cụ</translation>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">Lập chỉ mục các khối trên đĩa…</translation>
</message>
<message>
- <source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation type="unfinished">Yêu cầu thanh toán (tạo QR code và bitcoin: URIs)</translation>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">Xử lý khối trên đĩa…</translation>
</message>
<message>
- <source>Show the list of used sending addresses and labels</source>
- <translation type="unfinished">Hiển thị danh sách các địa chỉ và nhãn đã dùng để gửi</translation>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">Lập chỉ mục lại các khối trên đĩa…</translation>
</message>
<message>
- <source>Show the list of used receiving addresses and labels</source>
- <translation type="unfinished">Hiển thị danh sách các địa chỉ và nhãn đã dùng để nhận</translation>
- </message>
- <message>
- <source>&amp;Command-line options</source>
- <translation type="unfinished">&amp;Tùy chỉnh Command-line</translation>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">Kết nối với các peer…</translation>
</message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>Äã xá»­ lý %n khối của lịch sá»­ giao dịch.</numerusform>
</translation>
</message>
<message>
- <source>%1 behind</source>
- <translation type="unfinished">%1 phia sau</translation>
- </message>
- <message>
- <source>Last received block was generated %1 ago.</source>
- <translation type="unfinished">Khối nhận cuối cùng đã được tạo %1.</translation>
- </message>
- <message>
- <source>Transactions after this will not yet be visible.</source>
- <translation type="unfinished">Các giao dịch sau giao dịch này sẽ không được hiển thị.</translation>
- </message>
- <message>
- <source>Error</source>
- <translation type="unfinished">Lá»—i</translation>
- </message>
- <message>
- <source>Warning</source>
- <translation type="unfinished">Cảnh báo</translation>
- </message>
- <message>
- <source>Information</source>
- <translation type="unfinished">Thông tin</translation>
- </message>
- <message>
- <source>Up to date</source>
- <translation type="unfinished">Äã cập nhật</translation>
+ <source>Catching up…</source>
+ <translation type="unfinished">Äang bắt kịp...</translation>
</message>
<message>
<source>Load Partially Signed Bitcoin Transaction</source>
<translation type="unfinished">Kết nối với mạng Bitcoin thông qua một proxy SOCKS5 riêng cho các dịch vụ Tor hành.</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">Tải PSBT từ &amp;khay nhớ tạm…</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">Tải một phần giao dịch Bitcoin đã ký từ khay nhớ tạm</translation>
</message>
@@ -645,1585 +476,553 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Äông ví</translation>
</message>
<message>
- <source>Close all wallets</source>
- <translation type="unfinished">Äóng tất cả ví</translation>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Khôi phục ví...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Khôi phục ví từ tệp đã sao lưu</translation>
+ </message>
+ <message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">&amp;Giá trị mặt nạ</translation>
</message>
<message>
- <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
- <translation type="unfinished">Hiển thị %1 tin nhắn hỗ trợ để nhận được danh sách Bitcoin command-line khả dụng</translation>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">Che các giá trị trong tab Tổng quan</translation>
</message>
<message>
- <source>default wallet</source>
- <translation type="unfinished">ví mặc định</translation>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Tải bản sao lưu ví</translation>
</message>
<message>
- <source>No wallets available</source>
- <translation type="unfinished">Không có ví nào</translation>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Khôi phục ví</translation>
</message>
<message>
- <source>Zoom</source>
- <translation type="unfinished">Phóng</translation>
+ <source>Ctrl+M</source>
+ <translation type="unfinished">Nhấn Ctrl + M</translation>
</message>
<message>
- <source>Main Window</source>
- <translation type="unfinished">Màn hình chính</translation>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;Ẩn</translation>
</message>
<message>
- <source>%1 client</source>
- <translation type="unfinished">%1 khách</translation>
+ <source>S&amp;how</source>
+ <translation type="unfinished">Trìn&amp;h diễn</translation>
</message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nkết nối đang hoạt động với mạng lưới Bitcoin</numerusform>
</translation>
</message>
<message>
- <source>Warning: %1</source>
- <translation type="unfinished">Cảnh báo: %1</translation>
- </message>
- <message>
- <source>Date: %1
-</source>
- <translation type="unfinished">Ngày %1
-</translation>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">Nhấp để có thêm hành động.</translation>
</message>
<message>
- <source>Amount: %1
-</source>
- <translation type="unfinished">Số lượng: %1
-</translation>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">Hiển thị tab ngang hàng</translation>
</message>
<message>
- <source>Wallet: %1
-</source>
- <translation type="unfinished">Ví: %1
-</translation>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">Tắt hoạt động mạng</translation>
</message>
<message>
- <source>Type: %1
-</source>
- <translation type="unfinished">Loại: %1
-</translation>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">Bật hoạt động mạng</translation>
</message>
<message>
- <source>Label: %1
-</source>
- <translation type="unfinished">Nhãn: %1
-</translation>
- </message>
- <message>
- <source>Address: %1
-</source>
- <translation type="unfinished">Äịa chỉ: %1
-</translation>
- </message>
- <message>
- <source>Sent transaction</source>
- <translation type="unfinished">Giao dịch đã gửi</translation>
- </message>
- <message>
- <source>Incoming transaction</source>
- <translation type="unfinished">Giao dịch đang nhận</translation>
- </message>
- <message>
- <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
- <translation type="unfinished">Khởi tạo HD key &lt;b&gt;enabled&lt;/b&gt;</translation>
- </message>
- <message>
- <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
- <translation type="unfinished">Khởi tạo HD key &lt;b&gt;disabled&lt;/b&gt;</translation>
+ <source>Error: %1</source>
+ <translation type="unfinished">Lá»—i: %1</translation>
</message>
<message>
<source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
- <translation type="unfinished">Khóa riên tư &lt;b&gt;đã tắt&lt;/b&gt;</translation>
+ <translation type="unfinished">Khóa riêng tư &lt;b&gt;đã tắt&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 type="unfinished">Ví thì &lt;b&gt;encrypted&lt;/b&gt; và hiện tại &lt;b&gt;unlocked&lt;/b&gt;</translation>
+ <translation type="unfinished">Ví thì &lt;b&gt;được mã hóa &lt;/b&gt; và hiện tại &lt;b&gt;đã khóa&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 type="unfinished">Ví thì &lt;b&gt;encrypted&lt;/b&gt; và hiện tại &lt;b&gt;locked&lt;/b&gt;</translation>
+ <translation type="unfinished">Ví thì &lt;b&gt;được mã hóa &lt;/b&gt; và hiện tại &lt;b&gt;đã khóa&lt;/b&gt;</translation>
</message>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
<message>
- <source>Original message:</source>
- <translation type="unfinished">Tin nhắn ban đầu:</translation>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">ÄÆ¡n vị để hiển thị số tiá»n. Nhấp để chá»n Ä‘Æ¡n vị khác.</translation>
</message>
</context>
<context>
<name>CoinControlDialog</name>
<message>
- <source>Coin Selection</source>
- <translation type="unfinished">Lá»±a chá»n Coin</translation>
- </message>
- <message>
- <source>Quantity:</source>
- <translation type="unfinished">Số lượng:</translation>
- </message>
- <message>
- <source>Amount:</source>
- <translation type="unfinished">Số lượng:</translation>
- </message>
- <message>
- <source>Fee:</source>
- <translation type="unfinished">Phí:</translation>
- </message>
- <message>
- <source>Dust:</source>
- <translation type="unfinished">Rác:</translation>
- </message>
- <message>
- <source>After Fee:</source>
- <translation type="unfinished">Sau Phí:</translation>
- </message>
- <message>
- <source>Change:</source>
- <translation type="unfinished">Thay đổi:</translation>
- </message>
- <message>
- <source>(un)select all</source>
- <translation type="unfinished">(không)chá»n tất cả</translation>
- </message>
- <message>
- <source>Amount</source>
- <translation type="unfinished">Số lượng</translation>
- </message>
- <message>
- <source>Received with label</source>
- <translation type="unfinished">Äã nhận vá»›i nhãn</translation>
- </message>
- <message>
- <source>Received with address</source>
- <translation type="unfinished">Äã nhận vá»›i địa chỉ</translation>
- </message>
- <message>
- <source>Date</source>
- <translation type="unfinished">Ngày</translation>
- </message>
- <message>
- <source>Confirmations</source>
- <translation type="unfinished">Xác nhận</translation>
- </message>
- <message>
- <source>Confirmed</source>
- <translation type="unfinished">Äã xác nhận</translation>
- </message>
- <message>
- <source>Copy amount</source>
- <translation type="unfinished">Sao chép số lượng</translation>
- </message>
- <message>
- <source>Copy quantity</source>
- <translation type="unfinished">Sao chép số lượng</translation>
- </message>
- <message>
- <source>Copy fee</source>
- <translation type="unfinished">Sao chép phí</translation>
- </message>
- <message>
- <source>Copy after fee</source>
- <translation type="unfinished">Sao chép sau phí</translation>
- </message>
- <message>
- <source>Copy bytes</source>
- <translation type="unfinished">Sao chép bytes</translation>
- </message>
- <message>
- <source>Copy dust</source>
- <translation type="unfinished">Sao chép rác</translation>
- </message>
- <message>
- <source>Copy change</source>
- <translation type="unfinished">Sao chép thay đổi</translation>
- </message>
- <message>
- <source>(%1 locked)</source>
- <translation type="unfinished">(%1 đã khóa)</translation>
- </message>
- <message>
- <source>yes</source>
- <translation type="unfinished">có</translation>
+ <source>Tree mode</source>
+ <translation type="unfinished">Chế độ Tree</translation>
</message>
<message>
- <source>no</source>
- <translation type="unfinished">không</translation>
+ <source>List mode</source>
+ <translation type="unfinished">Chế độ List</translation>
</message>
<message>
- <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
- <translation type="unfinished">Label này chuyển sang đỠnếu bất cứ giao dịch nhận nào có số lượng nhỠhơn ngưỡng dust.</translation>
- </message>
- <message>
- <source>Can vary +/- %1 satoshi(s) per input.</source>
- <translation type="unfinished">Có thể thay đổi +/-%1 satoshi(s) trên input.</translation>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">Sao chép giao dịch &amp;ID và chỉ mục đầu ra</translation>
</message>
<message>
<source>(no label)</source>
- <translation type="unfinished">(không nhãn)</translation>
- </message>
- <message>
- <source>change from %1 (%2)</source>
- <translation type="unfinished">change từ %1 (%2)</translation>
+ <translation type="unfinished">(không có nhãn)</translation>
</message>
</context>
<context>
<name>CreateWalletActivity</name>
<message>
- <source>Create Wallet</source>
- <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
- <translation type="unfinished">Tạo Ví</translation>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Có quá nhiá»u ngÆ°á»i ký từ bên ngoài được tìm thấy</translation>
</message>
+</context>
+<context>
+ <name>LoadWalletsActivity</name>
<message>
- <source>Create wallet failed</source>
- <translation type="unfinished">Tạo ví thất bại</translation>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">Tải ví</translation>
</message>
<message>
- <source>Create wallet warning</source>
- <translation type="unfinished">Cảnh báo khi tạo ví</translation>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">Äang tải ví…</translation>
</message>
- </context>
+</context>
<context>
<name>OpenWalletActivity</name>
<message>
- <source>Open wallet failed</source>
- <translation type="unfinished">Mở ví thất bại</translation>
- </message>
- <message>
- <source>Open wallet warning</source>
- <translation type="unfinished">Mở ví cảnh báo</translation>
- </message>
- <message>
- <source>default wallet</source>
- <translation type="unfinished">ví mặc định</translation>
- </message>
- <message>
<source>Open Wallet</source>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">Mớ ví</translation>
</message>
</context>
<context>
- <name>WalletController</name>
+ <name>RestoreWalletActivity</name>
<message>
- <source>Close wallet</source>
- <translation type="unfinished">Äông ví</translation>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Khôi phục ví</translation>
</message>
<message>
- <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
- <translation type="unfinished">Bạn có chắc bạn muốn đóng ví %1 ?</translation>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">Äang khôi phục ví &lt;b&gt;%1&lt;/b&gt;…</translation>
</message>
<message>
- <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
- <translation type="unfinished">Äóng ví thá»i gian dài sẽ dẫn đến phải đồng bá»™ hóa lại cả chuá»—i nếu cắt tỉa pruning được kích hoạt</translation>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Khôi phục ví thất bại</translation>
</message>
<message>
- <source>Close all wallets</source>
- <translation type="unfinished">Äóng tất cả ví</translation>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Cảnh báo khối phục ví</translation>
</message>
<message>
- <source>Are you sure you wish to close all wallets?</source>
- <translation type="unfinished">Bạn có chắc chắn muốn đóng tất cả ví không?</translation>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">Tin nhắn khôi phục ví</translation>
</message>
</context>
<context>
- <name>CreateWalletDialog</name>
- <message>
- <source>Create Wallet</source>
- <translation type="unfinished">Tạo Ví</translation>
- </message>
- <message>
- <source>Wallet Name</source>
- <translation type="unfinished">Tên Ví</translation>
- </message>
- <message>
- <source>Wallet</source>
- <translation type="unfinished">Ví</translation>
- </message>
- <message>
- <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
- <translation type="unfinished">Mật mã hóa ví. Ví sẽ được mật mã hóa với cụm mật khẩu của bạn.</translation>
- </message>
- <message>
- <source>Encrypt Wallet</source>
- <translation type="unfinished">Mật mã hóa ví</translation>
- </message>
- <message>
- <source>Advanced Options</source>
- <translation type="unfinished">Giao dịch thiếu một số thông tin vỠđầu vào.</translation>
- </message>
- <message>
- <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
- <translation type="unfinished">Tắt các khóa cá nhân cho ví này. Các ví với khóa cá nhân tắt sẽ không có các khóa cá nhân và không thể có nhân HD hoặc nhập thêm khóa cá nhân. Việc này tốt cho các ví chỉ dùng để xem.</translation>
- </message>
- <message>
- <source>Disable Private Keys</source>
- <translation type="unfinished">Vô hiệu hóa khóa cá nhân</translation>
- </message>
+ <name>WalletController</name>
<message>
- <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
- <translation type="unfinished">Tạo một ví trống. Ví trống không có các khóa cá nhân hay script ban đầu. Khóa cá nhân và địa chỉ có thể được nhập, hoặc một nhân HD có thể được thiết lập sau đó.</translation>
+ <source>Close wallet</source>
+ <translation type="unfinished">Äông ví</translation>
</message>
<message>
- <source>Make Blank Wallet</source>
- <translation type="unfinished">Tạo ví trống</translation>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">Bạn có chắc chắn muốn đóng ví không &lt;i&gt;%1&lt;/i&gt;?</translation>
</message>
+ </context>
+<context>
+ <name>CreateWalletDialog</name>
<message>
<source>Use descriptors for scriptPubKey management</source>
- <translation type="unfinished">Không có máy chủ proxy nào được chỉ định. Sử dụng -proxy = &lt;ip&gt; hoặc -proxy = &lt;ip: port&gt;.</translation>
+ <translation type="unfinished">Sử dụng bộ mô tả để quản lý scriptPubKey</translation>
</message>
<message>
- <source>Descriptor Wallet</source>
- <translation type="unfinished">Mô tả ví</translation>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">Sá»­ dụng thiết bị ký bên ngoài chẳng hạn nhÆ° ví phần cứng. TrÆ°á»›c tiên, hãy định cấu hình tập lệnh ngÆ°á»i ký bên ngoài trong tùy chá»n ví.</translation>
</message>
<message>
- <source>Create</source>
- <translation type="unfinished">Tạo</translation>
+ <source>External signer</source>
+ <translation type="unfinished">NgÆ°á»i ký tên bên ngoài</translation>
</message>
<message>
- <source>Compiled without sqlite support (required for descriptor wallets)</source>
- <translation type="unfinished">Biên dịch cần hỗ trợ SQLite(Bắt buộc đối với mô tả ví)</translation>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Äược biên dịch mà không có há»— trợ ký bên ngoài (bắt buá»™c đối vá»›i ký bên ngoài)</translation>
</message>
- </context>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
- <source>&amp;Label</source>
- <translation type="unfinished">Nhãn dữ liệu</translation>
- </message>
- <message>
- <source>The label associated with this address list entry</source>
- <translation type="unfinished">Label liên kết với list address ban đầu này</translation>
- </message>
- <message>
- <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
- <translation type="unfinished">Label liên kết vá»›i list address ban đầu này. Äiá»u này chỉ được Ä‘iá»u chỉnh cho địa chỉ gá»­i.</translation>
- </message>
- <message>
- <source>&amp;Address</source>
- <translation type="unfinished">Äịa chỉ</translation>
- </message>
- <message>
- <source>New sending address</source>
- <translation type="unfinished">Address Ä‘ang gá»­i má»›i</translation>
+ <source>Edit Address</source>
+ <translation type="unfinished">Sửa địa chỉ</translation>
</message>
<message>
<source>Edit receiving address</source>
- <translation type="unfinished">Edit address đang nhận</translation>
+ <translation type="unfinished">Chỉnh sửa địa chỉ nhận</translation>
</message>
<message>
<source>Edit sending address</source>
- <translation type="unfinished">Edit address Ä‘ang gá»­i</translation>
+ <translation type="unfinished">Chỉnh sửa địa chỉ gửi</translation>
</message>
- <message>
- <source>The entered address "%1" is not a valid Bitcoin address.</source>
- <translation type="unfinished">Address đã nhập "%1" không 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 type="unfinished">Äịa chỉ "%1" đã tồn tại nhÆ° địa chỉ nhận vá»›i nhãn "%2" và vì vậy không thể thêm nhÆ° là địa chỉ gá»­i.</translation>
- </message>
- <message>
- <source>The entered address "%1" is already in the address book with label "%2".</source>
- <translation type="unfinished">Äịa chỉ nhập "%1" đã có trong sổ địa chỉ vá»›i nhãn "%2".</translation>
- </message>
- <message>
- <source>Could not unlock wallet.</source>
- <translation type="unfinished">Không thể unlock wallet.</translation>
- </message>
- <message>
- <source>New key generation failed.</source>
- <translation type="unfinished">Khởi tạo key mới thất bại.</translation>
- </message>
-</context>
-<context>
- <name>FreespaceChecker</name>
- <message>
- <source>A new data directory will be created.</source>
- <translation type="unfinished">Một danh mục dữ liệu mới sẽ được tạo.</translation>
- </message>
- <message>
- <source>name</source>
- <translation type="unfinished">tên</translation>
- </message>
- <message>
- <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation type="unfinished">Danh mục đã tồn tại. Thêm %1 nếu bạn dự định creat một danh mục mới ở đây.</translation>
- </message>
- <message>
- <source>Path already exists, and is not a directory.</source>
- <translation type="unfinished">Path đã tồn tại, và không là danh mục.</translation>
- </message>
- <message>
- <source>Cannot create data directory here.</source>
- <translation type="unfinished">Không thể create dữ liệu danh mục tại đây.</translation>
- </message>
-</context>
+ </context>
<context>
<name>Intro</name>
- <message>
- <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
- <translation type="unfinished">Ãt nhất %1 GB data sẽ được trữ tại danh mục này, và nó sẽ lá»›n theo thá»i gian.</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
</message>
- <message>
- <source>Approximately %1 GB of data will be stored in this directory.</source>
- <translation type="unfinished">Gần đúng %1 GB of data sẽ được lưu giữ trong danh mục này.</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(of %n GB cần thiết)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB cần cho toàn blockchain)</numerusform>
+ </translation>
</message>
<message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(đủ để khôi phục các bản sao lưu trong %n ngày)</numerusform>
</translation>
</message>
<message>
- <source>%1 will download and store a copy of the Bitcoin block chain.</source>
- <translation type="unfinished">%1 sẽ download và lưu trữ một bản copy của Bitcoin block chain.</translation>
- </message>
- <message>
- <source>The wallet will also be stored in this directory.</source>
- <translation type="unfinished">Wallet sẽ cùng được lưu giữ trong danh mục này.</translation>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation type="unfinished">Lỗi: Danh mục data xác định "%1" không thể được tạo.</translation>
</message>
<message>
- <source>Error: Specified data directory "%1" cannot be created.</source>
- <translation type="unfinished">Error: Danh mục data xác định "%1" không thể được tạo.</translation>
+ <source>Welcome</source>
+ <translation type="unfinished">Chào mừng</translation>
</message>
<message>
- <source>Error</source>
- <translation type="unfinished">Lá»—i</translation>
+ <source>Welcome to %1.</source>
+ <translation type="unfinished">Chào mừng bạn đến %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 type="unfinished">Äây là lần đầu chÆ°Æ¡ng trình khởi chạy, bạn có thể chá»n nÆ¡i %1 sẽ lÆ°u trữ data.</translation>
+ <translation type="unfinished">Äây là lần đầu chÆ°Æ¡ng trình khởi chạy, bạn có thể chá»n nÆ¡i %1 sẽ lÆ°u trữ dữ liệu.</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 type="unfinished">Khi bạn click OK, %1 sẽ bắt đầu download và process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</translation>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">Giới hạn lưu trữ chuỗi khối thành</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
- <translation type="unfinished">Äảo ngược lại thiết lập này yêu cầu download lại toàn bá»™ blockchain. Download toàn bá»™ blockchain trÆ°á»›c và loại nó sau đó sẽ nhanh hÆ¡n. Vô hiệu hóa má»™t số tính năng nâng cao.</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 type="unfinished">Äồng bá»™ hóa ban đầu này rất đòi há»i, và có thể phÆ¡i bày các sá»± cố vá» phần cứng vá»›i máy tính của bạn trÆ°á»›c đó đã không được chú ý. Má»—i khi bạn chạy %1, nó sẽ tiếp tục tải vá» nÆ¡i nó dừng lại.</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 type="unfinished">Nếu bạn đã chá»n giá»›i hạn block chain lÆ°u trữ (pruning),dữ liệu lịch sá»­ vẫn phải được tải xuống và xá»­ lý, nhÆ°ng sẽ bị xóa sau đó để giữ cho việc sá»­ dụng Ä‘Ä©a của bạn ở mức usage thấp.</translation>
+ <translation type="unfinished">Äảo ngược lại thiết lập này yêu cầu tại lại toàn bá»™ chuá»—i khối. Tải vá» toàn bá»™ chuá»—i khối trÆ°á»›c và loại nó sau đó sẽ nhanh hÆ¡n. Vô hiệu hóa má»™t số tính năng nâng cao.</translation>
</message>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
<message>
- <source>Use the default data directory</source>
- <translation type="unfinished">Sử dụng default danh mục đa ta</translation>
+ <source>About %1</source>
+ <translation type="unfinished">Vá» %1</translation>
</message>
<message>
- <source>Use a custom data directory:</source>
- <translation type="unfinished">Sử dụng custom danh mục data:</translation>
+ <source>Command-line options</source>
+ <translation type="unfinished">Tùy chá»n dòng lệnh</translation>
</message>
</context>
<context>
- <name>HelpMessageDialog</name>
- <message>
- <source>version</source>
- <translation type="unfinished">phiên bản</translation>
- </message>
- </context>
-<context>
<name>ShutdownWindow</name>
<message>
- <source>Do not shut down the computer until this window disappears.</source>
- <translation type="unfinished">Äừng tắt máy tính đến khi cá»­a sổ này đóng.</translation>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1 đang tắt…</translation>
</message>
-</context>
+ </context>
<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 type="unfinished">Giao dịch gần đây có thể chưa được hiển thị, và vì vậy số dư wallet của bạn có thể không dúng. Thông tin này sẽ được làm đúng khi wallet hoàn thành đồng bộ với bitcoin network, như chi tiết bên dưới.</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 type="unfinished">Cố gắng spend các bitcoins bị ảnh hưởng bởi các giao dịch chưa được hiển thị sẽ không được chấp nhận bởi mạng.</translation>
- </message>
- <message>
- <source>Number of blocks left</source>
- <translation type="unfinished">Số của blocks còn lại</translation>
- </message>
- <message>
- <source>Last block time</source>
- <translation type="unfinished">Thá»i gian block cuối cùng</translation>
- </message>
- <message>
- <source>Progress</source>
- <translation type="unfinished">Tiến độ</translation>
- </message>
- <message>
- <source>Progress increase per hour</source>
- <translation type="unfinished">Tiến Ä‘á»™ tăng má»—i giá»</translation>
+ <source>Unknown…</source>
+ <translation type="unfinished">Không xác định…</translation>
</message>
<message>
- <source>Estimated time left until synced</source>
- <translation type="unfinished">Ước tính thá»i gian còn lại đến khi đồng bá»™</translation>
+ <source>calculating…</source>
+ <translation type="unfinished">đang tính toán…</translation>
</message>
<message>
- <source>Hide</source>
- <translation type="unfinished">Ẩn</translation>
- </message>
- <message>
- <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
- <translation type="unfinished">%1 đang được đồng bộ. Header và block sẽ được download từ các nốt lân cận và thẩm định tới khi đạt đỉnh của blockchain.</translation>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Không xác định. Äồng bá»™ hóa tiêu Ä‘á» (%1, %2%)…</translation>
</message>
</context>
<context>
<name>OpenURIDialog</name>
<message>
- <source>Open bitcoin URI</source>
- <translation type="unfinished">Mở bitcoin URI</translation>
- </message>
- <message>
<source>Paste address from clipboard</source>
<extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
- <translation type="unfinished">Paste address từ clipboard</translation>
+ <translation type="unfinished">Dán địa chỉ từ khay nhớ tạm</translation>
</message>
</context>
<context>
<name>OptionsDialog</name>
<message>
- <source>Options</source>
- <translation type="unfinished">Tùy chỉnh</translation>
- </message>
- <message>
- <source>&amp;Main</source>
- <translation type="unfinished">&amp;Chính</translation>
- </message>
- <message>
<source>Automatically start %1 after logging in to the system.</source>
- <translation type="unfinished">Tự động bắt đầu %1 sau khi đăng nhập vào system.</translation>
+ <translation type="unfinished">Tự động bắt đầu %1 sau khi đăng nhập vào hệ thống.</translation>
</message>
<message>
<source>&amp;Start %1 on system login</source>
- <translation type="unfinished">&amp;Bắt đầu %1 trên đăng nhập system</translation>
- </message>
- <message>
- <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
- <translation type="unfinished">Hiển thị nếu cung cấp default SOCKS5 proxy is used to reach peers via this network type.</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 type="unfinished">Minimize thay vì thoát khá»i ứng dụng khi cá»­a sổ đóng lại. Khi bật tùy chá»n này, ứng dụng sẽ chỉ được đóng sau khi chá»n Exit trong menu.</translation>
- </message>
- <message>
- <source>Open the %1 configuration file from the working directory.</source>
- <translation type="unfinished">Mở %1 configuration file từ danh mục làm việc working directory.</translation>
- </message>
- <message>
- <source>Open Configuration File</source>
- <translation type="unfinished">Mở File cấu hình</translation>
- </message>
- <message>
- <source>Reset all client options to default.</source>
- <translation type="unfinished">Reset tất cả client options to default.</translation>
- </message>
- <message>
- <source>&amp;Reset Options</source>
- <translation type="unfinished">&amp;Reset Tùy chá»n</translation>
- </message>
- <message>
- <source>Prune &amp;block storage to</source>
- <translation type="unfinished">Cắt tỉa và lưu trữ khối tới</translation>
- </message>
- <message>
- <source>Reverting this setting requires re-downloading the entire blockchain.</source>
- <translation type="unfinished">Hoàn nguyên cài đặt này yêu cầu tải xuống lại toàn bộ blockchain.</translation>
- </message>
- <message>
- <source>Accept connections from outside.</source>
- <translation type="unfinished">Chấp nhận kết nối từ bên ngoài</translation>
+ <translation type="unfinished">&amp;Bắt đầu %1 trên đăng nhập hệ thống</translation>
</message>
<message>
- <source>Allow incomin&amp;g connections</source>
- <translation type="unfinished">Chấp nhận kết nối đang tới</translation>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">Cho phép cắt bớt làm giảm đáng kể không gian đĩa cần thiết để lưu trữ các giao dịch. Tất cả các khối vẫn được xác nhận đầy đủ. Hoàn nguyên cài đặt này yêu cầu tải xuống lại toàn bộ chuỗi khối.</translation>
</message>
<message>
- <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
- <translation type="unfinished">Kết nối đến Bitcoin network qua một SOCKS5 proxy.</translation>
+ <source>Size of &amp;database cache</source>
+ <translation type="unfinished">Kích thước bộ nhớ cache của &amp;cơ sở dữ liệu</translation>
</message>
<message>
- <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
- <translation type="unfinished">&amp;Connect qua SOCKS5 proxy (default proxy):</translation>
+ <source>Number of script &amp;verification threads</source>
+ <translation type="unfinished">Số lượng tập lệnh và chuỗi &amp;xác minh</translation>
</message>
<message>
- <source>Used for reaching peers via:</source>
- <translation type="unfinished">Sử dụng reaching peers via:</translation>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation type="unfinished">Äịa chỉ IP của proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
- <source>Show only a tray icon after minimizing the window.</source>
- <translation type="unfinished">Hiển thị chỉ thẻ icon sau khi thu nhỠcửa sổ.</translation>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Các tùy chá»n trong há»™p thoại này bị ghi đè bởi dòng lệnh</translation>
</message>
<message>
- <source>&amp;Minimize to the tray instead of the taskbar</source>
- <translation type="unfinished">&amp;Minimize đến thẻ thay vì taskbar</translation>
- </message>
- <message>
- <source>User Interface &amp;language:</source>
- <translation type="unfinished">Giao diện ngÆ°á»i dùng &amp;language:</translation>
- </message>
- <message>
- <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
- <translation type="unfinished">Giao diện ngôn ngữ ngÆ°á»i dùng có thể được thiết lập tại đây. Tùy chá»n này sẽ có hiệu lá»±c sau khi khởi Ä‘á»™ng lại %1.</translation>
+ <source>Reset all client options to default.</source>
+ <translation type="unfinished">Äặt lại tất cả các tùy chá»n máy khách vá» mặc định.</translation>
</message>
<message>
- <source>&amp;Unit to show amounts in:</source>
- <translation type="unfinished">&amp;Unit để hiện số lượng tại đây:</translation>
+ <source>&amp;Network</source>
+ <translation type="unfinished">&amp;Mạng</translation>
</message>
<message>
- <source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
- <translation type="unfinished">Chá»n default Ä‘Æ¡n vị phân chia để hiện giao diện và Ä‘ang gá»­i coins.</translation>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">Kích thÆ°á»›c bá»™ đệm cÆ¡ sở dữ liệu tối Ä‘a. Bá»™ nhá»› đệm lá»›n hÆ¡n có thể góp phần đồng bá»™ hóa nhanh hÆ¡n, sau đó lợi ích ít rõ rệt hÆ¡n đối vá»›i hầu hết các trÆ°á»ng hợp sá»­ dụng. Giảm kích thÆ°á»›c bá»™ nhá»› cache sẽ làm giảm mức sá»­ dụng bá»™ nhá»›. Bá»™ nhá»› mempool không sá»­ dụng được chia sẻ cho bá»™ nhá»› cache này.</translation>
</message>
<message>
- <source>Whether to show coin control features or not.</source>
- <translation type="unfinished">Cho hiển thị tính năng coin control hoặc không.</translation>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">Äặt số lượng chuá»—i xác minh tập lệnh. Giá trị âm tÆ°Æ¡ng ứng vá»›i số lõi bạn muốn để lại miá»…n phí cho hệ thống.</translation>
</message>
<message>
- <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
- <translation type="unfinished">Kết nối với mạng Bitcoin thông qua proxy SOCKS5 riêng cho các dịch vụ Tor</translation>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">Äiá»u này cho phép bạn hoặc công cụ của bên thứ ba giao tiếp vá»›i nút thông qua các lệnh dòng lệnh và JSON-RPC.</translation>
</message>
<message>
- <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
- <translation type="unfinished">Sử dụng proxy SOCKS&amp;5 riêng biệt để tiếp cận các đối tác ngang hàng thông qua các dịch vụ Tor Onion.</translation>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">Bật máy chủ R&amp;PC</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">Các tùy chá»n được đặt trong há»™p thoại này bị ghi đè bởi dòng lệnh hoặc trong tệp cấu hình:</translation>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Có đặt trừ phí khá»i số tiá»n làm mặc định hay không.</translation>
</message>
<message>
- <source>&amp;Cancel</source>
- <translation type="unfinished">&amp;Hủy</translation>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">Trừ &amp;phí khá»i số tiá»n theo mặc định</translation>
</message>
<message>
- <source>none</source>
- <translation type="unfinished">không có gì</translation>
+ <source>Expert</source>
+ <translation type="unfinished">Chuyên gia</translation>
</message>
<message>
- <source>Confirm options reset</source>
- <translation type="unfinished">Confirm tùy chá»n reset</translation>
+ <source>Enable coin &amp;control features</source>
+ <translation type="unfinished">Bật tính năng &amp;kiểm soát và tiá»n xu</translation>
</message>
<message>
- <source>Client restart required to activate changes.</source>
- <translation type="unfinished">Client yêu cầu khởi động lại để thay đổi có hiệu lực.</translation>
+ <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 type="unfinished">Nếu bạn vô hiệu hóa chi tiêu của thay đổi chÆ°a được xác nhận, thay đổi từ má»™t giao dịch sẽ không thể được sá»­ dụng cho đến khi giao dịch đó có ít nhất má»™t xác nhận. Äiá»u này cÅ©ng ảnh hưởng đến cách tính số dÆ° của bạn.</translation>
</message>
<message>
- <source>Client will be shut down. Do you want to proceed?</source>
- <translation type="unfinished">Client sẽ đóng lại. Tiếp tục chứ?</translation>
+ <source>&amp;Spend unconfirmed change</source>
+ <translation type="unfinished">&amp;Chi tiêu thay đổi chưa được xác nhận</translation>
</message>
<message>
- <source>Configuration options</source>
- <extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
- <translation type="unfinished">Tùy chá»n cấu hình</translation>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">Bật Ä‘iá»u khiển &amp;PSBT</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>
- <extracomment>Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</extracomment>
- <translation type="unfinished">File cấu hình được sá»­ dụng để chỉ định các tùy chá»n nâng cao của ngÆ°á»i dùng mà ghi đè GUI settings. Ngoài ra, bất kỳ tùy chá»n dòng lệnh sẽ ghi đè lên tập tin cấu hình này.</translation>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">Có hiển thị các Ä‘iá»u khiển PSBT hay không.</translation>
</message>
<message>
- <source>Cancel</source>
- <translation type="unfinished">Hủy</translation>
+ <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 type="unfinished">URL của bên thứ ba (ví dụ: trình khám phá khối) xuất hiện trong tab giao dịch dÆ°á»›i dạng các mục menu ngữ cảnh. %s trong URL được thay thế bằng mã băm giao dịch. Nhiá»u URL được phân tách bằng thanh dá»c |. </translation>
</message>
<message>
- <source>Error</source>
- <translation type="unfinished">Lá»—i</translation>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">&amp;URL giao dịch của bên thứ ba</translation>
</message>
<message>
- <source>The configuration file could not be opened.</source>
- <translation type="unfinished">Không thẻ mở tệp cấu hình.</translation>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">Äược biên dịch mà không có há»— trợ ký bên ngoài (bắt buá»™c đối vá»›i ký bên ngoài)</translation>
</message>
<message>
- <source>This change would require a client restart.</source>
- <translation type="unfinished">Việc change này sẽ cần một client restart.</translation>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">Các thiết lập hiện tại sẽ được sao lưu tại"%1".</translation>
</message>
<message>
- <source>The supplied proxy address is invalid.</source>
- <translation type="unfinished">Cung cấp proxy address thì invalid.</translation>
+ <source>Continue</source>
+ <translation type="unfinished">Tiếp tục</translation>
</message>
-</context>
+ </context>
<context>
- <name>OverviewPage</name>
- <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 type="unfinished">Thông tin được hiển thị có thể đã lá»—i thá»i. Cái wallet tá»± Ä‘á»™ng đồng bá»™ vá»›i Bitcoin network sau má»™t connection được thiết lập, nhÆ°ng quá trình này vẫn chÆ°a completed yet.</translation>
- </message>
- <message>
- <source>Watch-only:</source>
- <translation type="unfinished">Chỉ-xem:</translation>
- </message>
- <message>
- <source>Available:</source>
- <translation type="unfinished">Có hiệu lực:</translation>
- </message>
- <message>
- <source>Your current spendable balance</source>
- <translation type="unfinished">Số dư khả dụng:</translation>
- </message>
- <message>
- <source>Pending:</source>
- <translation type="unfinished">Äang xá»­ lý:</translation>
- </message>
- <message>
- <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
- <translation type="unfinished">Tất cả giao dịch vẫn chưa được confirmed, và chưa tính vào số dư có thể chi tiêu</translation>
- </message>
- <message>
- <source>Immature:</source>
- <translation type="unfinished">Chưa hoàn thiện:</translation>
- </message>
- <message>
- <source>Mined balance that has not yet matured</source>
- <translation type="unfinished">Mined balance chưa matured hẳn</translation>
- </message>
- <message>
- <source>Balances</source>
- <translation type="unfinished">Số dư</translation>
- </message>
- <message>
- <source>Total:</source>
- <translation type="unfinished">Tổng cộng:</translation>
- </message>
- <message>
- <source>Your current total balance</source>
- <translation type="unfinished">Tổng số dư hiện tại</translation>
- </message>
- <message>
- <source>Your current balance in watch-only addresses</source>
- <translation type="unfinished">Số dư hiện tại trong địa chỉ watch-only</translation>
- </message>
- <message>
- <source>Spendable:</source>
- <translation type="unfinished">Có thể sử dụng</translation>
- </message>
- <message>
- <source>Recent transactions</source>
- <translation type="unfinished">Giao dịch gần đây</translation>
- </message>
- <message>
- <source>Unconfirmed transactions to watch-only addresses</source>
- <translation type="unfinished">Giao dịch chưa được xác nhận đến watch-only addresses</translation>
- </message>
- <message>
- <source>Mined balance in watch-only addresses that has not yet matured</source>
- <translation type="unfinished">Mined số dư trong watch-only address chưa matured hẳn</translation>
- </message>
+ <name>OptionsModel</name>
<message>
- <source>Current total balance in watch-only addresses</source>
- <translation type="unfinished">Tổng số dư hiện tại trong watch-only addresses</translation>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">Không thể Ä‘á»c thiết lập "%1", %2.</translation>
</message>
- </context>
+</context>
<context>
<name>PSBTOperationsDialog</name>
<message>
- <source>Dialog</source>
- <translation type="unfinished">Bảng thoại</translation>
- </message>
- <message>
- <source>Sign Tx</source>
- <translation type="unfinished">Äăng ký Tx</translation>
- </message>
- <message>
- <source>Broadcast Tx</source>
- <translation type="unfinished">Truyá»n phát Tx</translation>
- </message>
- <message>
- <source>Copy to Clipboard</source>
- <translation type="unfinished">Lưu vào bảng tạm</translation>
- </message>
- <message>
- <source>Close</source>
- <translation type="unfinished">Äóng</translation>
- </message>
- <message>
- <source>Failed to load transaction: %1</source>
- <translation type="unfinished">Tải giao dịch thất bại: %1</translation>
- </message>
- <message>
- <source>Failed to sign transaction: %1</source>
- <translation type="unfinished">Äăng ký giao dịch thất bại :%1</translation>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">Không thể ký đầu vào khi ví bị khóa.</translation>
</message>
<message>
- <source>Could not sign any more inputs.</source>
- <translation type="unfinished">Không thể thêm bất cứ nguồn vào nào.</translation>
- </message>
- <message>
- <source>Signed %1 inputs, but more signatures are still required.</source>
- <translation type="unfinished">Nguồn %1 đã nạp, nhưng vẫn cần thêm các nguồn khác.</translation>
- </message>
- <message>
- <source>Unknown error processing transaction.</source>
- <translation type="unfinished">Lỗi không xác định xử lý giao dịch</translation>
- </message>
- <message>
- <source>Transaction broadcast successfully! Transaction ID: %1</source>
- <translation type="unfinished">Giao dịch dã được truyá»n thành công: Mã giao dịch: %1</translation>
- </message>
- <message>
- <source>Transaction broadcast failed: %1</source>
- <translation type="unfinished">Giao dịch truyá»n phát không thành công: %1</translation>
- </message>
- <message>
- <source>PSBT copied to clipboard.</source>
- <translation type="unfinished">Dữ liệu PSBT được sao chép vào bộ nhớ tạm.</translation>
- </message>
- <message>
- <source>Save Transaction Data</source>
- <translation type="unfinished">Lưu trữ giao dịch</translation>
- </message>
- <message>
- <source>PSBT saved to disk.</source>
- <translation type="unfinished">Dữ liệu PSBT được lưu vào ổ đĩa.</translation>
- </message>
- <message>
- <source> * Sends %1 to %2</source>
- <translation type="unfinished">*Gá»­i %1 tá»›i %2</translation>
- </message>
- <message>
- <source>Unable to calculate transaction fee or total transaction amount.</source>
- <translation type="unfinished">Không thể tính phí giao dịch hoặc tổng số tiá»n giao dịch.</translation>
- </message>
- <message>
- <source>Pays transaction fee: </source>
- <translation type="unfinished">Trả phí giao dịch</translation>
- </message>
- <message>
- <source>Total Amount</source>
- <translation type="unfinished">Tổng số</translation>
- </message>
- <message>
- <source>or</source>
- <translation type="unfinished">hoặc</translation>
- </message>
- <message>
- <source>Transaction is missing some information about inputs.</source>
- <translation type="unfinished">Giao dịch thiếu một số thông tin vỠđầu vào.</translation>
+ <source>Transaction has %1 unsigned inputs.</source>
+ <translation type="unfinished">Giao dịch có %1 đầu vào chưa được ký.</translation>
</message>
<message>
<source>Transaction still needs signature(s).</source>
- <translation type="unfinished">Giao dịch cần chữ ký</translation>
+ <translation type="unfinished">Giao dịch vẫn cần (các) chữ ký.</translation>
</message>
<message>
- <source>(But this wallet cannot sign transactions.)</source>
- <translation type="unfinished">(Nhưng ví này không thể đăng ký giao dịch.)</translation>
- </message>
- <message>
- <source>(But this wallet does not have the right keys.)</source>
- <translation type="unfinished">(Nhưng ví này không có chìa khóa phù hợp.)</translation>
- </message>
- <message>
- <source>Transaction is fully signed and ready for broadcast.</source>
- <translation type="unfinished">Giao dịch đã được đăng ký và chuẩn bị để phát lên</translation>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Nhưng không có ví nào được tải.)</translation>
</message>
</context>
<context>
- <name>PaymentServer</name>
- <message>
- <source>Cannot start bitcoin: click-to-pay handler</source>
- <translation type="unfinished">Không thể khởi tạo bitcoin: click-to-pay handler</translation>
- </message>
- <message>
- <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
- <translation type="unfinished">'bitcoin://' không khả dụng URI. Dùng thay vì 'bitcoin:' .</translation>
- </message>
- <message>
- <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
- <translation type="unfinished">URI không thể phân tích cú pháp! Äây có thể gây nên bởi invalid Bitcoin address hoặc URI không đúng định dạng tham số.</translation>
- </message>
- <message>
- <source>Payment request file handling</source>
- <translation type="unfinished">Payment request file đang xử lý</translation>
- </message>
-</context>
-<context>
<name>PeerTableModel</name>
<message>
- <source>User Agent</source>
- <extracomment>Title of Peers Table column which contains the peer's User Agent string.</extracomment>
- <translation type="unfinished">User Äặc Vụ</translation>
- </message>
- <message>
- <source>Sent</source>
- <extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment>
- <translation type="unfinished">Gá»­i</translation>
- </message>
- <message>
- <source>Received</source>
- <extracomment>Title of Peers Table column which indicates the total amount of network information we have received from the peer.</extracomment>
- <translation type="unfinished">Nhận</translation>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Tuổi</translation>
</message>
<message>
<source>Address</source>
<extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
<translation type="unfinished">Äịa chỉ</translation>
</message>
- <message>
- <source>Network</source>
- <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment>
- <translation type="unfinished">Mạng</translation>
- </message>
- </context>
-<context>
- <name>QRImageWidget</name>
- <message>
- <source>&amp;Copy Image</source>
- <translation type="unfinished">&amp;Sao chép ảnh</translation>
- </message>
- <message>
- <source>Resulting URI too long, try to reduce the text for label / message.</source>
- <translation type="unfinished">Äang tính toán URI quá dài, cố gắng giảm text cho label / message.</translation>
- </message>
- <message>
- <source>Error encoding URI into QR Code.</source>
- <translation type="unfinished">Error đang mã hóa URI đến QR Code.</translation>
- </message>
- <message>
- <source>QR code support not available.</source>
- <translation type="unfinished">Sự hổ trợ mã QR không sẵn có</translation>
- </message>
- <message>
- <source>Save QR Code</source>
- <translation type="unfinished">LÆ°u QR Code</translation>
- </message>
</context>
<context>
<name>RPCConsole</name>
<message>
- <source>&amp;Information</source>
- <translation type="unfinished">&amp;Thông tin</translation>
- </message>
- <message>
- <source>General</source>
- <translation type="unfinished">Tổng thể</translation>
- </message>
- <message>
- <source>To specify a non-default location of the data directory use the '%1' option.</source>
- <translation type="unfinished">Äể chỉ ra má»™t nÆ¡i không mặt định của thÆ° mục dữ liệu hãy dùng tùy chá»n '%1'</translation>
- </message>
- <message>
- <source>Blocksdir</source>
- <translation type="unfinished">Thư mục chứa các khối Blocksdir</translation>
- </message>
- <message>
- <source>To specify a non-default location of the blocks directory use the '%1' option.</source>
- <translation type="unfinished">Äể chỉ ra má»™t nÆ¡i không mặt định của thÆ° mục các khối hãy dùng tùy chá»n '%1'</translation>
- </message>
- <message>
- <source>Startup time</source>
- <translation type="unfinished">Startup lúc</translation>
- </message>
- <message>
- <source>Network</source>
- <translation type="unfinished">Mạng</translation>
- </message>
- <message>
- <source>Name</source>
- <translation type="unfinished">Tên</translation>
+ <source>Last Transaction</source>
+ <translation type="unfinished">Giao dịch cuối cùng</translation>
</message>
<message>
- <source>Number of connections</source>
- <translation type="unfinished">Số lượng connections</translation>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Cho dù chúng tôi chuyển tiếp địa chỉ đến đồng đẳng này.</translation>
</message>
<message>
- <source>Memory Pool</source>
- <translation type="unfinished">Pool Bá»™ Nhá»›</translation>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">Chuyển tiếp địa chỉ</translation>
</message>
<message>
- <source>Current number of transactions</source>
- <translation type="unfinished">Số giao dịch hiện tại</translation>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Tổng số các địa chỉ đã được xá»­ lý thành công nhận được từ ngÆ°á»i này (ngoại trừ các địa chỉ sụt giảm do giá»›i hạn tốc Ä‘á»™) </translation>
</message>
<message>
- <source>Memory usage</source>
- <translation type="unfinished">Bá»™ nhá»› usage</translation>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Tổng số các địa chỉ nhận được từ ngÆ°á»i ngày đã bị sụt giảm (không được xá»­ lý thành công) do giá»›i hạn vá» tốc Ä‘á»™.</translation>
</message>
<message>
- <source>Wallet: </source>
- <translation type="unfinished">Ví :</translation>
- </message>
- <message>
- <source>(none)</source>
- <translation type="unfinished">(không)</translation>
- </message>
- <message>
- <source>Received</source>
- <translation type="unfinished">Nhận</translation>
- </message>
- <message>
- <source>Sent</source>
- <translation type="unfinished">Gá»­i</translation>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Các địa chỉ đã được xử lý</translation>
</message>
<message>
- <source>Banned peers</source>
- <translation type="unfinished">Bị khóa peers</translation>
- </message>
- <message>
- <source>Select a peer to view detailed information.</source>
- <translation type="unfinished">Chá»n má»™t peer để xem thông tin chi tiết.</translation>
- </message>
- <message>
- <source>Version</source>
- <translation type="unfinished">Phiên bản</translation>
- </message>
- <message>
- <source>Starting Block</source>
- <translation type="unfinished">Block Bắt Äầu</translation>
- </message>
- <message>
- <source>Synced Headers</source>
- <translation type="unfinished">Headers đã được đồng bộ</translation>
- </message>
- <message>
- <source>Synced Blocks</source>
- <translation type="unfinished">Blocks đã được đồng bộ</translation>
- </message>
- <message>
- <source>The mapped Autonomous System used for diversifying peer selection.</source>
- <translation type="unfinished">Hệ thống tá»± Ä‘á»™ng ánh xạ được sá»­ dụng để Ä‘a dạng hóa lá»±a chá»n ngang hàng.</translation>
- </message>
- <message>
- <source>Mapped AS</source>
- <translation type="unfinished">AS đã được map</translation>
- </message>
- <message>
- <source>User Agent</source>
- <translation type="unfinished">User Äặc Vụ</translation>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">Tỷ lệ địa chỉ có giới hạn</translation>
</message>
<message>
<source>Node window</source>
<translation type="unfinished">Cửa sổ node</translation>
</message>
<message>
- <source>Current block height</source>
- <translation type="unfinished">Kích thước khối hiện tại</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 type="unfinished">Mở cái %1 debug log file từ danh mục dữ liệu hiện tại. Äiá»u này cần vài giây cho large log files.</translation>
- </message>
- <message>
- <source>Decrease font size</source>
- <translation type="unfinished">Giảm font size</translation>
- </message>
- <message>
- <source>Increase font size</source>
- <translation type="unfinished">Tăng font size</translation>
- </message>
- <message>
- <source>Permissions</source>
- <translation type="unfinished">Cho phép</translation>
- </message>
- <message>
- <source>Services</source>
- <translation type="unfinished">Dịch vụ</translation>
- </message>
- <message>
- <source>Connection Time</source>
- <translation type="unfinished">Connection Thá»i Gian</translation>
- </message>
- <message>
- <source>Last Send</source>
- <translation type="unfinished">Gửi Sau Cùng</translation>
- </message>
- <message>
- <source>Last Receive</source>
- <translation type="unfinished">Nhận Sau Cùng</translation>
- </message>
- <message>
- <source>The duration of a currently outstanding ping.</source>
- <translation type="unfinished">Thá»i hạn của má»™t ping hiện Ä‘ang nổi trá»™i.</translation>
- </message>
- <message>
- <source>Ping Wait</source>
- <translation type="unfinished">Ping Chá»</translation>
- </message>
- <message>
- <source>Min Ping</source>
- <translation type="unfinished">Ping NhỠNhất</translation>
- </message>
- <message>
- <source>Time Offset</source>
- <translation type="unfinished">Thá»i gian Offset</translation>
- </message>
- <message>
- <source>Last block time</source>
- <translation type="unfinished">Thá»i gian block cuối cùng</translation>
- </message>
- <message>
- <source>&amp;Console</source>
- <translation type="unfinished">&amp;BangDieuKhien</translation>
- </message>
- <message>
- <source>Debug log file</source>
- <translation type="unfinished">Debug file log</translation>
- </message>
- <message>
- <source>Clear console</source>
- <translation type="unfinished">Xóa console</translation>
- </message>
- <message>
- <source>Executing command without any wallet</source>
- <translation type="unfinished">Äang chạy lệnh khi không có ví nào</translation>
- </message>
- <message>
- <source>Executing command using "%1" wallet</source>
- <translation type="unfinished">Chạy lệnh bằng ví "%1"</translation>
- </message>
- <message>
- <source>Unknown</source>
- <translation type="unfinished">Không biết</translation>
- </message>
-</context>
-<context>
- <name>ReceiveCoinsDialog</name>
- <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 type="unfinished">Má»™t optional lá»i nhắn để đính kèm đến payment request, cái mà sẽ được hiển thị khi mà request Ä‘ang mở. LÆ°u ý: Tin nhắn này sẽ không được gá»­i vá»›i payment over the Bitcoin network.</translation>
- </message>
- <message>
- <source>An optional label to associate with the new receiving address.</source>
- <translation type="unfinished">Một optional label để liên kết với address đang nhận mới.</translation>
- </message>
- <message>
- <source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
- <translation type="unfinished">Sử dụng form cho request thanh toán. Tất cả chỗ trống là &lt;b&gt;optional&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 type="unfinished">Má»™t optional giá trị để request. Äể lại đây khoảng trống hoặc zero để không request má»™t giá trị xác định.</translation>
- </message>
- <message>
- <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
- <translation type="unfinished">Má»™t nhãn tùy chá»n để liên kết vá»›i địa chỉ nhận má»›i (được bạn sá»­ dụng để xác định hóa Ä‘Æ¡n). Nó cÅ©ng được đính kèm vá»›i yêu cầu thanh toán.</translation>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">&amp;Sao chép IP/Netmask</translation>
</message>
- <message>
- <source>An optional message that is attached to the payment request and may be displayed to the sender.</source>
- <translation type="unfinished">Má»™t thông báo tùy chá»n được đính kèm vá»›i yêu cầu thanh toán và có thể được hiển thị cho ngÆ°á»i gá»­i.</translation>
- </message>
- <message>
- <source>&amp;Create new receiving address</source>
- <translation type="unfinished">&amp;Tạo địa chỉ nhận mới</translation>
- </message>
- <message>
- <source>Clear all fields of the form.</source>
- <translation type="unfinished">Xóa hết các khoảng trống của form.</translation>
- </message>
- <message>
- <source>Clear</source>
- <translation type="unfinished">Xóa</translation>
- </message>
- <message>
- <source>Requested payments history</source>
- <translation type="unfinished">Yêu cầu lịch sử giao dịch</translation>
- </message>
- <message>
- <source>Show the selected request (does the same as double clicking an entry)</source>
- <translation type="unfinished">Hiển thị request đã chá»n (does the same as double clicking an entry)</translation>
- </message>
- <message>
- <source>Show</source>
- <translation type="unfinished">Hiển thị</translation>
- </message>
- <message>
- <source>Remove the selected entries from the list</source>
- <translation type="unfinished">Xóa bá» mục Ä‘ang chá»n từ danh sách</translation>
- </message>
- <message>
- <source>Remove</source>
- <translation type="unfinished">Gỡ bá»</translation>
- </message>
- <message>
- <source>Copy &amp;URI</source>
- <translation type="unfinished">Sao chép &amp;URI</translation>
- </message>
- <message>
- <source>Could not unlock wallet.</source>
- <translation type="unfinished">Không thể unlock wallet.</translation>
- </message>
- <message>
- <source>Could not generate new %1 address</source>
- <translation type="unfinished">Không thể tạo ra %1 địa chỉ mới</translation>
- </message>
-</context>
-<context>
- <name>ReceiveRequestDialog</name>
- <message>
- <source>Address:</source>
- <translation type="unfinished">Äịa chỉ</translation>
- </message>
- <message>
- <source>Amount:</source>
- <translation type="unfinished">Số lượng:</translation>
- </message>
- <message>
- <source>Label:</source>
- <translation type="unfinished">Nhãn</translation>
- </message>
- <message>
- <source>Message:</source>
- <translation type="unfinished">Tin nhắn:</translation>
- </message>
- <message>
- <source>Wallet:</source>
- <translation type="unfinished">Ví tiá»n</translation>
- </message>
- <message>
- <source>Copy &amp;URI</source>
- <translation type="unfinished">Sao chép &amp;URI</translation>
- </message>
- <message>
- <source>Copy &amp;Address</source>
- <translation type="unfinished">Sao chép địa chỉ</translation>
- </message>
- <message>
- <source>Payment information</source>
- <translation type="unfinished">Payment thông tin</translation>
- </message>
- <message>
- <source>Request payment to %1</source>
- <translation type="unfinished">Request payment đến %1</translation>
- </message>
-</context>
+ </context>
<context>
<name>RecentRequestsTableModel</name>
<message>
- <source>Date</source>
- <translation type="unfinished">Ngày</translation>
- </message>
- <message>
<source>Label</source>
<translation type="unfinished">Nhãn</translation>
</message>
<message>
- <source>Message</source>
- <translation type="unfinished">Tin nhắn</translation>
- </message>
- <message>
<source>(no label)</source>
- <translation type="unfinished">(không nhãn)</translation>
- </message>
- <message>
- <source>(no message)</source>
- <translation type="unfinished">(no tin nhắn)</translation>
- </message>
- <message>
- <source>(no amount requested)</source>
- <translation type="unfinished">(không amount yêu cầu)</translation>
+ <translation type="unfinished">(không có nhãn)</translation>
</message>
- <message>
- <source>Requested</source>
- <translation type="unfinished">Äã yêu cầu</translation>
- </message>
-</context>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
- <source>Send Coins</source>
- <translation type="unfinished">Gá»­i Coins</translation>
- </message>
- <message>
- <source>Coin Control Features</source>
- <translation type="unfinished">Coin Control Tính-năng</translation>
- </message>
- <message>
- <source>automatically selected</source>
- <translation type="unfinished">được chá»n má»™t cách hoàn toàn tá»± Ä‘á»™ng</translation>
- </message>
- <message>
- <source>Insufficient funds!</source>
- <translation type="unfinished">Không đủ tiá»n kìa!</translation>
- </message>
- <message>
- <source>Quantity:</source>
- <translation type="unfinished">Số lượng:</translation>
- </message>
- <message>
- <source>Amount:</source>
- <translation type="unfinished">Số lượng:</translation>
- </message>
- <message>
- <source>Fee:</source>
- <translation type="unfinished">Phí:</translation>
- </message>
- <message>
- <source>After Fee:</source>
- <translation type="unfinished">Sau Phí:</translation>
- </message>
- <message>
- <source>Change:</source>
- <translation type="unfinished">Thay đổi:</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 type="unfinished">Nếu cái này được bật, nhưng việc change address thì trống hoặc invalid, change sẽ được gửi cho một address vừa được tạo mới.</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 type="unfinished">Sá»­ dụng fallbackfee có thể dẫn đến hết quả Ä‘ang gá»­i má»™t transaction mà nó sẽ mất hàng giá» hoặc ngày (hoặc chẳng bao giá») được confirm. Suy nghÄ© chá»n fee của bạn bình thÆ°á»ng hoặc chá» cho đến khi validated hoàn thành chain.</translation>
- </message>
- <message>
- <source>Warning: Fee estimation is currently not possible.</source>
- <translation type="unfinished">Warning: Fee ước tính hiện tại không khả thi.</translation>
- </message>
- <message>
- <source>per kilobyte</source>
- <translation type="unfinished">trên mỗi kilobyte</translation>
- </message>
- <message>
- <source>Hide</source>
- <translation type="unfinished">Ẩn</translation>
- </message>
- <message>
- <source>Recommended:</source>
- <translation type="unfinished">Khuyên dùng:</translation>
- </message>
- <message>
- <source>Send to multiple recipients at once</source>
- <translation type="unfinished">Gá»­i đến tập thể ngÆ°á»i nhận má»™t lần</translation>
- </message>
- <message>
- <source>Clear all fields of the form.</source>
- <translation type="unfinished">Xóa hết các khoảng trống của form.</translation>
- </message>
- <message>
- <source>Dust:</source>
- <translation type="unfinished">Rác:</translation>
- </message>
- <message>
- <source>Hide transaction fee settings</source>
- <translation type="unfinished">Ẩn cài đặt phí giao dịch</translation>
- </message>
- <message>
- <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">Khi có khối lượng giao dịch ít hÆ¡n chổ trống trong các khối, các nhà đào má» cÅ©ng nhÆ° các nút chuyển tiếp có thể thá»±c thi chỉ vá»›i má»™t khoản phí tối thiểu. Chỉ trả khoản phí tối thiểu này là tốt, nhÆ°ng lÆ°u ý rằng Ä‘iá»u này có thể dẫn đến má»™t giao dịch không bao giá» xác nhận má»™t khi có nhu cầu giao dịch bitcoin nhiá»u hÆ¡n khả năng mạng có thể xá»­ lý.</translation>
- </message>
- <message>
- <source>A too low fee might result in a never confirming transaction (read the tooltip)</source>
- <translation type="unfinished">Má»™t khoản phí quá thấp có thể dẫn đến má»™t giao dịch không bao giá» xác nhận (Ä‘á»c chú giải công cụ)</translation>
- </message>
- <message>
- <source>Confirmation time target:</source>
- <translation type="unfinished">Thá»i gian xác nhận đối tượng:</translation>
- </message>
- <message>
- <source>Enable Replace-By-Fee</source>
- <translation type="unfinished">Kích hoạt Phí thay thế</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 type="unfinished">Vá»›i Phí thay thế (BIP-125), bạn có thể tăng phí giao dịch sau khi được gá»­i. Nếu không có Ä‘iá»u này, má»™t khoản phí cao hÆ¡n có thể được Ä‘á» xuất để bù đắp cho rủi ro chậm trá»… giao dịch tăng lên.</translation>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Bạn có muốn tạo giao dịch này không?</translation>
</message>
<message>
- <source>Balance:</source>
- <translation type="unfinished">Số dư:</translation>
- </message>
- <message>
- <source>Confirm the send action</source>
- <translation type="unfinished">Confirm hành động gửi</translation>
- </message>
- <message>
- <source>Copy quantity</source>
- <translation type="unfinished">Sao chép số lượng</translation>
- </message>
- <message>
- <source>Copy amount</source>
- <translation type="unfinished">Sao chép số lượng</translation>
- </message>
- <message>
- <source>Copy fee</source>
- <translation type="unfinished">Sao chép phí</translation>
- </message>
- <message>
- <source>Copy after fee</source>
- <translation type="unfinished">Sao chép sau phí</translation>
- </message>
- <message>
- <source>Copy bytes</source>
- <translation type="unfinished">Sao chép bytes</translation>
- </message>
- <message>
- <source>Copy dust</source>
- <translation type="unfinished">Sao chép rác</translation>
- </message>
- <message>
- <source>Copy change</source>
- <translation type="unfinished">Sao chép thay đổi</translation>
- </message>
- <message>
- <source>Cr&amp;eate Unsigned</source>
- <translation type="unfinished">Cr&amp;eate không được ký</translation>
- </message>
- <message>
- <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
- <translation type="unfinished">Tạo Giao dịch Bitcoin được ký một phần (PSBT) để sử dụng với các dạng như: ví ngoại tuyến %1 hoặc ví phần cứng tương thích PSBT.</translation>
- </message>
- <message>
- <source> from wallet '%1'</source>
- <translation type="unfinished">từ ví '%1'</translation>
- </message>
- <message>
- <source>%1 to '%2'</source>
- <translation type="unfinished">%1 tá»›i '%2'</translation>
- </message>
- <message>
- <source>%1 to %2</source>
- <translation type="unfinished">%1 đến%2</translation>
- </message>
- <message>
- <source>Save Transaction Data</source>
- <translation type="unfinished">Lưu trữ giao dịch</translation>
- </message>
- <message>
- <source>PSBT saved</source>
- <translation type="unfinished">PSBT đã lưu</translation>
- </message>
- <message>
- <source>or</source>
- <translation type="unfinished">hoặc</translation>
- </message>
- <message>
- <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
- <translation type="unfinished">Bạn có thể tăng phí sau khi gửi( với tín hiệu Phí Thay Thế, BIP-125)</translation>
- </message>
- <message>
- <source>Please, review your transaction.</source>
- <extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
- <translation type="unfinished">Làm ơn xem xét đánh giá giao dịch của bạn.</translation>
- </message>
- <message>
- <source>Not signalling Replace-By-Fee, BIP-125.</source>
- <translation type="unfinished">Không có tín hiệu Phí Thay Thế, BIP-125.</translation>
- </message>
- <message>
- <source>Total Amount</source>
- <translation type="unfinished">Tổng số</translation>
- </message>
- <message>
- <source>Confirm send coins</source>
- <translation type="unfinished">Confirm gá»­i coins</translation>
- </message>
- <message>
- <source>Watch-only balance:</source>
- <translation type="unfinished">Số dư chỉ xem:</translation>
- </message>
- <message>
- <source>The recipient address is not valid. Please recheck.</source>
- <translation type="unfinished">Äịa chỉ ngÆ°á»i nhận address thì không valid. Kiểm tra lại Ä‘i.</translation>
- </message>
- <message>
- <source>The amount to pay must be larger than 0.</source>
- <translation type="unfinished">Giả trị để pay cần phải lớn hơn 0.</translation>
- </message>
- <message>
- <source>The amount exceeds your balance.</source>
- <translation type="unfinished">Số tiá»n vượt quá số dÆ° của bạn.</translation>
- </message>
- <message>
- <source>The total exceeds your balance when the %1 transaction fee is included.</source>
- <translation type="unfinished">Tổng số lớn hơn số dư của bạn khi %1 transaction fee được tính vào.</translation>
- </message>
- <message>
- <source>Duplicate address found: addresses should only be used once each.</source>
- <translation type="unfinished">Trùng address được tìm thấy: địa chỉ chỉ nên được dùng một lần.</translation>
- </message>
- <message>
- <source>Transaction creation failed!</source>
- <translation type="unfinished">Transaction khởi tạo thất bại!</translation>
- </message>
- <message>
- <source>A fee higher than %1 is considered an absurdly high fee.</source>
- <translation type="unfinished">Một fee lớn hơn %1 được coi là ngớ ngẩn cao fee.</translation>
- </message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">Payment request hết hạn.</translation>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">Vui lòng xem lại giao dịch của bạn. Bạn có thể tạo và gửi giao dịch này hoặc tạo Giao dịch Bitcoin được ký một phần (PSBT), bạn có thể lưu hoặc sao chép và sau đó ký bằng, ví dụ: ví %1 ngoại tuyến hoặc ví phần cứng tương thích với PSBT.</translation>
</message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>Ước tính sẽ bắt đầu xác nhận trong %n khối.</numerusform>
</translation>
</message>
<message>
- <source>Warning: Unknown change address</source>
- <translation type="unfinished">Warning: Không biết change address</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 type="unfinished">The address bạn đã chá»n dành cho change thì không phải part of this wallet. Bất kỳ hay tất cả funds in your wallet có thể được gá»­i đến address này. Bạn chắc chứ?</translation>
- </message>
- <message>
<source>(no label)</source>
- <translation type="unfinished">(không nhãn)</translation>
+ <translation type="unfinished">(không có nhãn)</translation>
</message>
</context>
<context>
<name>SendCoinsEntry</name>
<message>
- <source>Choose previously used address</source>
- <translation type="unfinished">Chá»n má»›i thì address</translation>
- </message>
- <message>
- <source>The Bitcoin address to send the payment to</source>
- <translation type="unfinished">The Bitcoin address để gửi the payment đến</translation>
- </message>
- <message>
<source>Paste address from clipboard</source>
- <translation type="unfinished">Paste address từ clipboard</translation>
- </message>
- <message>
- <source>Remove this entry</source>
- <translation type="unfinished">Xóa bỠentry này</translation>
+ <translation type="unfinished">Dán địa chỉ từ khay nhớ tạm</translation>
</message>
- <message>
- <source>The amount to send in the selected unit</source>
- <translation type="unfinished">Lượng tiá»n để gá»­i trong má»—i Ä‘Æ¡n vị đã chá»n</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 type="unfinished">The fee sẽ được khấu trừ từ số tiá»n Ä‘ang gá»­i. NgÆ°á»i nhận sẽ receive ít bitcoins hÆ¡n bạn gõ vào khoảng trống. Nếu nhiá»u ngÆ°á»i gá»­i được chá»n, fee sẽ được chia Ä‘á»u.</translation>
- </message>
- <message>
- <source>S&amp;ubtract fee from amount</source>
- <translation type="unfinished">S&amp;ubtract fee từ amount</translation>
- </message>
- <message>
- <source>Use available balance</source>
- <translation type="unfinished">Sử dụng số dư sẵn có</translation>
- </message>
- <message>
- <source>Message:</source>
- <translation type="unfinished">Tin nhắn:</translation>
- </message>
- <message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">Äây là má»™t chÆ°a được chứng thá»±c payment request.</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">Äây là má»™t chÆ°a được chứng thá»±c payment request.</translation>
- </message>
- <message>
- <source>Enter a label for this address to add it to the list of used addresses</source>
- <translation type="unfinished">Nhập một label cho cái address này để thêm vào danh sách địa chỉ đã sử dụng</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 type="unfinished">Một tin nhắn được đính kèm với số bitcoin: URI mà sẽ được lưu giữ với transaction dành cho tài liệu tham khảo. Lưu ý: Tin nhắn này sẽ không được gửi thông qua Bitcoin network.</translation>
- </message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">Pay Äến:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">Bản ghi nhớ:</translation>
- </message>
-</context>
+ </context>
<context>
<name>SendConfirmationDialog</name>
<message>
@@ -2234,196 +1033,57 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>SignVerifyMessageDialog</name>
<message>
- <source>Signatures - Sign / Verify a Message</source>
- <translation type="unfinished">Chữ ký - Sign / Verify a Message</translation>
- </message>
- <message>
- <source>&amp;Sign Message</source>
- <translation type="unfinished">&amp;Sign Tin nhắn</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 type="unfinished">Bạn có thể ký/đồng ý với địa chỉ chứng minh bạn có thể receive bitcoins đã gửi đến chúng. Cẩn thận không ký bất cứ không rõ hay random, như các cuộc tấn công lừa đảo có thể cố lừa bạn ký tên vào danh tính của bạn.. Chỉ ký các bản tuyên bố hoàn chỉnh mà bạn đồng ý.</translation>
- </message>
- <message>
- <source>The Bitcoin address to sign the message with</source>
- <translation type="unfinished">The Bitcoin address để ký với tin nhắn</translation>
- </message>
- <message>
- <source>Choose previously used address</source>
- <translation type="unfinished">Chá»n má»›i thì address</translation>
- </message>
- <message>
<source>Paste address from clipboard</source>
- <translation type="unfinished">Paste address từ clipboard</translation>
- </message>
- <message>
- <source>Enter the message you want to sign here</source>
- <translation type="unfinished">Nhập tin nhắn bạn muốn ký tại đây</translation>
- </message>
- <message>
- <source>Copy the current signature to the system clipboard</source>
- <translation type="unfinished">Copy hiện tại signature tới system clipboard</translation>
- </message>
- <message>
- <source>Sign the message to prove you own this Bitcoin address</source>
- <translation type="unfinished">Ký tin nhắn để chứng minh bạn sở hữu Bitcoin address này</translation>
- </message>
- <message>
- <source>Reset all sign message fields</source>
- <translation type="unfinished">Reset tất cả khoảng chữ ký nhắn</translation>
- </message>
- <message>
- <source>&amp;Verify Message</source>
- <translation type="unfinished">&amp;Verify Tin nhắn</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 type="unfinished">Nhập vào address ngÆ°á»i nhận, tin nhắn (chắc rằng bạn copy line breaks, khoảng trống, tabs, etc. chính xác) và signature bên dÆ°á»›i verify tin nhắn. Cẩn thận không Ä‘á»c nhiá»u hÆ¡n từ signature so vá»›i cái được ký trong bản thân tin nhắn, để tránh bị lừa bá»›i man-in-the-middle tấn công. LÆ°u ý rằng Ä‘iá»u này chỉ chứng nhận nhóm những ngÆ°á»i nhân vá»›i address, nó không thể chứng minh bên gá»­i có bất kỳ transaction!</translation>
- </message>
- <message>
- <source>The Bitcoin address the message was signed with</source>
- <translation type="unfinished">The Bitcoin address tin nhắn đã ký với</translation>
- </message>
- <message>
- <source>The signed message to verify</source>
- <translation type="unfinished">Tin nhắn đã được ký để xác nhận</translation>
- </message>
- <message>
- <source>The signature given when the message was signed</source>
- <translation type="unfinished">Chữ ký được cung cấp khi tin nhắn đã được ký</translation>
- </message>
- <message>
- <source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
- <translation type="unfinished">Verify tin nhắn để chắc rằng nó đã được ký với xác định Bitcoin address</translation>
- </message>
- <message>
- <source>Reset all verify message fields</source>
- <translation type="unfinished">Reset tất cả verify khoảng trống nhắn</translation>
- </message>
- <message>
- <source>Click "Sign Message" to generate signature</source>
- <translation type="unfinished">Click "Sign Message" để generate signature</translation>
- </message>
- <message>
- <source>The entered address is invalid.</source>
- <translation type="unfinished">Äã nhập address thì invalid.</translation>
- </message>
- <message>
- <source>Please check the address and try again.</source>
- <translation type="unfinished">Vui lòng kiểm tra address và thử lại.</translation>
- </message>
- <message>
- <source>The entered address does not refer to a key.</source>
- <translation type="unfinished">Äã nhập address không refer to a key.</translation>
- </message>
- <message>
- <source>Wallet unlock was cancelled.</source>
- <translation type="unfinished">Wallet unlock đã được hủy.</translation>
- </message>
- <message>
- <source>No error</source>
- <translation type="unfinished">Không lỗi</translation>
+ <translation type="unfinished">Dán địa chỉ từ khay nhớ tạm</translation>
</message>
+ </context>
+<context>
+ <name>SplashScreen</name>
<message>
- <source>Private key for the entered address is not available.</source>
- <translation type="unfinished">Private key cho address đã nhập thì không có sẵn.</translation>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">nhấn q để tắt máy</translation>
</message>
- </context>
+</context>
<context>
<name>TransactionDesc</name>
<message>
- <source>Date</source>
- <translation type="unfinished">Ngày</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/xác nhận, ở trong bể bộ nhớ - memory pool</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/xác nhận, không ở trong bể bộ nhớ - memory pool</translation>
</message>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>sẽ trưởng thành sau%n khối nữa </numerusform>
</translation>
</message>
- <message>
- <source>Message</source>
- <translation type="unfinished">Tin nhắn</translation>
- </message>
- <message>
- <source>Transaction virtual size</source>
- <translation type="unfinished">Kích cỡ giao dịch ảo</translation>
- </message>
- <message>
- <source> (Certificate was not verified)</source>
- <translation type="unfinished">(Chứng chỉ chưa được thẩm định)</translation>
- </message>
- <message>
- <source>Amount</source>
- <translation type="unfinished">Số lượng</translation>
- </message>
</context>
<context>
<name>TransactionTableModel</name>
<message>
- <source>Date</source>
- <translation type="unfinished">Ngày</translation>
- </message>
- <message>
<source>Label</source>
<translation type="unfinished">Nhãn</translation>
</message>
<message>
- <source>Conflicted</source>
- <translation type="unfinished">Xung Ä‘á»™t</translation>
- </message>
- <message>
<source>(no label)</source>
- <translation type="unfinished">(không nhãn)</translation>
+ <translation type="unfinished">(không có nhãn)</translation>
</message>
</context>
<context>
<name>TransactionView</name>
<message>
- <source>All</source>
- <translation type="unfinished">Tất cả</translation>
- </message>
- <message>
- <source>Today</source>
- <translation type="unfinished">Hôm nay</translation>
- </message>
- <message>
- <source>This week</source>
- <translation type="unfinished">Tuần này</translation>
- </message>
- <message>
- <source>This month</source>
- <translation type="unfinished">Tháng này</translation>
- </message>
- <message>
- <source>Last month</source>
- <translation type="unfinished">Tháng trước</translation>
- </message>
- <message>
- <source>This year</source>
- <translation type="unfinished">Năm nay</translation>
- </message>
- <message>
<source>Other</source>
<translation type="unfinished">Khác</translation>
</message>
<message>
- <source>Enter address, transaction id, or label to search</source>
- <translation type="unfinished">Nhập địa chỉ, số id giao dịch, hoặc nhãn để tìm kiếm</translation>
- </message>
- <message>
- <source>Comma separated file</source>
- <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
- <translation type="unfinished">Tệp tách dấu phẩy</translation>
- </message>
- <message>
- <source>Confirmed</source>
- <translation type="unfinished">Äã xác nhận</translation>
- </message>
- <message>
- <source>Date</source>
- <translation type="unfinished">Ngày</translation>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">Hiển thị trong %1</translation>
</message>
<message>
<source>Label</source>
@@ -2433,80 +1093,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Address</source>
<translation type="unfinished">Äịa chỉ</translation>
</message>
- <message>
- <source>Exporting Failed</source>
- <translation type="unfinished">Xuất Thất Bại</translation>
- </message>
</context>
<context>
- <name>WalletFrame</name>
- <message>
- <source>No wallet has been loaded.
-Go to File &gt; Open Wallet to load a wallet.
-- OR -</source>
- <translation type="unfinished">ChÆ°a có ví nào được tải. Äi tá»›i Tệp&gt; Mở Ví để nạp ví.- HOẶC -</translation>
- </message>
- <message>
- <source>Create a new wallet</source>
- <translation type="unfinished">Tạo một ví mới</translation>
- </message>
- <message>
- <source>Error</source>
- <translation type="unfinished">Lá»—i</translation>
- </message>
- <message>
- <source>Load Transaction Data</source>
- <translation type="unfinished">Tải thông tin giao dịch</translation>
- </message>
- <message>
- <source>Partially Signed Transaction (*.psbt)</source>
- <translation type="unfinished">Giao dịch được đăng ký một phần (*.psbt)</translation>
- </message>
- <message>
- <source>PSBT file must be smaller than 100 MiB</source>
- <translation type="unfinished">Tệp PSBT phải nhỠhơn 100 MiB</translation>
- </message>
- <message>
- <source>Unable to decode PSBT</source>
- <translation type="unfinished">Không thể giải mã PSBT</translation>
- </message>
-</context>
-<context>
- <name>WalletModel</name>
- <message>
- <source>Send Coins</source>
- <translation type="unfinished">Gá»­i Coins</translation>
- </message>
- <message>
- <source>Fee bump error</source>
- <translation type="unfinished">Fee bơm error</translation>
- </message>
- <message>
- <source>Can't draft transaction.</source>
- <translation type="unfinished">Không thể tạo tạm giao dịch.</translation>
- </message>
- <message>
- <source>PSBT copied</source>
- <translation type="unfinished">Äã sao chép PSBT</translation>
- </message>
- <message>
- <source>default wallet</source>
- <translation type="unfinished">ví mặc định</translation>
- </message>
-</context>
-<context>
<name>WalletView</name>
<message>
<source>&amp;Export</source>
<translation type="unfinished">&amp;Xuất</translation>
</message>
- <message>
- <source>Export the data in the current tab to a file</source>
- <translation type="unfinished">Xuất dữ liệu trong thẻ hiện tại ra file</translation>
- </message>
- <message>
- <source>Cancel</source>
- <translation type="unfinished">Hủy</translation>
- </message>
-</context>
+ </context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_yo.ts b/src/qt/locale/bitcoin_yo.ts
index 75a8046ab2..c377bba316 100644
--- a/src/qt/locale/bitcoin_yo.ts
+++ b/src/qt/locale/bitcoin_yo.ts
@@ -2,9 +2,33 @@
<context>
<name>AddressBookPage</name>
<message>
+ <source>Right-click to edit address or label</source>
+ <translation type="unfinished">Te botiini apa otun lati se atunse si adireesi tabi isaami</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation type="unfinished">si adireesi tuntun</translation>
+ </message>
+ <message>
<source>&amp;New</source>
<translation type="unfinished">&amp;ati tuntun</translation>
</message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation type="unfinished">da adiresi tuntun ti o sayan ko si eto sileti </translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation type="unfinished">daako</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation type="unfinished">paade</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">samukuro adiresi ti o sese sayan kuro ninu akojo</translation>
+ </message>
</context>
<context>
<name>QObject</name>
@@ -105,6 +129,24 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_zh-Hans.ts b/src/qt/locale/bitcoin_zh-Hans.ts
index 455cdf958a..0514bc1c17 100644
--- a/src/qt/locale/bitcoin_zh-Hans.ts
+++ b/src/qt/locale/bitcoin_zh-Hans.ts
@@ -2,95 +2,104 @@
<context>
<name>AddressBookPage</name>
<message>
+ <source>Right-click to edit address or label</source>
+ <translation type="unfinished">é¼ æ ‡å³å‡»ç¼–辑地å€æˆ–标签</translation>
+ </message>
+ <message>
<source>Create a new address</source>
- <translation type="unfinished">创建一个新的地å€</translation>
+ <translation type="unfinished">创建新地å€</translation>
</message>
<message>
<source>&amp;New</source>
- <translation type="unfinished">新建</translation>
+ <translation type="unfinished">新建(&amp;N)</translation>
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation type="unfinished">å¤åˆ¶é€‰å®šçš„地å€åˆ°ç³»ç»Ÿå‰ªåˆ‡æ¿</translation>
+ <translation type="unfinished">å¤åˆ¶å½“å‰é€‰ä¸­çš„地å€åˆ°ç³»ç»Ÿå‰ªè´´æ¿</translation>
</message>
<message>
<source>&amp;Copy</source>
- <translation type="unfinished">å¤åˆ¶</translation>
+ <translation type="unfinished">å¤åˆ¶(&amp;C)</translation>
</message>
<message>
<source>C&amp;lose</source>
- <translation type="unfinished">关闭</translation>
+ <translation type="unfinished">关闭(&amp;L)</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation type="unfinished">从列表删除选定的地å€</translation>
+ <translation type="unfinished">从列表中删除选中的地å€</translation>
</message>
<message>
<source>Enter address or label to search</source>
- <translation type="unfinished">输入地å€æˆ–者标签进行æœç´¢</translation>
+ <translation type="unfinished">输入地å€æˆ–标签æ¥æœç´¢</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation type="unfinished">导出当å‰æ•°æ®åˆ°æ–‡ä»¶</translation>
+ <translation type="unfinished">将当å‰æ ‡ç­¾é¡µæ•°æ®å¯¼å‡ºåˆ°æ–‡ä»¶</translation>
</message>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">导出</translation>
+ <translation type="unfinished">导出(&amp;E)</translation>
</message>
<message>
<source>&amp;Delete</source>
- <translation type="unfinished">删除</translation>
+ <translation type="unfinished">删除(&amp;D)</translation>
</message>
<message>
<source>Choose the address to send coins to</source>
- <translation type="unfinished">选择å‘é€æ¯”特å¸åœ°å€</translation>
+ <translation type="unfinished">选择è¦å‘å¸ç»™å“ªäº›åœ°å€</translation>
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation type="unfinished">选择接收比特å¸åœ°å€</translation>
+ <translation type="unfinished">选择è¦ç”¨å“ªäº›åœ°å€æ”¶å¸</translation>
</message>
<message>
<source>C&amp;hoose</source>
- <translation type="unfinished">选择</translation>
+ <translation type="unfinished">选择(&amp;H)</translation>
</message>
<message>
<source>Sending addresses</source>
- <translation type="unfinished">å‘é€åœ°å€</translation>
+ <translation type="unfinished">付款地å€</translation>
</message>
<message>
<source>Receiving addresses</source>
- <translation type="unfinished">接收地å€</translation>
+ <translation type="unfinished">收款地å€</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 type="unfinished">这是你的比特å¸å‘å¸åœ°å€ã€‚å‘é€å‰è¯·ç¡®è®¤å‘é€æ•°é‡å’ŒæŽ¥æ”¶åœ°å€</translation>
+ <translation type="unfinished">您å¯ä»¥ç»™è¿™äº›æ¯”特å¸åœ°å€ä»˜æ¬¾ã€‚在付款之å‰ï¼ŒåŠ¡å¿…è¦æ£€æŸ¥é‡‘é¢å’Œæ”¶æ¬¾åœ°å€æ˜¯å¦æ­£ç¡®ã€‚</translation>
</message>
<message>
<source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
Signing is only possible with addresses of the type 'legacy'.</source>
- <translation type="unfinished">这是你的比特å¸æŽ¥æ”¶åœ°å€ã€‚点击接收选项å¡ä¸­â€œåˆ›å»ºæ–°çš„接收地å€â€æŒ‰é’®æ¥åˆ›å»ºæ–°çš„地å€ã€‚
-ç­¾ååªèƒ½ä½¿ç”¨â€œä¼ ç»Ÿâ€ç±»åž‹çš„地å€ã€‚</translation>
+ <translation type="unfinished">这是您用æ¥æ”¶æ¬¾çš„比特å¸åœ°å€ã€‚使用“接收â€æ ‡ç­¾é¡µä¸­çš„“创建新收款地å€â€æŒ‰é’®æ¥åˆ›å»ºæ–°çš„收款地å€ã€‚
+åªæœ‰â€œä¼ ç»Ÿï¼ˆlegacy)â€ç±»åž‹çš„地å€æ”¯æŒç­¾å。</translation>
</message>
<message>
<source>&amp;Copy Address</source>
- <translation type="unfinished">å¤åˆ¶åœ°å€</translation>
+ <translation type="unfinished">å¤åˆ¶åœ°å€(&amp;C)</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation type="unfinished">å¤åˆ¶æ ‡ç­¾</translation>
+ <translation type="unfinished">å¤åˆ¶æ ‡ç­¾(&amp;L)</translation>
</message>
<message>
<source>&amp;Edit</source>
- <translation type="unfinished">编辑</translation>
+ <translation type="unfinished">编辑(&amp;E)</translation>
</message>
<message>
<source>Export Address List</source>
<translation type="unfinished">导出地å€åˆ—表</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">逗å·åˆ†éš”文件</translation>
+ </message>
+ <message>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
- <translation type="unfinished">ä¿å­˜åœ°å€åˆ—表至%1æ—¶å‘生错误,请é‡è¯•ã€‚</translation>
+ <translation type="unfinished">å°è¯•ä¿å­˜åœ°å€åˆ—表到 %1 æ—¶å‘生错误。请å†è¯•ä¸€æ¬¡ã€‚</translation>
</message>
<message>
<source>Exporting Failed</source>
@@ -128,7 +137,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Repeat new passphrase</source>
- <translation type="unfinished">é‡å¤è¾“入新密ç </translation>
+ <translation type="unfinished">é‡å¤æ–°å¯†ç </translation>
</message>
<message>
<source>Show passphrase</source>
@@ -140,7 +149,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation type="unfinished">æ­¤æ“作需è¦æ‚¨çš„钱包密ç ç”¨æ¥è§£é”钱包。</translation>
+ <translation type="unfinished">这个æ“作需è¦ä½ çš„钱包密ç æ¥è§£é”钱包。</translation>
</message>
<message>
<source>Unlock wallet</source>
@@ -156,11 +165,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</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 type="unfinished">注æ„:如果你加密了钱包åˆå¿˜è®°äº†å¯†ç ï¼Œä½ å°†ä¼šä¸¢å¤±æ‰€æœ‰çš„比特å¸ï¼</translation>
+ <translation type="unfinished">警告: 如果把钱包加密åŽåˆå¿˜è®°å¯†ç ï¼Œä½ å°±ä¼šä»Žæ­¤&lt;b&gt;失去其中所有的比特å¸äº†&lt;/b&gt;ï¼</translation>
</message>
<message>
<source>Are you sure you wish to encrypt your wallet?</source>
- <translation type="unfinished">你确定è¦å°†é’±åŒ…加密å—?</translation>
+ <translation type="unfinished">你确定è¦æŠŠé’±åŒ…加密å—?</translation>
</message>
<message>
<source>Wallet encrypted</source>
@@ -168,160 +177,4450 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Enter the new passphrase for 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 type="unfinished">输入钱包的新密ç ã€‚&lt;br/&gt;密ç ä¸­è¯·ä½¿ç”¨&lt;b&gt;10个或更多éšæœºå­—符&lt;/b&gt;,或&lt;b&gt;8个或更多的å•è¯&lt;/b&gt;。</translation>
+ <translation type="unfinished">为此钱包输入新密ç ã€‚&lt;br/&gt;请使用由&lt;b&gt;å个或更多的éšæœºå­—符&lt;/b&gt;,或者&lt;b&gt;八个或更多å•è¯&lt;/b&gt;组æˆçš„密ç ã€‚</translation>
</message>
<message>
<source>Enter the old passphrase and new passphrase for the wallet.</source>
- <translation type="unfinished">输入钱包的旧密ç å’Œæ–°å¯†ç ã€‚</translation>
+ <translation type="unfinished">输入此钱包的旧密ç å’Œæ–°å¯†ç ã€‚</translation>
+ </message>
+ <message>
+ <source>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>
<source>Wallet to be encrypted</source>
- <translation type="unfinished">需è¦åŠ å¯†çš„钱包</translation>
+ <translation type="unfinished">è¦åŠ å¯†çš„钱包</translation>
</message>
<message>
<source>Your wallet is about to be encrypted. </source>
- <translation type="unfinished">你的钱包将è¦è¢«åŠ å¯†</translation>
+ <translation type="unfinished">您的钱包将è¦è¢«åŠ å¯†ã€‚</translation>
</message>
<message>
<source>Your wallet is now encrypted. </source>
- <translation type="unfinished">你的钱包已被加密</translation>
+ <translation type="unfinished">您的钱包现在已被加密。</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 type="unfinished">é‡è¦: 请用新生æˆçš„ã€å·²åŠ å¯†çš„钱包备份文件å–代你之å‰ç•™çš„钱包文件备份。出于安全方é¢çš„原因,一旦你开始使用新的已加密钱包,旧的未加密钱包文件备份就失效了。</translation>
</message>
<message>
<source>Wallet encryption failed</source>
<translation type="unfinished">钱包加密失败</translation>
</message>
<message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation type="unfinished">因为内部错误导致钱包加密失败。你的钱包还是没加密。</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">æ供的密ç ä¸ä¸€è‡´ã€‚</translation>
+ </message>
+ <message>
<source>Wallet unlock failed</source>
<translation type="unfinished">钱包解é”失败</translation>
</message>
- </context>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation type="unfinished">输入的钱包解é”密ç ä¸æ­£ç¡®ã€‚</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished">钱包密ç ä¿®æ”¹æˆåŠŸã€‚</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished">警告: 大写字æ¯é”定已开å¯ï¼</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation type="unfinished">IP/网络掩ç </translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation type="unfinished">在此之å‰ä¿æŒå°ç¦:</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">设置文件%1å¯èƒ½å·²æŸå或无效。</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">未æ•èŽ·çš„异常</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">å‘生致命错误。%1 å·²ç»æ— æ³•ç»§ç»­å®‰å…¨è¿è¡Œå¹¶å³å°†é€€å‡ºã€‚</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">内部错误</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">å‘生了一个内部错误。%1将会å°è¯•å®‰å…¨åœ°ç»§ç»­è¿è¡Œã€‚关于这个未知的错误我们有以下的æè¿°ä¿¡æ¯ç”¨äºŽå‚考。</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
+ <message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">è¦å°†è®¾ç½®é‡ç½®ä¸ºé»˜è®¤å€¼ï¼Œè¿˜æ˜¯è¦æ”¾å¼ƒæ›´æ”¹å¹¶ä¸­æ­¢ï¼Ÿ</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">出现致命错误。请检查设置文件是å¦å¯å†™ï¼Œæˆ–者å°è¯•å¸¦ -nosettings å‚æ•°è¿è¡Œã€‚</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation type="unfinished">错误:指定的数æ®ç›®å½•â€œ%1â€ä¸å­˜åœ¨ã€‚</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">错误:无法解æžé…置文件: %1</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">错误: %1</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1 还没有安全退出...</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished">未知</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">金é¢</translation>
+ </message>
+ <message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation type="unfinished">请输入一个比特å¸åœ°å€ (例如 %1)</translation>
+ </message>
+ <message>
+ <source>Unroutable</source>
+ <translation type="unfinished">ä¸å¯è·¯ç”±</translation>
+ </message>
+ <message>
+ <source>Internal</source>
+ <translation type="unfinished">内部</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
+ <translation type="unfinished">ä¼ å…¥</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment>
+ <translation type="unfinished">传出</translation>
+ </message>
+ <message>
+ <source>Full Relay</source>
+ <extracomment>Peer connection type that relays all network information.</extracomment>
+ <translation type="unfinished">完整转å‘</translation>
+ </message>
+ <message>
+ <source>Block Relay</source>
+ <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">区å—转å‘</translation>
+ </message>
+ <message>
+ <source>Manual</source>
+ <extracomment>Peer connection type established manually through one of several methods.</extracomment>
+ <translation type="unfinished">手册</translation>
+ </message>
+ <message>
+ <source>Feeler</source>
+ <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">触须</translation>
+ </message>
+ <message>
+ <source>Address Fetch</source>
+ <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment>
+ <translation type="unfinished">地å€å–回</translation>
+ </message>
+ <message>
+ <source>%1 d</source>
+ <translation type="unfinished">%1 天</translation>
+ </message>
+ <message>
+ <source>%1 h</source>
+ <translation type="unfinished">%1 å°æ—¶</translation>
+ </message>
+ <message>
+ <source>%1 m</source>
+ <translation type="unfinished">%1 分钟</translation>
+ </message>
+ <message>
+ <source>%1 s</source>
+ <translation type="unfinished">%1 秒</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished">æ— </translation>
+ </message>
+ <message>
+ <source>N/A</source>
+ <translation type="unfinished">ä¸å¯ç”¨</translation>
+ </message>
+ <message>
+ <source>%1 ms</source>
+ <translation type="unfinished">%1 毫秒</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n秒</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n分钟</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n å°æ—¶</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n 天</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n 周</numerusform>
</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation type="unfinished">%1 和 %2</translation>
+ </message>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nå¹´</numerusform>
</translation>
</message>
+ <message>
+ <source>%1 B</source>
+ <translation type="unfinished">%1 字节</translation>
+ </message>
</context>
<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">无法读å–设置文件</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">无法写入设置文件</translation>
+ </message>
+ <message>
+ <source>The %s developers</source>
+ <translation type="unfinished">%s å¼€å‘者</translation>
+ </message>
+ <message>
+ <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
+ <translation type="unfinished">%sæŸå。请å°è¯•ç”¨bitcoin-wallet钱包工具æ¥å¯¹å…¶è¿›è¡Œæ€¥æ•‘。或者用一个备份进行还原。</translation>
+ </message>
+ <message>
+ <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
+ <translation type="unfinished">å‚æ•° -maxtxfee 被设置得éžå¸¸é«˜ï¼å³ä½¿æ˜¯å•ç¬”交易也å¯èƒ½ä»˜å‡ºå¦‚此之大的手续费。</translation>
+ </message>
+ <message>
+ <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
+ <translation type="unfinished">无法把钱包版本从%ié™çº§åˆ°%i。钱包版本未改å˜ã€‚</translation>
+ </message>
+ <message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation type="unfinished">无法é”定数æ®ç›®å½• %s。%s å¯èƒ½å·²ç»åœ¨è¿è¡Œã€‚</translation>
+ </message>
+ <message>
+ <source>Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
+ <translation type="unfinished">无法在ä¸æ”¯æŒâ€œæ‹†åˆ†å‰çš„密钥池â€ï¼ˆpre split keypool)的情况下把“éžæ‹†åˆ†HD钱包â€ï¼ˆnon HD split wallet)从版本%iå‡çº§åˆ°%i。请使用版本å·%i,或者压根ä¸è¦æŒ‡å®šç‰ˆæœ¬å·ã€‚</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation type="unfinished">在MITå议下分å‘,å‚è§é™„带的 %s 或 %s 文件</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 type="unfinished">è¯»å– %s æ—¶å‘生错误ï¼æ‰€æœ‰çš„密钥都å¯ä»¥æ­£ç¡®è¯»å–,但是交易记录或地å€ç°¿æ•°æ®å¯èƒ½å·²ç»ä¸¢å¤±æˆ–出错。</translation>
+ </message>
+ <message>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">读å–%s出错ï¼äº¤æ˜“æ•°æ®å¯èƒ½ä¸¢å¤±æˆ–有误。é‡æ–°æ‰«æ钱包中。</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
+ <translation type="unfinished">错误: 转储文件格å¼ä¸æ­£ç¡®ã€‚得到是"%s",而预期本应得到的是 "format"。</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source>
+ <translation type="unfinished">错误: 转储文件标识符记录ä¸æ­£ç¡®ã€‚得到的是 "%s",而预期本应得到的是 "%s"。</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
+ <translation type="unfinished">错误: 转储文件版本ä¸è¢«æ”¯æŒã€‚这个版本的 bitcoin-wallet åªæ”¯æŒç‰ˆæœ¬ä¸º 1 的转储文件。得到的转储文件版本å´æ˜¯%s</translation>
+ </message>
+ <message>
+ <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source>
+ <translation type="unfinished">错误: 传统钱包åªæ”¯æŒ "legacy", "p2sh-segwit", å’Œ "bech32" 这三ç§åœ°å€ç±»åž‹</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation type="unfinished">手续费估计失败。而且备用手续费估计(fallbackfee)已被ç¦ç”¨ã€‚请å†ç­‰ä¸€äº›åŒºå—,或者通过-fallbackfeeå‚æ•°å¯ç”¨å¤‡ç”¨æ‰‹ç»­è´¹ä¼°è®¡ã€‚</translation>
+ </message>
+ <message>
+ <source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
+ <translation type="unfinished">文件%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 type="unfinished">å‚æ•° -maxtxfee=&lt;amount&gt;: '%s' 指定了éžæ³•çš„é‡‘é¢ (手续费必须至少达到最å°è½¬å‘费率(minrelay fee) %s 以é¿å…交易å¡ç€å‘ä¸å‡ºåŽ»)</translation>
+ </message>
+ <message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">无效或æŸåçš„peers.dat (%s)。如果你确信这是一个bug,请å馈到%s。作为å˜é€šåŠžæ³•ï¼Œä½ å¯ä»¥æŠŠçŽ°æœ‰æ–‡ä»¶ (%s) 移开(é‡å‘½åã€ç§»åŠ¨æˆ–删除),这样就å¯ä»¥åœ¨ä¸‹æ¬¡å¯åŠ¨æ—¶åˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶äº†ã€‚</translation>
+ </message>
+ <message>
+ <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
+ <translation type="unfinished">æ供多个洋葱路由绑定地å€ã€‚对自动创建的洋葱æœåŠ¡ç”¨%s</translation>
+ </message>
+ <message>
+ <source>No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">没有æ供转储文件。è¦ä½¿ç”¨ createfromdump ,必须æä¾› -dumpfile=&lt;filename&gt;。</translation>
+ </message>
+ <message>
+ <source>No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
+ <translation type="unfinished">没有æ供转储文件。è¦ä½¿ç”¨ dump ,必须æä¾› -dumpfile=&lt;filename&gt;。</translation>
+ </message>
+ <message>
+ <source>No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
+ <translation type="unfinished">没有æ供钱包格å¼ã€‚è¦ä½¿ç”¨ createfromdump ,必须æä¾› -format=&lt;format&gt;</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 type="unfinished">请检查电脑的日期时间设置是å¦æ­£ç¡®ï¼æ—¶é—´é”™è¯¯å¯èƒ½ä¼šå¯¼è‡´ %s è¿è¡Œå¼‚常。</translation>
+ </message>
+ <message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <translation type="unfinished">如果你认为%s对你比较有用的è¯ï¼Œè¯·å¯¹æˆ‘们进行一些自愿贡献。请访问%s网站æ¥èŽ·å–有关这个软件的更多信æ¯ã€‚</translation>
+ </message>
+ <message>
+ <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
+ <translation type="unfinished">修剪被设置得太å°ï¼Œå·²ç»ä½ŽäºŽæœ€å°å€¼%d MiB,请使用更大的数值。</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">修剪模å¼ä¸Ž -reindex-chainstate ä¸å…¼å®¹ã€‚请进行一次完整的 -reindex 。</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 type="unfinished">修剪:上次åŒæ­¥é’±åŒ…çš„ä½ç½®å·²ç»è¶…出(è½åŽäºŽï¼‰çŽ°æœ‰ä¿®å‰ªåŽæ•°æ®çš„范围。你需è¦è¿›è¡Œ-reindex(对于已ç»å¯ç”¨ä¿®å‰ªèŠ‚点,就需è¦é‡æ–°ä¸‹è½½æ•´ä¸ªåŒºå—链)</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
+ <translation type="unfinished">SQLiteDatabase: SQLite钱包schema版本%d未知。åªæ”¯æŒ%d版本</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 type="unfinished">区å—æ•°æ®åº“包å«æœªæ¥çš„交易,这å¯èƒ½æ˜¯ç”±æœ¬æœºé”™è¯¯çš„日期时间引起。若确认本机日期时间正确,请é‡æ–°å»ºç«‹åŒºå—æ•°æ®åº“。</translation>
+ </message>
+ <message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">区å—索引数æ®åº“å«æœ‰åŽ†å²é—留的 'txindex' 。å¯ä»¥è¿è¡Œå®Œæ•´çš„ -reindex æ¥æ¸…ç†è¢«å ç”¨çš„ç£ç›˜ç©ºé—´ï¼›ä¹Ÿå¯ä»¥å¿½ç•¥è¿™ä¸ªé”™è¯¯ã€‚这个错误消æ¯å°†ä¸ä¼šå†æ¬¡æ˜¾ç¤ºã€‚</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation type="unfinished">这笔交易在扣除手续费åŽçš„金é¢å¤ªå°ï¼Œä»¥è‡³äºŽæ— æ³•é€å‡º</translation>
+ </message>
+ <message>
+ <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source>
+ <translation type="unfinished">如果这个钱包之å‰æ²¡æœ‰æ­£ç¡®å…³é—­ï¼Œè€Œä¸”上一次是被新版的Berkeley DB加载过,就会å‘生这个错误。如果是这样,请使用上次加载过这个钱包的那个软件。</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 type="unfinished">这是测试用的预å‘布版本 - 请谨慎使用 - ä¸è¦ç”¨æ¥æŒ–矿,或者在正å¼å•†ç”¨çŽ¯å¢ƒä¸‹ä½¿ç”¨</translation>
+ </message>
+ <message>
+ <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
+ <translation type="unfinished">为了在常规选å¸è¿‡ç¨‹ä¸­ä¼˜å…ˆè€ƒè™‘é¿å…“åªèŠ±å‡ºä¸€ä¸ªåœ°å€ä¸Šçš„一部分å¸â€ï¼ˆpartial spend)这ç§æƒ…况,您最多还需è¦ï¼ˆåœ¨å¸¸è§„手续费之外)付出的交易手续费。</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
+ <translation type="unfinished">找零低于当å‰ç²‰å°˜é˜ˆå€¼æ—¶ä¼šè¢«èˆå¼ƒï¼Œå¹¶è®¡å…¥æ‰‹ç»­è´¹ï¼Œè¿™äº›äº¤æ˜“手续费就是在这ç§æƒ…况下产生的。</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation type="unfinished">ä¸èƒ½ä¼°è®¡æ‰‹ç»­è´¹æ—¶ï¼Œä½ ä¼šä»˜å‡ºè¿™ä¸ªæ‰‹ç»­è´¹é‡‘é¢ã€‚</translation>
+ </message>
+ <message>
+ <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
+ <translation type="unfinished">网络版本字符串的总长度 (%i) 超过最大长度 (%i) 了。请å‡å°‘ uacomment å‚数的数目或长度。</translation>
+ </message>
+ <message>
+ <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
+ <translation type="unfinished">无法é‡æ”¾åŒºå—。你需è¦å…ˆç”¨-reindex-chainstateå‚æ•°æ¥é‡å»ºæ•°æ®åº“。</translation>
+ </message>
+ <message>
+ <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source>
+ <translation type="unfinished">æä¾›äº†æœªçŸ¥çš„é’±åŒ…æ ¼å¼ "%s" 。请使用 "bdb" 或 "sqlite" 中的一ç§ã€‚</translation>
+ </message>
+ <message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">找到了ä¸å—支æŒçš„ chainstate æ•°æ®åº“æ ¼å¼ã€‚请使用 -reindex-chainstate å‚æ•°é‡å¯ã€‚这将会é‡å»º chainstate æ•°æ®åº“。</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">钱包创建æˆåŠŸã€‚æ—§å¼é’±åŒ…已被弃用,未æ¥å°†ä¸å†æ”¯æŒåˆ›å»ºæˆ–打开旧å¼é’±åŒ…。</translation>
+ </message>
+ <message>
+ <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
+ <translation type="unfinished">警告: è½¬å‚¨æ–‡ä»¶çš„é’±åŒ…æ ¼å¼ "%s" ä¸Žå‘½ä»¤è¡ŒæŒ‡å®šçš„æ ¼å¼ "%s" ä¸ç¬¦ã€‚</translation>
+ </message>
+ <message>
+ <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
+ <translation type="unfinished">警告:在已ç»ç¦ç”¨ç§é’¥çš„钱包 {%s} 中ä»ç„¶æ£€æµ‹åˆ°ç§é’¥</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 type="unfinished">警告:我们和其他节点似乎没达æˆå…±è¯†ï¼æ‚¨å¯èƒ½éœ€è¦å‡çº§ï¼Œæˆ–者就是其他节点å¯èƒ½éœ€è¦å‡çº§ã€‚</translation>
+ </message>
+ <message>
+ <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
+ <translation type="unfinished">需è¦éªŒè¯é«˜åº¦åœ¨%d之åŽçš„区å—è§è¯æ•°æ®ã€‚请使用 -reindex é‡æ–°å¯åŠ¨ã€‚</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 type="unfinished">您需è¦ä½¿ç”¨ -reindex é‡æ–°æž„建数æ®åº“以回到未修剪模å¼ã€‚这将é‡æ–°ä¸‹è½½æ•´ä¸ªåŒºå—链</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation type="unfinished">%séžå¸¸é«˜ï¼</translation>
+ </message>
+ <message>
+ <source>-maxmempool must be at least %d MB</source>
+ <translation type="unfinished">-maxmempool 最å°ä¸º%d MB</translation>
+ </message>
+ <message>
+ <source>A fatal internal error occurred, see debug.log for details</source>
+ <translation type="unfinished">å‘生了致命的内部错误,请在debug.log中查看详情</translation>
+ </message>
+ <message>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation type="unfinished">æ— æ³•è§£æž - %s 地å€: '%s'</translation>
+ </message>
+ <message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">在 -dnsseed 被设为 false 时无法将 -forcednsseed 设为 true 。</translation>
+ </message>
+ <message>
+ <source>Cannot set -peerblockfilters without -blockfilterindex.</source>
+ <translation type="unfinished">没有å¯ç”¨-blockfilterindex,就ä¸èƒ½å¯ç”¨-peerblockfilters。</translation>
+ </message>
+ <message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation type="unfinished">ä¸èƒ½å†™å…¥åˆ°æ•°æ®ç›®å½•'%s';请检查文件æƒé™ã€‚</translation>
+ </message>
+ <message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">无法完æˆç”±ä¹‹å‰ç‰ˆæœ¬å¯åŠ¨çš„ -txindex å‡çº§ã€‚请用之å‰çš„版本é‡æ–°å¯åŠ¨ï¼Œæˆ–者进行一次完整的 -reindex 。</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s请求监å¬ç«¯å£ %u。这个端å£è¢«è®¤ä¸ºæ˜¯â€œåçš„â€ï¼Œæ‰€ä»¥ä¸å¤ªå¯èƒ½æœ‰Bitcoin Core节点会连接到它。有关详细信æ¯å’Œå®Œæ•´åˆ—表,请å‚è§ doc/p2p-bad-ports.md 。</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">-reindex-chainstate 与 -blockfilterindex ä¸å…¼å®¹ã€‚请在进行 -reindex-chainstate 时临时ç¦ç”¨ blockfilterindex ,或者改用 -reindex (而ä¸æ˜¯ -reindex-chainstate )æ¥å®Œæ•´åœ°é‡å»ºæ‰€æœ‰ç´¢å¼•ã€‚</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">-reindex-chainstate 与 -coinstatsindex ä¸å…¼å®¹ã€‚请在进行 -reindex-chainstate 时临时ç¦ç”¨ coinstatsindex ,或者改用 -reindex (而ä¸æ˜¯ -reindex-chainstate )æ¥å®Œæ•´åœ°é‡å»ºæ‰€æœ‰ç´¢å¼•ã€‚</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">-reindex-chainstate 与 -txindex ä¸å…¼å®¹ã€‚请在进行 -reindex-chainstate 时临时ç¦ç”¨ txindex ,或者改用 -reindex (而ä¸æ˜¯ -reindex-chainstate )æ¥å®Œæ•´åœ°é‡å»ºæ‰€æœ‰ç´¢å¼•ã€‚</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">å‡å®šæœ‰æ•ˆï¼ˆassume-valid): 上次åŒæ­¥é’±åŒ…时进度越过了现有的区å—æ•°æ®ã€‚你需è¦ç­‰å¾…åŽå°éªŒè¯é“¾ä¸‹è½½æ›´å¤šçš„区å—。</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">在使用地å€ç®¡ç†å™¨(addrman)寻找出站连接时,无法åŒæ—¶æ供特定的连接。</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">加载%s时出错: 编译时未å¯ç”¨å¤–部签å器支æŒï¼Œå´ä»ç„¶è¯•å›¾åŠ è½½å¤–部签å器钱包</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">错误:钱包中的地å€ç°¿æ•°æ®æ— æ³•è¢«è¯†åˆ«ä¸ºå±žäºŽè¿ç§»åŽçš„钱包</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">错误:è¿ç§»è¿‡ç¨‹ä¸­åˆ›å»ºäº†é‡å¤çš„输出æ述符。你的钱包å¯èƒ½å·²æŸå。</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">错误:钱包中的交易%s无法被识别为属于è¿ç§»åŽçš„钱包</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">错误:无法为这个é—留钱包生æˆè¾“出æ述符。请先确定钱包已被解é”</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">无法é‡å‘½å无效的 peers.dat 文件。 请移动或删除它,然åŽé‡è¯•ã€‚</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">互ä¸å…¼å®¹çš„选项:-dnsseed=1 已被显å¼æŒ‡å®šï¼Œä½† -onlynet ç¦æ­¢äº†IPv4/IPv6 连接</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">出站连接被é™åˆ¶ä¸ºä»…使用 Tor (-onlynet=onion),但是到达 Tor 网络的代ç†è¢«æ˜¾å¼ç¦æ­¢ï¼š -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">出站连接被é™åˆ¶ä¸ºä»…使用 Tor (-onlynet=onion),但是未æ供到达 Tor 网络的代ç†ï¼šæ²¡æœ‰æä¾› -proxy=, -onion= 或 -listenonion å‚æ•°</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">找到无法识别的输出æ述符。加载钱包%s
+
+钱包å¯èƒ½ç”±æ–°ç‰ˆè½¯ä»¶åˆ›å»ºï¼Œ
+请å°è¯•è¿è¡Œæœ€æ–°çš„软件版本。
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">ä¸æ”¯æŒçš„类别é™å®šæ—¥å¿—等级 -loglevel=%s。预期å‚æ•° -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s。有效的类别: %s。</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+无法清ç†å¤±è´¥çš„è¿ç§»</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+无法还原钱包备份</translation>
+ </message>
+ <message>
+ <source>Config setting for %s only applied on %s network when in [%s] section.</source>
+ <translation type="unfinished">对 %s çš„é…置设置åªå¯¹ %s 网络生效,如果它ä½äºŽé…置的 [%s] 章节的è¯ã€‚</translation>
+ </message>
+ <message>
+ <source>Copyright (C) %i-%i</source>
+ <translation type="unfinished">版æƒæ‰€æœ‰ (C) %i-%i</translation>
+ </message>
+ <message>
+ <source>Corrupted block database detected</source>
+ <translation type="unfinished">检测到区å—æ•°æ®åº“æŸå</translation>
+ </message>
+ <message>
+ <source>Could not find asmap file %s</source>
+ <translation type="unfinished">找ä¸åˆ°asmap文件%s</translation>
+ </message>
+ <message>
+ <source>Could not parse asmap file %s</source>
+ <translation type="unfinished">无法解æžasmap文件%s</translation>
+ </message>
+ <message>
+ <source>Disk space is too low!</source>
+ <translation type="unfinished">ç£ç›˜ç©ºé—´å¤ªä½Ž!</translation>
+ </message>
+ <message>
+ <source>Do you want to rebuild the block database now?</source>
+ <translation type="unfinished">你想现在就é‡å»ºåŒºå—æ•°æ®åº“å—?</translation>
+ </message>
+ <message>
+ <source>Done loading</source>
+ <translation type="unfinished">加载完æˆ</translation>
+ </message>
+ <message>
+ <source>Dump file %s does not exist.</source>
+ <translation type="unfinished">转储文件 %s ä¸å­˜åœ¨</translation>
+ </message>
+ <message>
+ <source>Error creating %s</source>
+ <translation type="unfinished">创建%s时出错</translation>
+ </message>
+ <message>
+ <source>Error initializing block database</source>
+ <translation type="unfinished">åˆå§‹åŒ–区å—æ•°æ®åº“时出错</translation>
+ </message>
+ <message>
+ <source>Error initializing wallet database environment %s!</source>
+ <translation type="unfinished">åˆå§‹åŒ–钱包数æ®åº“环境错误 %s!</translation>
+ </message>
+ <message>
+ <source>Error loading %s</source>
+ <translation type="unfinished">载入 %s æ—¶å‘生错误</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation type="unfinished">加载 %s 时出错:åªèƒ½åœ¨åˆ›å»ºé’±åŒ…æ—¶ç¦ç”¨ç§é’¥ã€‚</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation type="unfinished">%s 加载出错:钱包æŸå</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation type="unfinished">%s 加载错误:请å‡çº§åˆ°æœ€æ–°ç‰ˆ %s</translation>
+ </message>
+ <message>
+ <source>Error loading block database</source>
+ <translation type="unfinished">加载区å—æ•°æ®åº“时出错</translation>
+ </message>
+ <message>
+ <source>Error opening block database</source>
+ <translation type="unfinished">打开区å—æ•°æ®åº“时出错</translation>
+ </message>
+ <message>
+ <source>Error reading from database, shutting down.</source>
+ <translation type="unfinished">读å–æ•°æ®åº“出错,关闭中。</translation>
+ </message>
+ <message>
+ <source>Error reading next record from wallet database</source>
+ <translation type="unfinished">从钱包数æ®åº“读å–下一æ¡è®°å½•æ—¶å‡ºé”™</translation>
+ </message>
+ <message>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">错误:无法添加仅观察交易至仅观察钱包</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">错误:无法删除仅观察交易</translation>
+ </message>
+ <message>
+ <source>Error: Couldn't create cursor into database</source>
+ <translation type="unfinished">错误: 无法在数æ®åº“中创建指针</translation>
+ </message>
+ <message>
+ <source>Error: Disk space is low for %s</source>
+ <translation type="unfinished">错误: %s 所在的ç£ç›˜ç©ºé—´ä½Žã€‚</translation>
+ </message>
+ <message>
+ <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
+ <translation type="unfinished">错误: 转储文件的校验和ä¸ç¬¦ã€‚计算得到%s,预料中本应该得到%s</translation>
+ </message>
+ <message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">错误:创建新仅观察钱包失败</translation>
+ </message>
+ <message>
+ <source>Error: Got key that was not hex: %s</source>
+ <translation type="unfinished">错误: 得到了ä¸æ˜¯å六进制的键:%s</translation>
+ </message>
+ <message>
+ <source>Error: Got value that was not hex: %s</source>
+ <translation type="unfinished">错误: 得到了ä¸æ˜¯å六进制的数值:%s</translation>
+ </message>
+ <message>
+ <source>Error: Keypool ran out, please call keypoolrefill first</source>
+ <translation type="unfinished">错误: 密钥池已被耗尽,请先调用keypoolrefill</translation>
+ </message>
+ <message>
+ <source>Error: Missing checksum</source>
+ <translation type="unfinished">错误:跳过检查检验和</translation>
+ </message>
+ <message>
+ <source>Error: No %s addresses available.</source>
+ <translation type="unfinished">错误: 没有å¯ç”¨çš„%s地å€ã€‚</translation>
+ </message>
+ <message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">错误:有些仅观察交易无法被删除</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">错误:此钱包已ç»åœ¨ä½¿ç”¨SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">错误:这个钱包已ç»æ˜¯è¾“出æ述符钱包</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">错误:无法开始读å–这个数æ®åº“中的所有记录</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">错误:无法为你的钱包创建备份</translation>
+ </message>
+ <message>
+ <source>Error: Unable to parse version %u as a uint32_t</source>
+ <translation type="unfinished">错误:无法把版本å·%u作为unit32_t解æž</translation>
+ </message>
+ <message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">错误:无法读å–这个数æ®åº“中的所有记录</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">错误:无法移除仅观察地å€ç°¿æ•°æ®</translation>
+ </message>
+ <message>
+ <source>Error: Unable to write record to new wallet</source>
+ <translation type="unfinished">错误: 无法写入记录到新钱包</translation>
+ </message>
+ <message>
+ <source>Failed to listen on any port. Use -listen=0 if you want this.</source>
+ <translation type="unfinished">监å¬ç«¯å£å¤±è´¥ã€‚如果你愿æ„çš„è¯ï¼Œè¯·ä½¿ç”¨ -listen=0 å‚数。</translation>
+ </message>
+ <message>
+ <source>Failed to rescan the wallet during initialization</source>
+ <translation type="unfinished">åˆå§‹åŒ–æ—¶é‡æ‰«æ钱包失败</translation>
+ </message>
+ <message>
+ <source>Failed to verify database</source>
+ <translation type="unfinished">校验数æ®åº“失败</translation>
+ </message>
+ <message>
+ <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source>
+ <translation type="unfinished">手续费率 (%s) 低于最大手续费率设置 (%s)</translation>
+ </message>
+ <message>
+ <source>Ignoring duplicate -wallet %s.</source>
+ <translation type="unfinished">忽略é‡å¤çš„ -wallet %s。</translation>
+ </message>
+ <message>
+ <source>Importing…</source>
+ <translation type="unfinished">导入...</translation>
+ </message>
+ <message>
+ <source>Incorrect or no genesis block found. Wrong datadir for network?</source>
+ <translation type="unfinished">没有找到创世区å—,或者创世区å—ä¸æ­£ç¡®ã€‚是å¦æŠŠæ•°æ®ç›®å½•é”™è¯¯åœ°è®¾æˆäº†å¦ä¸€ä¸ªç½‘络(比如测试网络)的?</translation>
+ </message>
+ <message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation type="unfinished">åˆå§‹åŒ–完整性检查失败。%s å³å°†å…³é—­ã€‚</translation>
+ </message>
+ <message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">找ä¸åˆ°äº¤æ˜“输入项,å¯èƒ½å·²ç»è¢«èŠ±æŽ‰äº†</translation>
+ </message>
+ <message>
+ <source>Insufficient funds</source>
+ <translation type="unfinished">金é¢ä¸è¶³</translation>
+ </message>
+ <message>
+ <source>Invalid -i2psam address or hostname: '%s'</source>
+ <translation type="unfinished">无效的 -i2psam 地å€æˆ–主机å: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid -onion address or hostname: '%s'</source>
+ <translation type="unfinished">无效的 -onion 地å€: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid -proxy address or hostname: '%s'</source>
+ <translation type="unfinished">无效的 -proxy 地å€æˆ–主机å: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid P2P permission: '%s'</source>
+ <translation type="unfinished">无效的 P2P æƒé™ï¼š'%s'</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation type="unfinished">å‚æ•° -%s=&lt;amount&gt;: '%s' 指定了无效的金é¢</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -discardfee=&lt;amount&gt;: '%s'</source>
+ <translation type="unfinished">å‚æ•° -discardfee=&lt;amount&gt;: '%s' 指定了无效的金é¢</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
+ <translation type="unfinished">å‚æ•° -fallbackfee=&lt;amount&gt;: '%s' 指定了无效的金é¢</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
+ <translation type="unfinished">å‚æ•° -paytxfee=&lt;amount&gt; 指定了éžæ³•çš„金é¢: '%s' (必须至少达到 %s)</translation>
+ </message>
+ <message>
+ <source>Invalid netmask specified in -whitelist: '%s'</source>
+ <translation type="unfinished">å‚æ•° -whitelist: '%s' 指定了无效的网络掩ç </translation>
+ </message>
+ <message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">监å¬å¤–部连接失败 (listen函数返回了错误 %s)</translation>
+ </message>
+ <message>
+ <source>Loading P2P addresses…</source>
+ <translation type="unfinished">加载P2P地å€...</translation>
+ </message>
+ <message>
+ <source>Loading banlist…</source>
+ <translation type="unfinished">加载å°ç¦åˆ—表...</translation>
+ </message>
+ <message>
+ <source>Loading block index…</source>
+ <translation type="unfinished">加载区å—索引...</translation>
+ </message>
+ <message>
+ <source>Loading wallet…</source>
+ <translation type="unfinished">加载钱包...</translation>
+ </message>
+ <message>
+ <source>Missing amount</source>
+ <translation type="unfinished">找ä¸åˆ°é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">找ä¸åˆ°ç”¨äºŽä¼°è®¡äº¤æ˜“大å°çš„解答数æ®</translation>
+ </message>
+ <message>
+ <source>Need to specify a port with -whitebind: '%s'</source>
+ <translation type="unfinished">-whitebind: '%s' 需è¦æŒ‡å®šä¸€ä¸ªç«¯å£</translation>
+ </message>
+ <message>
+ <source>No addresses available</source>
+ <translation type="unfinished">没有å¯ç”¨çš„地å€</translation>
+ </message>
+ <message>
+ <source>Not enough file descriptors available.</source>
+ <translation type="unfinished">没有足够的文件æ述符å¯ç”¨ã€‚</translation>
+ </message>
+ <message>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation type="unfinished">ä¸èƒ½æŠŠä¿®å‰ªé…ç½®æˆä¸€ä¸ªè´Ÿæ•°ã€‚</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation type="unfinished">修剪模å¼ä¸Ž -txindex ä¸å…¼å®¹ã€‚</translation>
+ </message>
+ <message>
+ <source>Pruning blockstore…</source>
+ <translation type="unfinished">修剪区å—存储...</translation>
+ </message>
+ <message>
+ <source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
+ <translation type="unfinished">因为系统的é™åˆ¶ï¼Œå°† -maxconnections å‚数从 %d é™åˆ°äº† %d</translation>
+ </message>
+ <message>
+ <source>Replaying blocks…</source>
+ <translation type="unfinished">é‡æ”¾åŒºå—...</translation>
+ </message>
+ <message>
+ <source>Rescanning…</source>
+ <translation type="unfinished">é‡æ‰«æ...</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source>
+ <translation type="unfinished">SQLiteDatabase: 执行校验数æ®åº“语å¥æ—¶å¤±è´¥: %s</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source>
+ <translation type="unfinished">SQLiteDatabase: 预处ç†ç”¨äºŽæ ¡éªŒæ•°æ®åº“的语å¥æ—¶å¤±è´¥: %s</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Failed to read database verification error: %s</source>
+ <translation type="unfinished">SQLiteDatabase: 读å–æ•°æ®åº“失败,校验错误: %s</translation>
+ </message>
+ <message>
+ <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source>
+ <translation type="unfinished">SQLiteDatabase: æ„料之外的应用ID。预期为%u,实际为%u</translation>
+ </message>
+ <message>
+ <source>Section [%s] is not recognized.</source>
+ <translation type="unfinished">无法识别é…置章节 [%s]。</translation>
+ </message>
+ <message>
+ <source>Signing transaction failed</source>
+ <translation type="unfinished">ç­¾å交易失败</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" does not exist</source>
+ <translation type="unfinished">å‚æ•° -walletdir "%s" 指定了ä¸å­˜åœ¨çš„路径</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is a relative path</source>
+ <translation type="unfinished">å‚æ•° -walletdir "%s" 指定了相对路径</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is not a directory</source>
+ <translation type="unfinished">å‚æ•° -walletdir "%s" 指定的路径ä¸æ˜¯ç›®å½•</translation>
+ </message>
+ <message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation type="unfinished">指定的区å—目录"%s"ä¸å­˜åœ¨ã€‚</translation>
+ </message>
+ <message>
+ <source>Starting network threads…</source>
+ <translation type="unfinished">å¯åŠ¨ç½‘络线程...</translation>
+ </message>
+ <message>
+ <source>The source code is available from %s.</source>
+ <translation type="unfinished">å¯ä»¥ä»Ž %s 获å–æºä»£ç ã€‚</translation>
+ </message>
+ <message>
+ <source>The specified config file %s does not exist</source>
+ <translation type="unfinished">指定的é…置文件%sä¸å­˜åœ¨</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation type="unfinished">交易金é¢å¤ªå°ï¼Œä¸è¶³ä»¥æ”¯ä»˜äº¤æ˜“è´¹</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation type="unfinished">钱包会é¿å…让手续费低于最å°è½¬å‘费率(minrelay fee)。</translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation type="unfinished">这是实验性的软件。</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation type="unfinished">这是你æ¯æ¬¡äº¤æ˜“付款时最少è¦ä»˜çš„手续费。</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation type="unfinished">如果å‘é€äº¤æ˜“,这将是你è¦æ”¯ä»˜çš„手续费。</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation type="unfinished">交易金é¢å¤ªå°</translation>
+ </message>
+ <message>
+ <source>Transaction amounts must not be negative</source>
+ <translation type="unfinished">交易金é¢ä¸ä¸å¯ä¸ºè´Ÿæ•°</translation>
+ </message>
+ <message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">交易找零输出项编å·è¶…出范围</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation type="unfinished">此交易在内存池中的存在过长的链æ¡</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation type="unfinished">交易必须包å«è‡³å°‘一个收款人</translation>
+ </message>
+ <message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">交易需è¦ä¸€ä¸ªæ‰¾é›¶åœ°å€ï¼Œä½†æ˜¯æˆ‘们无法生æˆå®ƒã€‚</translation>
+ </message>
+ <message>
+ <source>Transaction too large</source>
+ <translation type="unfinished">交易过大</translation>
+ </message>
+ <message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分é…内存</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer (bind returned error %s)</source>
+ <translation type="unfinished">无法在本机绑定%sç«¯å£ (bind函数返回了错误 %s)</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation type="unfinished">无法在本机绑定 %s 端å£ã€‚%s å¯èƒ½å·²ç»åœ¨è¿è¡Œã€‚</translation>
+ </message>
+ <message>
+ <source>Unable to create the PID file '%s': %s</source>
+ <translation type="unfinished">无法创建PID文件'%s': %s</translation>
+ </message>
+ <message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">无法为外部输入找到UTXO</translation>
+ </message>
+ <message>
+ <source>Unable to generate initial keys</source>
+ <translation type="unfinished">无法生æˆåˆå§‹å¯†é’¥</translation>
+ </message>
+ <message>
+ <source>Unable to generate keys</source>
+ <translation type="unfinished">无法生æˆå¯†é’¥</translation>
+ </message>
+ <message>
+ <source>Unable to open %s for writing</source>
+ <translation type="unfinished">无法打开%s用于写入</translation>
+ </message>
+ <message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">æ— æ³•è§£æž -maxuploadtarget: '%s'</translation>
+ </message>
+ <message>
+ <source>Unable to start HTTP server. See debug log for details.</source>
+ <translation type="unfinished">无法å¯åŠ¨HTTPæœåŠ¡ï¼ŒæŸ¥çœ‹æ—¥å¿—获å–更多信æ¯</translation>
+ </message>
+ <message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">在è¿ç§»å‰æ— æ³•å¸è½½é’±åŒ…</translation>
+ </message>
+ <message>
+ <source>Unknown -blockfilterindex value %s.</source>
+ <translation type="unfinished">未知的 -blockfilterindex 数值 %s。</translation>
+ </message>
+ <message>
+ <source>Unknown address type '%s'</source>
+ <translation type="unfinished">未知的地å€ç±»åž‹ '%s'</translation>
+ </message>
+ <message>
+ <source>Unknown change type '%s'</source>
+ <translation type="unfinished">未知的找零类型 '%s'</translation>
+ </message>
+ <message>
+ <source>Unknown network specified in -onlynet: '%s'</source>
+ <translation type="unfinished">-onlynet 指定的是未知网络: %s</translation>
+ </message>
+ <message>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished">ä¸æ˜Žçš„交易规则已ç»æ¿€æ´» (versionbit %i)</translation>
+ </message>
+ <message>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">ä¸æ”¯æŒçš„全局日志等级 -loglevel=%s 。有效的数值:%s 。</translation>
+ </message>
+ <message>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">ä¸æ”¯æŒçš„日志分类 %s=%s。</translation>
+ </message>
+ <message>
+ <source>User Agent comment (%s) contains unsafe characters.</source>
+ <translation type="unfinished">用户代ç†å¤‡æ³¨(%s)包å«ä¸å®‰å…¨çš„字符。</translation>
+ </message>
+ <message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">验è¯åŒºå—...</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)…</source>
+ <translation type="unfinished">验è¯é’±åŒ…...</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation type="unfinished">钱包需è¦è¢«é‡å†™ï¼šè¯·é‡æ–°å¯åŠ¨%sæ¥å®Œæˆ</translation>
+ </message>
+</context>
+<context>
<name>BitcoinGUI</name>
+ <message>
+ <source>&amp;Overview</source>
+ <translation type="unfinished">概况(&amp;O)</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation type="unfinished">显示钱包概况</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation type="unfinished">交易记录(&amp;T)</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation type="unfinished">æµè§ˆäº¤æ˜“历å²</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation type="unfinished">退出(&amp;X)</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation type="unfinished">退出程åº</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation type="unfinished">关于 %1 (&amp;A)</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation type="unfinished">显示 %1 的相关信æ¯</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation type="unfinished">关于 &amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation type="unfinished">显示 Qt 相关信æ¯</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation type="unfinished">修改%1çš„é…置选项</translation>
+ </message>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">创建一个新的钱包</translation>
+ </message>
+ <message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">最å°åŒ–(&amp;M)</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">钱包:</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">网络活动已ç¦ç”¨ã€‚</translation>
+ </message>
+ <message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation type="unfinished">代ç†æœåŠ¡å™¨å·²&lt;b&gt;å¯ç”¨&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation type="unfinished">å‘一个比特å¸åœ°å€å‘å¸</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation type="unfinished">备份钱包到其他ä½ç½®</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation type="unfinished">修改钱包加密密ç </translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation type="unfinished">å‘é€(&amp;S)</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation type="unfinished">接收(&amp;R)</translation>
+ </message>
+ <message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">选项(&amp;O)</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">加密钱包(&amp;E)</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">把你钱包中的ç§é’¥åŠ å¯†</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">备份钱包(&amp;B)</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">修改密ç (&amp;C)</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">ç­¾å消æ¯(&amp;M)</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">用比特å¸åœ°å€å…³è”çš„ç§é’¥ä¸ºæ¶ˆæ¯ç­¾å,以è¯æ˜Žæ‚¨æ‹¥æœ‰è¿™ä¸ªæ¯”特å¸åœ°å€</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">验è¯æ¶ˆæ¯(&amp;V)</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">校验消æ¯ï¼Œç¡®ä¿è¯¥æ¶ˆæ¯æ˜¯ç”±æŒ‡å®šçš„比特å¸åœ°å€æ‰€æœ‰è€…ç­¾åçš„</translation>
+ </message>
+ <message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">从文件加载PSBT(&amp;L)...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">打开&amp;URI...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">关闭钱包...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">创建钱包...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">关闭所有钱包...</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation type="unfinished">文件(&amp;F)</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation type="unfinished">设置(&amp;S)</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation type="unfinished">帮助(&amp;H)</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation type="unfinished">标签页工具æ </translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">åŒæ­¥åŒºå—头 (%1%)…</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">与网络åŒæ­¥...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">对ç£ç›˜ä¸Šçš„区å—进行索引...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">处ç†ç£ç›˜ä¸Šçš„区å—...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">é‡æ–°ç´¢å¼•ç£ç›˜ä¸Šçš„区å—...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">连接到节点...</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation type="unfinished">请求支付 (生æˆäºŒç»´ç å’Œ bitcoin: URI)</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation type="unfinished">显示用过的付款地å€å’Œæ ‡ç­¾çš„列表</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation type="unfinished">显示用过的收款地å€å’Œæ ‡ç­¾çš„列表</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation type="unfinished">命令行选项(&amp;C)</translation>
+ </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>已处ç†%n个区å—的交易历å²ã€‚</numerusform>
</translation>
</message>
+ <message>
+ <source>%1 behind</source>
+ <translation type="unfinished">è½åŽ %1</translation>
+ </message>
+ <message>
+ <source>Catching up…</source>
+ <translation type="unfinished">正在追上进度...</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation type="unfinished">最新收到的区å—产生于 %1 之å‰ã€‚</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation type="unfinished">在此之åŽçš„交易尚ä¸å¯è§</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">错误</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation type="unfinished">警告</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation type="unfinished">ä¿¡æ¯</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation type="unfinished">已是最新</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction</source>
+ <translation type="unfinished">加载部分签å比特å¸äº¤æ˜“(PSBT)</translation>
+ </message>
+ <message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">从剪贴æ¿åŠ è½½PSBT(&amp;C)...</translation>
+ </message>
+ <message>
+ <source>Load Partially Signed Bitcoin Transaction from clipboard</source>
+ <translation type="unfinished">从剪贴æ¿ä¸­åŠ è½½éƒ¨åˆ†ç­¾å比特å¸äº¤æ˜“(PSBT)</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">节点窗å£</translation>
+ </message>
+ <message>
+ <source>Open node debugging and diagnostic console</source>
+ <translation type="unfinished">打开节点调试与诊断控制å°</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished">付款地å€(&amp;S)</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished">收款地å€(&amp;R)</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI</source>
+ <translation type="unfinished">打开bitcoin:开头的URI</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <translation type="unfinished">打开钱包</translation>
+ </message>
+ <message>
+ <source>Open a wallet</source>
+ <translation type="unfinished">打开一个钱包</translation>
+ </message>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">å¸è½½é’±åŒ…</translation>
+ </message>
+ <message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">从备份文件æ¢å¤é’±åŒ…</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">关闭所有钱包</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation type="unfinished">显示 %1 帮助信æ¯ï¼ŒèŽ·å–å¯ç”¨å‘½ä»¤è¡Œé€‰é¡¹åˆ—表</translation>
+ </message>
+ <message>
+ <source>&amp;Mask values</source>
+ <translation type="unfinished">é®ä½æ•°å€¼(&amp;M)</translation>
+ </message>
+ <message>
+ <source>Mask the values in the Overview tab</source>
+ <translation type="unfinished">在“概况â€æ ‡ç­¾é¡µä¸­ä¸æ˜Žæ–‡æ˜¾ç¤ºæ•°å€¼ã€åªæ˜¾ç¤ºæŽ©ç </translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">默认钱包</translation>
+ </message>
+ <message>
+ <source>No wallets available</source>
+ <translation type="unfinished">没有å¯ç”¨çš„钱包</translation>
+ </message>
+ <message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">钱包数æ®</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">加载钱包备份</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">钱包å称</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">窗å£(&amp;W)</translation>
+ </message>
+ <message>
+ <source>Zoom</source>
+ <translation type="unfinished">缩放</translation>
+ </message>
+ <message>
+ <source>Main Window</source>
+ <translation type="unfinished">主窗å£</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation type="unfinished">%1 客户端</translation>
+ </message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">éšè—(&amp;H)</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">显示(&amp;H)</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n æ¡åˆ°æ¯”特å¸ç½‘络的活动连接</numerusform>
</translation>
</message>
- </context>
+ <message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">点击查看更多æ“作。</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">显示节点标签</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">ç¦ç”¨ç½‘络活动</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">å¯ç”¨ç½‘络活动</translation>
+ </message>
+ <message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">预åŒæ­¥åŒºå—头 (%1%)…</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">错误: %1</translation>
+ </message>
+ <message>
+ <source>Warning: %1</source>
+ <translation type="unfinished">警告: %1</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation type="unfinished">日期: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation type="unfinished">金é¢: %1
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation type="unfinished">钱包: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation type="unfinished">类型: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation type="unfinished">标签: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation type="unfinished">地å€: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation type="unfinished">é€å‡ºäº¤æ˜“</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation type="unfinished">æµå…¥äº¤æ˜“</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD密钥生æˆ&lt;b&gt;å¯ç”¨&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">HD密钥生æˆ&lt;b&gt;ç¦ç”¨&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished">ç§é’¥&lt;b&gt;ç¦ç”¨&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 type="unfinished">钱包已被&lt;b&gt;加密&lt;/b&gt;,当å‰ä¸º&lt;b&gt;解é”&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 type="unfinished">钱包已被&lt;b&gt;加密&lt;/b&gt;,当å‰ä¸º&lt;b&gt;é”定&lt;/b&gt;状æ€</translation>
+ </message>
+ <message>
+ <source>Original message:</source>
+ <translation type="unfinished">原消æ¯:</translation>
+ </message>
+</context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation type="unfinished">金é¢å•ä½ã€‚å•å‡»é€‰æ‹©åˆ«çš„å•ä½ã€‚</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Coin Selection</source>
+ <translation type="unfinished">手动选å¸</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">总é‡:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">字节数:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">金é¢:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">费用:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">粉尘:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">加上交易费用åŽ:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">找零:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation type="unfinished">å…¨(ä¸)选</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation type="unfinished">树状模å¼</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation type="unfinished">列表模å¼</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">金é¢</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation type="unfinished">收款标签</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation type="unfinished">收款地å€</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">日期</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation type="unfinished">确认</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">已确认</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">å¤åˆ¶é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">å¤åˆ¶åœ°å€(&amp;C)</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">å¤åˆ¶æ ‡ç­¾(&amp;L)</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">å¤åˆ¶é‡‘é¢(&amp;A)</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">å¤åˆ¶äº¤æ˜“&amp;ID和输出åºå·</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">é”定未花费(&amp;O)</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">解é”未花费(&amp;U)</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">å¤åˆ¶æ•°ç›®</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">å¤åˆ¶æ‰‹ç»­è´¹</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">å¤åˆ¶å«äº¤æ˜“费的金é¢</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">å¤åˆ¶å­—节数</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">å¤åˆ¶ç²‰å°˜é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">å¤åˆ¶æ‰¾é›¶é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation type="unfinished">(%1å·²é”定)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation type="unfinished">是</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation type="unfinished">å¦</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished">当任何一个收款金é¢å°äºŽç›®å‰çš„粉尘金é¢é˜ˆå€¼æ—¶ï¼Œæ–‡å­—会å˜çº¢è‰²ã€‚</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation type="unfinished">æ¯ä¸ªè¾“å…¥å¯èƒ½æœ‰ +/- %1 èª (satoshi) 的误差。</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(无标签)</translation>
</message>
- </context>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation type="unfinished">æ¥è‡ª %1 的找零 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation type="unfinished">(找零)</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletActivity</name>
+ <message>
+ <source>Create Wallet</source>
+ <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
+ <translation type="unfinished">创建钱包</translation>
+ </message>
+ <message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">创建钱包&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Create wallet failed</source>
+ <translation type="unfinished">创建钱包失败</translation>
+ </message>
+ <message>
+ <source>Create wallet warning</source>
+ <translation type="unfinished">创建钱包警告</translation>
+ </message>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">无法列出签å器</translation>
+ </message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">找到的外部签å器太多</translation>
+ </message>
+</context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">加载钱包</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">加载钱包...</translation>
+ </message>
+</context>
+<context>
+ <name>OpenWalletActivity</name>
+ <message>
+ <source>Open wallet failed</source>
+ <translation type="unfinished">打开钱包失败</translation>
+ </message>
+ <message>
+ <source>Open wallet warning</source>
+ <translation type="unfinished">打开钱包警告</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">默认钱包</translation>
+ </message>
+ <message>
+ <source>Open Wallet</source>
+ <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
+ <translation type="unfinished">打开钱包</translation>
+ </message>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">打开钱包&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…&lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…失败</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…警告</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…消æ¯</translation>
+ </message>
+</context>
+<context>
+ <name>WalletController</name>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">å¸è½½é’±åŒ…</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished">您确定想è¦å…³é—­é’±åŒ…&lt;i&gt;%1&lt;/i&gt;å—?</translation>
+ </message>
+ <message>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished">å¯ç”¨ä¿®å‰ªæ—¶ï¼Œå¦‚果一个钱包被å¸è½½å¤ªä¹…,就必须é‡æ–°åŒæ­¥æ•´æ¡åŒºå—链æ‰èƒ½å†æ¬¡åŠ è½½å®ƒã€‚</translation>
+ </message>
+ <message>
+ <source>Close all wallets</source>
+ <translation type="unfinished">关闭所有钱包</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to close all wallets?</source>
+ <translation type="unfinished">您确定想è¦å…³é—­æ‰€æœ‰é’±åŒ…å—?</translation>
+ </message>
+</context>
+<context>
+ <name>CreateWalletDialog</name>
+ <message>
+ <source>Create Wallet</source>
+ <translation type="unfinished">创建钱包</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <translation type="unfinished">钱包å称</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation type="unfinished">钱包</translation>
+ </message>
+ <message>
+ <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
+ <translation type="unfinished">加密钱包。将会使用您指定的密ç å°†é’±åŒ…加密。</translation>
+ </message>
+ <message>
+ <source>Encrypt Wallet</source>
+ <translation type="unfinished">加密钱包</translation>
+ </message>
+ <message>
+ <source>Advanced Options</source>
+ <translation type="unfinished">进阶设定</translation>
+ </message>
+ <message>
+ <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
+ <translation type="unfinished">ç¦ç”¨æ­¤é’±åŒ…çš„ç§é’¥ã€‚被ç¦ç”¨ç§é’¥çš„钱包将ä¸ä¼šå«æœ‰ä»»ä½•ç§é’¥ï¼Œè€Œä¸”也ä¸èƒ½å«æœ‰HDç§å­æˆ–导入的ç§é’¥ã€‚作为仅观察钱包,这是比较ç†æƒ³çš„。</translation>
+ </message>
+ <message>
+ <source>Disable Private Keys</source>
+ <translation type="unfinished">ç¦ç”¨ç§é’¥</translation>
+ </message>
+ <message>
+ <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
+ <translation type="unfinished">创建一个空白的钱包。空白钱包最åˆä¸å«æœ‰ä»»ä½•ç§é’¥æˆ–脚本。å¯ä»¥ä»¥åŽå†å¯¼å…¥ç§é’¥å’Œåœ°å€ï¼Œæˆ–设置HDç§å­ã€‚</translation>
+ </message>
+ <message>
+ <source>Make Blank Wallet</source>
+ <translation type="unfinished">创建空白钱包</translation>
+ </message>
+ <message>
+ <source>Use descriptors for scriptPubKey management</source>
+ <translation type="unfinished">使用输出æ述符进行scriptPubKey管ç†</translation>
+ </message>
+ <message>
+ <source>Descriptor Wallet</source>
+ <translation type="unfinished">输出æ述符钱包</translation>
+ </message>
+ <message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">使用åƒæ˜¯ç¡¬ä»¶é’±åŒ…这样的外部签å设备。请在钱包å好设置中先é…ç½®å·å¤–部签å器脚本。</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">外部签å器</translation>
+ </message>
+ <message>
+ <source>Create</source>
+ <translation type="unfinished">创建</translation>
+ </message>
+ <message>
+ <source>Compiled without sqlite support (required for descriptor wallets)</source>
+ <translation type="unfinished">编译时未å¯ç”¨SQLite支æŒï¼ˆè¾“出æ述符钱包需è¦å®ƒï¼‰</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">编译时未å¯ç”¨å¤–部签åæ”¯æŒ (外部签å需è¦è¿™ä¸ªåŠŸèƒ½)</translation>
+ </message>
+</context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation type="unfinished">编辑地å€</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation type="unfinished">标签(&amp;L)</translation>
+ </message>
+ <message>
+ <source>The label associated with this address list entry</source>
+ <translation type="unfinished">与此地å€å…³è”的标签</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation type="unfinished">与这个列表项关è”的地å€ã€‚åªæœ‰ä»˜æ¬¾åœ°å€æ‰èƒ½è¢«ä¿®æ”¹ï¼ˆæ”¶æ¬¾åœ°å€ä¸èƒ½è¢«ä¿®æ”¹ï¼‰ã€‚</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation type="unfinished">地å€(&amp;A)</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation type="unfinished">新建付款地å€</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation type="unfinished">编辑收款地å€</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation type="unfinished">编辑付款地å€</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation type="unfinished">è¾“å…¥çš„åœ°å€ %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 type="unfinished">地å€â€œ%1â€å·²ç»å­˜åœ¨ï¼Œå®ƒæ˜¯ä¸€ä¸ªæ”¶æ¬¾åœ°å€ï¼Œæ ‡ç­¾ä¸ºâ€œ%2â€ï¼Œæ‰€ä»¥å®ƒä¸èƒ½ä½œä¸ºä¸€ä¸ªä»˜æ¬¾åœ°å€è¢«æ·»åŠ è¿›æ¥ã€‚</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation type="unfinished">输入的地å€â€œ%1â€å·²ç»å­˜åœ¨äºŽåœ°å€ç°¿ä¸­ï¼Œæ ‡ç­¾ä¸ºâ€œ%2â€ã€‚</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">无法解é”钱包。</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation type="unfinished">生æˆæ–°å¯†é’¥å¤±è´¥ã€‚</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>A new data directory will be created.</source>
+ <translation type="unfinished">一个新的数æ®ç›®å½•å°†è¢«åˆ›å»ºã€‚</translation>
+ </message>
+ <message>
+ <source>name</source>
+ <translation type="unfinished">å称</translation>
+ </message>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation type="unfinished">目录已存在。如果您打算在这里创建一个新目录,请添加 %1。</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation type="unfinished">路径已存在,并且ä¸æ˜¯ä¸€ä¸ªç›®å½•ã€‚</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation type="unfinished">无法在此创建数æ®ç›®å½•ã€‚</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
+ <message>
+ <source>Bitcoin</source>
+ <translation type="unfinished">比特å¸</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>å¯ç”¨ç©ºé—´ %n GB</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(éœ€è¦ %n GB的空间)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(ä¿å­˜å®Œæ•´çš„é“¾éœ€è¦ %n GB)</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation type="unfinished">此目录中至少会ä¿å­˜ %1 GB çš„æ•°æ®ï¼Œå¹¶ä¸”大å°è¿˜ä¼šéšç€æ—¶é—´å¢žé•¿ã€‚</translation>
+ </message>
+ <message>
+ <source>Approximately %1 GB of data will be stored in this directory.</source>
+ <translation type="unfinished">会在此目录中存储约 %1 GB çš„æ•°æ®ã€‚</translation>
+ </message>
<message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(足以æ¢å¤ %n 天之内的备份)</numerusform>
</translation>
</message>
- </context>
+ <message>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation type="unfinished">%1 将会下载并存储比特å¸åŒºå—链。</translation>
+ </message>
+ <message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished">钱包也会被ä¿å­˜åœ¨è¿™ä¸ªç›®å½•ä¸­ã€‚</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation type="unfinished">错误:无法创建指定的数æ®ç›®å½• "%1"</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">错误</translation>
+ </message>
+ <message>
+ <source>Welcome</source>
+ <translation type="unfinished">欢迎</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation type="unfinished">欢迎使用 %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 type="unfinished">由于这是第一次å¯åŠ¨æ­¤ç¨‹åºï¼Œæ‚¨å¯ä»¥é€‰æ‹©%1存储数æ®çš„ä½ç½®</translation>
+ </message>
+ <message>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">将区å—链存储é™åˆ¶åˆ°</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
+ <translation type="unfinished">å–消此设置需è¦é‡æ–°ä¸‹è½½æ•´ä¸ªåŒºå—链。先完整下载整æ¡é“¾å†è¿›è¡Œä¿®å‰ªä¼šæ›´å¿«ã€‚这会ç¦ç”¨ä¸€äº›é«˜çº§åŠŸèƒ½ã€‚</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 type="unfinished">åˆå§‹åŒ–åŒæ­¥è¿‡ç¨‹æ˜¯éžå¸¸åƒåŠ›çš„,åŒæ—¶å¯èƒ½ä¼šæš´éœ²æ‚¨ä¹‹å‰æ²¡æœ‰æ³¨æ„到的电脑硬件问题。你æ¯æ¬¡å¯åŠ¨%1时,它都会从之å‰ä¸­æ–­çš„地方继续下载。</translation>
+ </message>
+ <message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">当你å•å‡»ç¡®è®¤åŽï¼Œ%1 将会从%4在%3年创始时最早的交易开始,下载并处ç†å®Œæ•´çš„ %4 区å—链 (%2 GB)。</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 type="unfinished">如果你选择é™åˆ¶åŒºå—链存储大å°ï¼ˆåŒºå—链è£å‰ªæ¨¡å¼ï¼‰ï¼Œç¨‹åºä¾ç„¶ä¼šä¸‹è½½å¹¶å¤„ç†å…¨éƒ¨åŽ†å²æ•°æ®ï¼Œåªæ˜¯ä¸å¿…须的部分会在使用åŽè¢«åˆ é™¤ï¼Œä»¥å ç”¨æœ€å°‘的存储空间。</translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation type="unfinished">使用默认的数æ®ç›®å½•</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation type="unfinished">使用自定义的数æ®ç›®å½•:</translation>
+ </message>
+</context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation type="unfinished">版本</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished">关于 %1</translation>
+ </message>
+ <message>
+ <source>Command-line options</source>
+ <translation type="unfinished">命令行选项</translation>
+ </message>
+</context>
+<context>
+ <name>ShutdownWindow</name>
+ <message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1正在关闭...</translation>
+ </message>
+ <message>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation type="unfinished">在此窗å£æ¶ˆå¤±å‰ä¸è¦å…³é—­è®¡ç®—机。</translation>
+ </message>
+</context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">窗体</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 type="unfinished">近期交易å¯èƒ½å°šæœªæ˜¾ç¤ºï¼Œå› æ­¤å½“å‰ä½™é¢å¯èƒ½ä¸å‡†ç¡®ã€‚以上信æ¯å°†åœ¨ä¸Žæ¯”特å¸ç½‘络完全åŒæ­¥åŽæ›´æ­£ã€‚详情如下</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 type="unfinished">å°è¯•ä½¿ç”¨å—未å¯è§äº¤æ˜“å½±å“çš„ä½™é¢å°†ä¸è¢«ç½‘络接å—。</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation type="unfinished">剩余区å—æ•°é‡</translation>
+ </message>
+ <message>
+ <source>Unknown…</source>
+ <translation type="unfinished">未知...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">计算中...</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">上一区å—时间</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation type="unfinished">进度</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation type="unfinished">æ¯å°æ—¶è¿›åº¦å¢žåŠ </translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation type="unfinished">预计剩余åŒæ­¥æ—¶é—´</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">éšè—</translation>
+ </message>
+ <message>
+ <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
+ <translation type="unfinished">%1ç›®å‰æ­£åœ¨åŒæ­¥ä¸­ã€‚它会从其他节点下载区å—头和区å—æ•°æ®å¹¶è¿›è¡ŒéªŒè¯ï¼Œç›´åˆ°æŠµè¾¾åŒºå—链尖端。</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">未知。åŒæ­¥åŒºå—头(%1, %2%)...</translation>
+ </message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">未知。预åŒæ­¥åŒºå—头 (%1, %2%)…</translation>
+ </message>
+</context>
+<context>
+ <name>OpenURIDialog</name>
+ <message>
+ <source>Open bitcoin URI</source>
+ <translation type="unfinished">打开比特å¸URI</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment>
+ <translation type="unfinished">从剪贴æ¿ç²˜è´´åœ°å€</translation>
+ </message>
+</context>
+<context>
+ <name>OptionsDialog</name>
+ <message>
+ <source>Options</source>
+ <translation type="unfinished">选项</translation>
+ </message>
+ <message>
+ <source>&amp;Main</source>
+ <translation type="unfinished">主è¦(&amp;M)</translation>
+ </message>
+ <message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation type="unfinished">在登入系统åŽè‡ªåŠ¨å¯åŠ¨ %1</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation type="unfinished">系统登入时å¯åŠ¨ %1 (&amp;S)</translation>
+ </message>
+ <message>
+ <source>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">å¯ç”¨åŒºå—修剪会显著å‡å°å­˜å‚¨äº¤æ˜“对ç£ç›˜ç©ºé—´çš„需求。所有的区å—ä»ç„¶ä¼šè¢«å®Œæ•´æ ¡éªŒã€‚å–消这个设置需è¦é‡æ–°ä¸‹è½½æ•´æ¡åŒºå—链。</translation>
+ </message>
+ <message>
+ <source>Size of &amp;database cache</source>
+ <translation type="unfinished">æ•°æ®åº“缓存大å°(&amp;D)</translation>
+ </message>
+ <message>
+ <source>Number of script &amp;verification threads</source>
+ <translation type="unfinished">脚本验è¯çº¿ç¨‹æ•°(&amp;V)</translation>
+ </message>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation type="unfinished">代ç†æœåŠ¡å™¨ 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 type="unfinished">显示默认的SOCKS5代ç†æ˜¯å¦è¢«ç”¨äºŽåœ¨è¯¥ç±»åž‹çš„网络下连接åŒä¼´ã€‚</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 type="unfinished">窗å£è¢«å…³é—­æ—¶æœ€å°åŒ–程åºè€Œä¸æ˜¯é€€å‡ºã€‚当此选项å¯ç”¨æ—¶ï¼Œåªæœ‰åœ¨èœå•ä¸­é€‰æ‹©â€œé€€å‡ºâ€æ—¶æ‰ä¼šè®©ç¨‹åºé€€å‡ºã€‚</translation>
+ </message>
+ <message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">这个对è¯æ¡†ä¸­çš„设置已被如下命令行选项覆盖:</translation>
+ </message>
+ <message>
+ <source>Open the %1 configuration file from the working directory.</source>
+ <translation type="unfinished">从工作目录下打开é…置文件 %1。</translation>
+ </message>
+ <message>
+ <source>Open Configuration File</source>
+ <translation type="unfinished">打开é…置文件</translation>
+ </message>
+ <message>
+ <source>Reset all client options to default.</source>
+ <translation type="unfinished">æ¢å¤å®¢æˆ·ç«¯çš„缺çœè®¾ç½®</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation type="unfinished">æ¢å¤ç¼ºçœè®¾ç½®(&amp;R)</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation type="unfinished">网络(&amp;N)</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation type="unfinished">将区å—存储修剪至(&amp;B)</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation type="unfinished">警告:还原此设置需è¦é‡æ–°ä¸‹è½½æ•´ä¸ªåŒºå—链。</translation>
+ </message>
+ <message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">æ•°æ®åº“缓存的最大大å°ã€‚加大缓存有助于加快åŒæ­¥ï¼Œä½†å¯¹äºŽå¤§å¤šæ•°ä½¿ç”¨åœºæ™¯æ¥è¯´ï¼Œç»§ç»­åŠ å¤§åŽæ”¶æ•ˆä¼šè¶Šæ¥è¶Šä¸æ˜Žæ˜¾ã€‚é™ä½Žç¼“存大å°å°†ä¼šå‡å°å†…存使用é‡ã€‚内存池中尚未被使用的那部分内存也会被共享用于这里的数æ®åº“缓存。</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">设置脚本验è¯çº¿ç¨‹çš„æ•°é‡ã€‚负值则表示你想è¦ä¿ç•™ç»™ç³»ç»Ÿçš„核心数é‡ã€‚</translation>
+ </message>
+ <message>
+ <source>(0 = auto, &lt;0 = leave that many cores free)</source>
+ <translation type="unfinished">(0 = 自动, &lt;0 = ä¿æŒæŒ‡å®šæ•°é‡çš„CPU核心空闲)</translation>
+ </message>
+ <message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">è¿™å…许作为用户的你或第三方工具通过命令行和JSON-RPC命令行与节点通信。</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">å¯ç”¨R&amp;PCæœåŠ¡å™¨</translation>
+ </message>
+ <message>
+ <source>W&amp;allet</source>
+ <translation type="unfinished">钱包(&amp;A)</translation>
+ </message>
+ <message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">是å¦è¦é»˜è®¤ä»Žé‡‘é¢ä¸­å‡åŽ»æ‰‹ç»­è´¹ã€‚</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">默认从金é¢ä¸­å‡åŽ»äº¤æ˜“手续费(&amp;F)</translation>
+ </message>
+ <message>
+ <source>Expert</source>
+ <translation type="unfinished">专家</translation>
+ </message>
+ <message>
+ <source>Enable coin &amp;control features</source>
+ <translation type="unfinished">å¯ç”¨æ‰‹åŠ¨é€‰å¸åŠŸèƒ½(&amp;C)</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 type="unfinished">如果您ç¦æ­¢åŠ¨ç”¨å°šæœªç¡®è®¤çš„找零资金,则一笔交易的找零资金至少需è¦æœ‰1个确认åŽæ‰èƒ½åŠ¨ç”¨ã€‚è¿™åŒæ—¶ä¹Ÿä¼šå½±å“账户余é¢çš„计算。</translation>
+ </message>
+ <message>
+ <source>&amp;Spend unconfirmed change</source>
+ <translation type="unfinished">动用尚未确认的找零资金(&amp;S)</translation>
+ </message>
+ <message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">å¯ç”¨&amp;PSBT控件</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">是å¦è¦æ˜¾ç¤ºPSBT控件</translation>
+ </message>
+ <message>
+ <source>External Signer (e.g. hardware wallet)</source>
+ <translation type="unfinished">外部签å器(例如硬件钱包)</translation>
+ </message>
+ <message>
+ <source>&amp;External signer script path</source>
+ <translation type="unfinished">外部签å器脚本路径(&amp;E)</translation>
+ </message>
+ <message>
+ <source>Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
+ <translation type="unfinished">指å‘兼容Bitcoin Core的脚本的完整路径 (例如 C:\Downloads\hwi.exe 或者 /Users/you/Downloads/hwi.py )。注æ„: æ¶æ„软件å¯èƒ½ä¼šå·çªƒæ‚¨çš„å¸ï¼</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 type="unfinished">自动在路由器中为比特å¸å®¢æˆ·ç«¯æ‰“开端å£ã€‚åªæœ‰å½“您的路由器开å¯äº† UPnP 选项时此功能æ‰ä¼šæœ‰ç”¨ã€‚</translation>
+ </message>
+ <message>
+ <source>Map port using &amp;UPnP</source>
+ <translation type="unfinished">使用 &amp;UPnP 映射端å£</translation>
+ </message>
+ <message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
+ <translation type="unfinished">自动在路由器中为比特å¸å®¢æˆ·ç«¯æ‰“开端å£ã€‚åªæœ‰å½“æ‚¨çš„è·¯ç”±å™¨æ”¯æŒ NAT-PMP 功能并开å¯å®ƒï¼Œè¿™ä¸ªåŠŸèƒ½æ‰ä¼šæ­£å¸¸å·¥ä½œã€‚外边端å£å¯ä»¥æ˜¯éšæœºçš„。</translation>
+ </message>
+ <message>
+ <source>Map port using NA&amp;T-PMP</source>
+ <translation type="unfinished">使用 NA&amp;T-PMP 映射端å£</translation>
+ </message>
+ <message>
+ <source>Accept connections from outside.</source>
+ <translation type="unfinished">接å—外部连接。</translation>
+ </message>
+ <message>
+ <source>Allow incomin&amp;g connections</source>
+ <translation type="unfinished">å…许传入连接(&amp;G)</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
+ <translation type="unfinished">通过 SOCKS5 代ç†è¿žæŽ¥æ¯”特å¸ç½‘络。</translation>
+ </message>
+ <message>
+ <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
+ <translation type="unfinished">通过 SO&amp;CKS5 代ç†è¿žæŽ¥(默认代ç†):</translation>
+ </message>
+ <message>
+ <source>Proxy &amp;IP:</source>
+ <translation type="unfinished">代ç†æœåŠ¡å™¨ &amp;IP:</translation>
+ </message>
+ <message>
+ <source>&amp;Port:</source>
+ <translation type="unfinished">端å£(&amp;P):</translation>
+ </message>
+ <message>
+ <source>Port of the proxy (e.g. 9050)</source>
+ <translation type="unfinished">代ç†æœåŠ¡å™¨ç«¯å£ï¼ˆä¾‹å¦‚ 9050)</translation>
+ </message>
+ <message>
+ <source>Used for reaching peers via:</source>
+ <translation type="unfinished">在走这些途径连接到节点的时候å¯ç”¨:</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">窗å£(&amp;W)</translation>
+ </message>
+ <message>
+ <source>Show the icon in the system tray.</source>
+ <translation type="unfinished">在通知区域显示图标。</translation>
+ </message>
+ <message>
+ <source>&amp;Show tray icon</source>
+ <translation type="unfinished">显示通知区域图标(&amp;S)</translation>
+ </message>
+ <message>
+ <source>Show only a tray icon after minimizing the window.</source>
+ <translation type="unfinished">最å°åŒ–窗å£åŽä»…显示托盘图标</translation>
+ </message>
+ <message>
+ <source>&amp;Minimize to the tray instead of the taskbar</source>
+ <translation type="unfinished">最å°åŒ–到托盘(&amp;M)</translation>
+ </message>
+ <message>
+ <source>M&amp;inimize on close</source>
+ <translation type="unfinished">å•å‡»å…³é—­æŒ‰é’®æ—¶æœ€å°åŒ–(&amp;I)</translation>
+ </message>
+ <message>
+ <source>&amp;Display</source>
+ <translation type="unfinished">显示(&amp;D)</translation>
+ </message>
+ <message>
+ <source>User Interface &amp;language:</source>
+ <translation type="unfinished">用户界é¢è¯­è¨€(&amp;L):</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation type="unfinished">å¯ä»¥åœ¨è¿™é‡Œè®¾å®šç”¨æˆ·ç•Œé¢çš„语言。这个设定在é‡å¯ %1 åŽæ‰ä¼šç”Ÿæ•ˆã€‚</translation>
+ </message>
+ <message>
+ <source>&amp;Unit to show amounts in:</source>
+ <translation type="unfinished">比特å¸é‡‘é¢å•ä½(&amp;U):</translation>
+ </message>
+ <message>
+ <source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
+ <translation type="unfinished">选择显示åŠå‘é€æ¯”特å¸æ—¶ä½¿ç”¨çš„最å°å•ä½ã€‚</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 type="unfinished">这个第三方网å€ï¼ˆæ¯”如区å—æµè§ˆå™¨ï¼‰ä¼šå‡ºçŽ°åœ¨äº¤æ˜“选项å¡çš„å³é”®èœå•ä¸­ã€‚ 网å€ä¸­çš„%s代表交易哈希。多个网å€éœ€è¦ç”¨ç«–线 | 相互分隔。</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">第三方交易网å€(&amp;T)</translation>
+ </message>
+ <message>
+ <source>Whether to show coin control features or not.</source>
+ <translation type="unfinished">是å¦æ˜¾ç¤ºæ‰‹åŠ¨é€‰å¸åŠŸèƒ½ã€‚</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
+ <translation type="unfinished">连接比特å¸ç½‘络时专门为Tor onionæœåŠ¡ä½¿ç”¨å¦ä¸€ä¸ª SOCKS5 代ç†ã€‚</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
+ <translation type="unfinished">连接Tor onionæœåŠ¡èŠ‚点时使用å¦ä¸€ä¸ªSOCKS&amp;5代ç†ï¼š</translation>
+ </message>
+ <message>
+ <source>Monospaced font in the Overview tab:</source>
+ <translation type="unfinished">在概览标签页的等宽字体:</translation>
+ </message>
+ <message>
+ <source>embedded "%1"</source>
+ <translation type="unfinished">嵌入的 "%1"</translation>
+ </message>
+ <message>
+ <source>closest matching "%1"</source>
+ <translation type="unfinished">与 "%1" 最接近的匹é…</translation>
+ </message>
+ <message>
+ <source>&amp;OK</source>
+ <translation type="unfinished">确定(&amp;O)</translation>
+ </message>
+ <message>
+ <source>&amp;Cancel</source>
+ <translation type="unfinished">å–消(&amp;C)</translation>
+ </message>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">编译时未å¯ç”¨å¤–部签åæ”¯æŒ (外部签å需è¦è¿™ä¸ªåŠŸèƒ½)</translation>
+ </message>
+ <message>
+ <source>default</source>
+ <translation type="unfinished">默认</translation>
+ </message>
+ <message>
+ <source>none</source>
+ <translation type="unfinished">æ— </translation>
+ </message>
+ <message>
+ <source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
+ <translation type="unfinished">确认æ¢å¤é»˜è®¤è®¾ç½®</translation>
+ </message>
+ <message>
+ <source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
+ <translation type="unfinished">需è¦é‡å¯å®¢æˆ·ç«¯æ‰èƒ½ä½¿æ›´æ”¹ç”Ÿæ•ˆã€‚</translation>
+ </message>
+ <message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">当å‰è®¾ç½®å°†ä¼šè¢«å¤‡ä»½åˆ° "%1"。</translation>
+ </message>
+ <message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
+ <translation type="unfinished">客户端å³å°†å…³é—­ï¼Œæ‚¨æƒ³ç»§ç»­å—?</translation>
+ </message>
+ <message>
+ <source>Configuration options</source>
+ <extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
+ <translation type="unfinished">é…置选项</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>
+ <extracomment>Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</extracomment>
+ <translation type="unfinished">é…置文件å¯ä»¥ç”¨æ¥è®¾ç½®é«˜çº§é€‰é¡¹ã€‚é…置文件会覆盖设置界é¢çª—å£ä¸­çš„选项。此外,命令行会覆盖é…置文件指定的选项。</translation>
+ </message>
+ <message>
+ <source>Continue</source>
+ <translation type="unfinished">继续</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">å–消</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">错误</translation>
+ </message>
+ <message>
+ <source>The configuration file could not be opened.</source>
+ <translation type="unfinished">无法打开é…置文件。</translation>
+ </message>
+ <message>
+ <source>This change would require a client restart.</source>
+ <translation type="unfinished">此更改需è¦é‡å¯å®¢æˆ·ç«¯ã€‚</translation>
+ </message>
+ <message>
+ <source>The supplied proxy address is invalid.</source>
+ <translation type="unfinished">æ供的代ç†æœåŠ¡å™¨åœ°å€æ— æ•ˆã€‚</translation>
+ </message>
+</context>
+<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">无法读å–设置 "%1",%2。</translation>
+ </message>
+</context>
+<context>
+ <name>OverviewPage</name>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished">窗体</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 type="unfinished">现在显示的消æ¯å¯èƒ½æ˜¯è¿‡æœŸçš„。在连接上比特å¸ç½‘络节点åŽï¼Œæ‚¨çš„钱包将自动与网络åŒæ­¥ï¼Œä½†æ˜¯è¿™ä¸ªè¿‡ç¨‹è¿˜æ²¡æœ‰å®Œæˆã€‚</translation>
+ </message>
+ <message>
+ <source>Watch-only:</source>
+ <translation type="unfinished">仅观察:</translation>
+ </message>
+ <message>
+ <source>Available:</source>
+ <translation type="unfinished">å¯ä½¿ç”¨çš„ä½™é¢:</translation>
+ </message>
+ <message>
+ <source>Your current spendable balance</source>
+ <translation type="unfinished">您当å‰å¯ä½¿ç”¨çš„ä½™é¢</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation type="unfinished">等待中的余é¢:</translation>
+ </message>
+ <message>
+ <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
+ <translation type="unfinished">尚未确认的交易总é¢ï¼Œæœªè®¡å…¥å½“å‰ä½™é¢</translation>
+ </message>
+ <message>
+ <source>Immature:</source>
+ <translation type="unfinished">未æˆç†Ÿçš„:</translation>
+ </message>
+ <message>
+ <source>Mined balance that has not yet matured</source>
+ <translation type="unfinished">尚未æˆç†Ÿçš„挖矿收入余é¢</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation type="unfinished">ä½™é¢</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation type="unfinished">总é¢:</translation>
+ </message>
+ <message>
+ <source>Your current total balance</source>
+ <translation type="unfinished">您当å‰çš„总余é¢</translation>
+ </message>
+ <message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation type="unfinished">您当å‰åœ¨ä»…观察观察地å€ä¸­çš„ä½™é¢</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation type="unfinished">å¯åŠ¨ç”¨:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation type="unfinished">最近交易</translation>
+ </message>
+ <message>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation type="unfinished">仅观察地å€çš„未确认交易</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation type="unfinished">仅观察地å€ä¸­å°šæœªæˆç†Ÿçš„挖矿收入余é¢:</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation type="unfinished">仅观察地å€ä¸­çš„当å‰æ€»ä½™é¢</translation>
+ </message>
+ <message>
+ <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
+ <translation type="unfinished">“概况â€æ ‡ç­¾é¡µå·²å¯ç”¨éšç§æ¨¡å¼ã€‚è¦æ˜Žæ–‡æ˜¾ç¤ºæ•°å€¼ï¼Œè¯·åœ¨è®¾ç½®ä¸­å–消勾选“ä¸æ˜Žæ–‡æ˜¾ç¤ºæ•°å€¼â€ã€‚</translation>
+ </message>
+</context>
+<context>
+ <name>PSBTOperationsDialog</name>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished">会è¯</translation>
+ </message>
+ <message>
+ <source>Sign Tx</source>
+ <translation type="unfinished">ç­¾å交易</translation>
+ </message>
+ <message>
+ <source>Broadcast Tx</source>
+ <translation type="unfinished">广播交易</translation>
+ </message>
+ <message>
+ <source>Copy to Clipboard</source>
+ <translation type="unfinished">å¤åˆ¶åˆ°å‰ªè´´æ¿</translation>
+ </message>
+ <message>
+ <source>Save…</source>
+ <translation type="unfinished">ä¿å­˜...</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished">关闭</translation>
+ </message>
+ <message>
+ <source>Failed to load transaction: %1</source>
+ <translation type="unfinished">加载交易失败: %1</translation>
+ </message>
+ <message>
+ <source>Failed to sign transaction: %1</source>
+ <translation type="unfinished">ç­¾å交易失败: %1</translation>
+ </message>
+ <message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">钱包已é”定,无法签å交易输入项。</translation>
+ </message>
+ <message>
+ <source>Could not sign any more inputs.</source>
+ <translation type="unfinished">没有交易输入项å¯ä¾›ç­¾å了。</translation>
+ </message>
+ <message>
+ <source>Signed %1 inputs, but more signatures are still required.</source>
+ <translation type="unfinished">已签å %1 个交易输入项,但是ä»ç„¶è¿˜æœ‰ä½™ä¸‹çš„项目需è¦ç­¾å。</translation>
+ </message>
+ <message>
+ <source>Signed transaction successfully. Transaction is ready to broadcast.</source>
+ <translation type="unfinished">æˆåŠŸç­¾å交易。交易已ç»å¯ä»¥å¹¿æ’­ã€‚</translation>
+ </message>
+ <message>
+ <source>Unknown error processing transaction.</source>
+ <translation type="unfinished">处ç†äº¤æ˜“æ—¶é‡åˆ°æœªçŸ¥é”™è¯¯ã€‚</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast successfully! Transaction ID: %1</source>
+ <translation type="unfinished">å·²æˆåŠŸå¹¿æ’­äº¤æ˜“ï¼äº¤æ˜“ID: %1</translation>
+ </message>
+ <message>
+ <source>Transaction broadcast failed: %1</source>
+ <translation type="unfinished">交易广播失败: %1</translation>
+ </message>
+ <message>
+ <source>PSBT copied to clipboard.</source>
+ <translation type="unfinished">å·²å¤åˆ¶PSBT到剪贴æ¿</translation>
+ </message>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">ä¿å­˜äº¤æ˜“æ•°æ®</translation>
+ </message>
+ <message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">部分签å交易(二进制)</translation>
+ </message>
+ <message>
+ <source>PSBT saved to disk.</source>
+ <translation type="unfinished">PSBTå·²ä¿å­˜åˆ°ç¡¬ç›˜</translation>
+ </message>
+ <message>
+ <source> * Sends %1 to %2</source>
+ <translation type="unfinished"> * å‘é€ %1 至 %2</translation>
+ </message>
+ <message>
+ <source>Unable to calculate transaction fee or total transaction amount.</source>
+ <translation type="unfinished">无法计算交易费用或总交易金é¢ã€‚</translation>
+ </message>
+ <message>
+ <source>Pays transaction fee: </source>
+ <translation type="unfinished">支付交易费用:</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">总é¢</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">或</translation>
+ </message>
+ <message>
+ <source>Transaction has %1 unsigned inputs.</source>
+ <translation type="unfinished">交易中å«æœ‰%1个未签å输入项。</translation>
+ </message>
+ <message>
+ <source>Transaction is missing some information about inputs.</source>
+ <translation type="unfinished">交易中有输入项缺失æŸäº›ä¿¡æ¯ã€‚</translation>
+ </message>
+ <message>
+ <source>Transaction still needs signature(s).</source>
+ <translation type="unfinished">交易ä»ç„¶éœ€è¦ç­¾å。</translation>
+ </message>
+ <message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(但没有加载钱包。)</translation>
+ </message>
+ <message>
+ <source>(But this wallet cannot sign transactions.)</source>
+ <translation type="unfinished">(但这个钱包ä¸èƒ½ç­¾å交易)</translation>
+ </message>
+ <message>
+ <source>(But this wallet does not have the right keys.)</source>
+ <translation type="unfinished">(但这个钱包没有正确的密钥)</translation>
+ </message>
+ <message>
+ <source>Transaction is fully signed and ready for broadcast.</source>
+ <translation type="unfinished">交易已ç»å®Œå…¨ç­¾å,å¯ä»¥å¹¿æ’­ã€‚</translation>
+ </message>
+ <message>
+ <source>Transaction status is unknown.</source>
+ <translation type="unfinished">交易状æ€æœªçŸ¥ã€‚</translation>
+ </message>
+</context>
+<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation type="unfinished">支付请求出错</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation type="unfinished">无法å¯åŠ¨ bitcoin: å议的“一键支付â€å¤„ç†ç¨‹åº</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation type="unfinished">URI 处ç†</translation>
+ </message>
+ <message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation type="unfinished">‘bitcoin://’ä¸æ˜¯åˆæ³•çš„URI。请改用'bitcoin:'。</translation>
+ </message>
+ <message>
+ <source>Cannot process payment request because BIP70 is not supported.
+Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.
+If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
+ <translation type="unfinished">因为ä¸æ”¯æŒBIP70,无法处ç†ä»˜æ¬¾è¯·æ±‚。
+由于BIP70具有广泛的安全缺陷,无论哪个商家指引è¦æ±‚您更æ¢é’±åŒ…,我们都强烈建议您ä¸è¦å¬ä¿¡ã€‚
+如果您看到了这个错误,您应该è¦æ±‚商家æ供兼容BIP21çš„URI。</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation type="unfinished">æ— æ³•è§£æž URI 地å€ï¼å¯èƒ½æ˜¯å› ä¸ºæ¯”特å¸åœ°å€æ— æ•ˆï¼Œæˆ–是 URI å‚æ•°æ ¼å¼é”™è¯¯ã€‚</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation type="unfinished">支付请求文件处ç†</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
+ <source>User Agent</source>
+ <extracomment>Title of Peers Table column which contains the peer's User Agent string.</extracomment>
+ <translation type="unfinished">用户代ç†</translation>
+ </message>
+ <message>
+ <source>Peer</source>
+ <extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
+ <translation type="unfinished">节点</translation>
+ </message>
+ <message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">连接时间</translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
+ <translation type="unfinished">æ–¹å‘</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment>
+ <translation type="unfinished">å·²å‘é€</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <extracomment>Title of Peers Table column which indicates the total amount of network information we have received from the peer.</extracomment>
+ <translation type="unfinished">已接收</translation>
+ </message>
+ <message>
<source>Address</source>
<extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
<translation type="unfinished">地å€</translation>
</message>
- </context>
+ <message>
+ <source>Type</source>
+ <extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment>
+ <translation type="unfinished">类型</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment>
+ <translation type="unfinished">网络</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <extracomment>An Inbound Connection from a Peer.</extracomment>
+ <translation type="unfinished">ä¼ å…¥</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <extracomment>An Outbound Connection to a Peer.</extracomment>
+ <translation type="unfinished">传出</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">ä¿å­˜å›¾åƒ(&amp;S)...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation type="unfinished">å¤åˆ¶å›¾åƒ(&amp;C)</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation type="unfinished">URI 太长,请试ç€ç²¾ç®€æ ‡ç­¾æˆ–消æ¯æ–‡æœ¬ã€‚</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation type="unfinished">把 URI ç¼–ç æˆäºŒç»´ç æ—¶å‘生错误。</translation>
+ </message>
+ <message>
+ <source>QR code support not available.</source>
+ <translation type="unfinished">ä¸æ”¯æŒäºŒç»´ç ã€‚</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation type="unfinished">ä¿å­˜äºŒç»´ç </translation>
+ </message>
+ <message>
+ <source>PNG Image</source>
+ <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment>
+ <translation type="unfinished">PNG图åƒ</translation>
+ </message>
+</context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>N/A</source>
+ <translation type="unfinished">ä¸å¯ç”¨</translation>
+ </message>
+ <message>
+ <source>Client version</source>
+ <translation type="unfinished">客户端版本</translation>
+ </message>
+ <message>
+ <source>&amp;Information</source>
+ <translation type="unfinished">ä¿¡æ¯(&amp;I)</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation type="unfinished">常规</translation>
+ </message>
+ <message>
+ <source>Datadir</source>
+ <translation type="unfinished">æ•°æ®ç›®å½•</translation>
+ </message>
+ <message>
+ <source>To specify a non-default location of the data directory use the '%1' option.</source>
+ <translation type="unfinished">如果ä¸æƒ³ç”¨é»˜è®¤çš„æ•°æ®ç›®å½•ä½ç½®ï¼Œè¯·ç”¨ '%1' 这个选项æ¥æŒ‡å®šæ–°çš„ä½ç½®ã€‚</translation>
+ </message>
+ <message>
+ <source>Blocksdir</source>
+ <translation type="unfinished">区å—存储目录</translation>
+ </message>
+ <message>
+ <source>To specify a non-default location of the blocks directory use the '%1' option.</source>
+ <translation type="unfinished">如果è¦è‡ªå®šä¹‰åŒºå—存储目录的ä½ç½®ï¼Œè¯·ç”¨ '%1' 这个选项æ¥æŒ‡å®šæ–°çš„ä½ç½®ã€‚</translation>
+ </message>
+ <message>
+ <source>Startup time</source>
+ <translation type="unfinished">å¯åŠ¨æ—¶é—´</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished">网络</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished">å称</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation type="unfinished">连接数</translation>
+ </message>
+ <message>
+ <source>Block chain</source>
+ <translation type="unfinished">区å—链</translation>
+ </message>
+ <message>
+ <source>Memory Pool</source>
+ <translation type="unfinished">内存池</translation>
+ </message>
+ <message>
+ <source>Current number of transactions</source>
+ <translation type="unfinished">当å‰äº¤æ˜“æ•°é‡</translation>
+ </message>
+ <message>
+ <source>Memory usage</source>
+ <translation type="unfinished">内存使用</translation>
+ </message>
+ <message>
+ <source>Wallet: </source>
+ <translation type="unfinished">钱包:</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation type="unfinished">(æ— )</translation>
+ </message>
+ <message>
+ <source>&amp;Reset</source>
+ <translation type="unfinished">é‡ç½®(&amp;R)</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation type="unfinished">已接收</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation type="unfinished">å·²å‘é€</translation>
+ </message>
+ <message>
+ <source>&amp;Peers</source>
+ <translation type="unfinished">节点(&amp;P)</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation type="unfinished">å·²å°ç¦èŠ‚点</translation>
+ </message>
+ <message>
+ <source>Select a peer to view detailed information.</source>
+ <translation type="unfinished">选择节点查看详细信æ¯ã€‚</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation type="unfinished">版本</translation>
+ </message>
+ <message>
+ <source>Starting Block</source>
+ <translation type="unfinished">起步区å—</translation>
+ </message>
+ <message>
+ <source>Synced Headers</source>
+ <translation type="unfinished">å·²åŒæ­¥åŒºå—头</translation>
+ </message>
+ <message>
+ <source>Synced Blocks</source>
+ <translation type="unfinished">å·²åŒæ­¥åŒºå—</translation>
+ </message>
+ <message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">最近交易</translation>
+ </message>
+ <message>
+ <source>The mapped Autonomous System used for diversifying peer selection.</source>
+ <translation type="unfinished">映射到的自治系统,被用æ¥å¤šæ ·åŒ–选择节点</translation>
+ </message>
+ <message>
+ <source>Mapped AS</source>
+ <translation type="unfinished">映射到的AS</translation>
+ </message>
+ <message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">是å¦æŠŠåœ°å€è½¬å‘给这个节点。</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">地å€è½¬å‘</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">从这个节点接收并处ç†è¿‡çš„地å€æ€»æ•°ï¼ˆé™¤åŽ»å› é¢‘次é™åˆ¶è€Œä¸¢å¼ƒçš„那些地å€ï¼‰ã€‚</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">从这个节点接收åŽåˆå› é¢‘次é™åˆ¶è€Œä¸¢å¼ƒï¼ˆæœªè¢«å¤„ç†ï¼‰çš„地å€æ€»æ•°ã€‚</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">已处ç†åœ°å€</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">被频率é™åˆ¶ä¸¢å¼ƒçš„地å€</translation>
+ </message>
+ <message>
+ <source>User Agent</source>
+ <translation type="unfinished">用户代ç†</translation>
+ </message>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">节点窗å£</translation>
+ </message>
+ <message>
+ <source>Current block height</source>
+ <translation type="unfinished">当å‰åŒºå—高度</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 type="unfinished">打开当å‰æ•°æ®ç›®å½•ä¸­çš„ %1 调试日志文件。日志文件大的è¯å¯èƒ½è¦ç­‰ä¸Šå‡ ç§’钟。</translation>
+ </message>
+ <message>
+ <source>Decrease font size</source>
+ <translation type="unfinished">缩å°å­—体大å°</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation type="unfinished">放大字体大å°</translation>
+ </message>
+ <message>
+ <source>Permissions</source>
+ <translation type="unfinished">æƒé™</translation>
+ </message>
+ <message>
+ <source>The direction and type of peer connection: %1</source>
+ <translation type="unfinished">节点连接的方å‘和类型: %1</translation>
+ </message>
+ <message>
+ <source>Direction/Type</source>
+ <translation type="unfinished">æ–¹å‘/类型</translation>
+ </message>
+ <message>
+ <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
+ <translation type="unfinished">这个节点是通过这ç§ç½‘络å议连接到的: IPv4, IPv6, Onion, I2P, 或 CJDNS.</translation>
+ </message>
+ <message>
+ <source>Services</source>
+ <translation type="unfinished">æœåŠ¡</translation>
+ </message>
+ <message>
+ <source>Whether the peer requested us to relay transactions.</source>
+ <translation type="unfinished">这个节点是å¦è¦æ±‚我们转å‘交易。</translation>
+ </message>
+ <message>
+ <source>Wants Tx Relay</source>
+ <translation type="unfinished">è¦æ±‚交易转å‘</translation>
+ </message>
+ <message>
+ <source>High bandwidth BIP152 compact block relay: %1</source>
+ <translation type="unfinished">高带宽BIP152密实区å—转å‘: %1</translation>
+ </message>
+ <message>
+ <source>High Bandwidth</source>
+ <translation type="unfinished">高带宽</translation>
+ </message>
+ <message>
+ <source>Connection Time</source>
+ <translation type="unfinished">连接时间</translation>
+ </message>
+ <message>
+ <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
+ <translation type="unfinished">自从这个节点上一次å‘æ¥å¯é€šè¿‡åˆå§‹æœ‰æ•ˆæ€§æ£€æŸ¥çš„新区å—以æ¥åˆ°çŽ°åœ¨ç»è¿‡çš„时间</translation>
+ </message>
+ <message>
+ <source>Last Block</source>
+ <translation type="unfinished">上一个区å—</translation>
+ </message>
+ <message>
+ <source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
+ <extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment>
+ <translation type="unfinished">自从这个节点上一次å‘æ¥è¢«æˆ‘们的内存池接å—的新交易到现在ç»è¿‡çš„时间</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation type="unfinished">上次å‘é€</translation>
+ </message>
+ <message>
+ <source>Last Receive</source>
+ <translation type="unfinished">上次接收</translation>
+ </message>
+ <message>
+ <source>Ping Time</source>
+ <translation type="unfinished">Ping 延时</translation>
+ </message>
+ <message>
+ <source>The duration of a currently outstanding ping.</source>
+ <translation type="unfinished">ç›®å‰è¿™ä¸€æ¬¡ ping å·²ç»è¿‡åŽ»çš„时间。</translation>
+ </message>
+ <message>
+ <source>Ping Wait</source>
+ <translation type="unfinished">Ping 等待</translation>
+ </message>
+ <message>
+ <source>Min Ping</source>
+ <translation type="unfinished">æœ€å° Ping 值</translation>
+ </message>
+ <message>
+ <source>Time Offset</source>
+ <translation type="unfinished">时间å移</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation type="unfinished">上一区å—时间</translation>
+ </message>
+ <message>
+ <source>&amp;Open</source>
+ <translation type="unfinished">打开(&amp;O)</translation>
+ </message>
+ <message>
+ <source>&amp;Console</source>
+ <translation type="unfinished">控制å°(&amp;C)</translation>
+ </message>
+ <message>
+ <source>&amp;Network Traffic</source>
+ <translation type="unfinished">网络æµé‡(&amp;N)</translation>
+ </message>
+ <message>
+ <source>Totals</source>
+ <translation type="unfinished">总数</translation>
+ </message>
+ <message>
+ <source>Debug log file</source>
+ <translation type="unfinished">调试日志文件</translation>
+ </message>
+ <message>
+ <source>Clear console</source>
+ <translation type="unfinished">清空控制å°</translation>
+ </message>
+ <message>
+ <source>In:</source>
+ <translation type="unfinished">ä¼ å…¥:</translation>
+ </message>
+ <message>
+ <source>Out:</source>
+ <translation type="unfinished">传出:</translation>
+ </message>
+ <message>
+ <source>Inbound: initiated by peer</source>
+ <extracomment>Explanatory text for an inbound peer connection.</extracomment>
+ <translation type="unfinished">入站: 由对端å‘èµ·</translation>
+ </message>
+ <message>
+ <source>Outbound Full Relay: default</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment>
+ <translation type="unfinished">出站完整转å‘: 默认</translation>
+ </message>
+ <message>
+ <source>Outbound Block Relay: does not relay transactions or addresses</source>
+ <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment>
+ <translation type="unfinished">出站区å—转å‘: ä¸è½¬å‘交易和地å€</translation>
+ </message>
+ <message>
+ <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
+ <extracomment>Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</extracomment>
+ <translation type="unfinished">出站手动: 加入使用RPC %1 或 %2/%3 é…置选项</translation>
+ </message>
+ <message>
+ <source>Outbound Feeler: short-lived, for testing addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment>
+ <translation type="unfinished">出站触须: 短暂,用于测试地å€</translation>
+ </message>
+ <message>
+ <source>Outbound Address Fetch: short-lived, for soliciting addresses</source>
+ <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment>
+ <translation type="unfinished">出站地å€å–回: 短暂,用于请求å–回地å€</translation>
+ </message>
+ <message>
+ <source>we selected the peer for high bandwidth relay</source>
+ <translation type="unfinished">我们选择了用于高带宽转å‘的节点</translation>
+ </message>
+ <message>
+ <source>the peer selected us for high bandwidth relay</source>
+ <translation type="unfinished">对端选择了我们用于高带宽转å‘</translation>
+ </message>
+ <message>
+ <source>no high bandwidth relay selected</source>
+ <translation type="unfinished">未选择高带宽转å‘</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">å¤åˆ¶åœ°å€(&amp;C)</translation>
+ </message>
+ <message>
+ <source>&amp;Disconnect</source>
+ <translation type="unfinished">æ–­å¼€(&amp;D)</translation>
+ </message>
+ <message>
+ <source>1 &amp;hour</source>
+ <translation type="unfinished">1 å°æ—¶(&amp;H)</translation>
+ </message>
+ <message>
+ <source>1 d&amp;ay</source>
+ <translation type="unfinished">1 天(&amp;A)</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation type="unfinished">1 周(&amp;W)</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation type="unfinished">1 å¹´(&amp;Y)</translation>
+ </message>
+ <message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">å¤åˆ¶IP/网络掩ç (&amp;C)</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation type="unfinished">解å°(&amp;U)</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation type="unfinished">网络活动已ç¦ç”¨</translation>
+ </message>
+ <message>
+ <source>Executing command without any wallet</source>
+ <translation type="unfinished">ä¸ä½¿ç”¨ä»»ä½•é’±åŒ…执行命令</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation type="unfinished">使用“%1â€é’±åŒ…执行命令</translation>
+ </message>
+ <message>
+ <source>Welcome to the %1 RPC console.
+Use up and down arrows to navigate history, and %2 to clear screen.
+Use %3 and %4 to increase or decrease the font size.
+Type %5 for an overview of available commands.
+For more information on using this console, type %6.
+
+%7WARNING: 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.%8</source>
+ <extracomment>RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</extracomment>
+ <translation type="unfinished">欢迎æ¥åˆ° %1 RPC 控制å°ã€‚
+使用上与下箭头以进行历å²å¯¼èˆªï¼Œ%2 以清除å±å¹•ã€‚
+使用%3 å’Œ %4 以增加或å‡å°å­—体大å°ã€‚
+输入 %5 以显示å¯ç”¨å‘½ä»¤çš„概览。
+查看更多关于此控制å°çš„ä¿¡æ¯ï¼Œè¾“å…¥ %6。
+
+%7 警告:骗å­ä»¬å¾ˆæ´»è·ƒï¼Œå‘Šè¯‰ç”¨æˆ·åœ¨è¿™é‡Œè¾“入命令,å·èµ°ä»–们钱包中的内容。ä¸è¦åœ¨ä¸å®Œå…¨äº†è§£ä¸€ä¸ªå‘½ä»¤çš„åŽæžœçš„情况下使用此控制å°ã€‚%8</translation>
+ </message>
+ <message>
+ <source>Executing…</source>
+ <extracomment>A console message indicating an entered command is currently being executed.</extracomment>
+ <translation type="unfinished">执行中……</translation>
+ </message>
+ <message>
+ <source>(peer: %1)</source>
+ <translation type="unfinished">(节点: %1)</translation>
+ </message>
+ <message>
+ <source>via %1</source>
+ <translation type="unfinished">通过 %1</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished">是</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished">å¦</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation type="unfinished">到</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation type="unfinished">æ¥è‡ª</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation type="unfinished">å°ç¦æ—¶é•¿</translation>
+ </message>
+ <message>
+ <source>Never</source>
+ <translation type="unfinished">æ°¸ä¸</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation type="unfinished">未知</translation>
+ </message>
+</context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Amount:</source>
+ <translation type="unfinished">金é¢(&amp;A):</translation>
+ </message>
+ <message>
+ <source>&amp;Label:</source>
+ <translation type="unfinished">标签(&amp;L):</translation>
+ </message>
+ <message>
+ <source>&amp;Message:</source>
+ <translation type="unfinished">消æ¯(&amp;M):</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 type="unfinished">å¯åœ¨æ”¯ä»˜è¯·æ±‚上备注一æ¡ä¿¡æ¯ï¼Œåœ¨æ‰“开支付请求时å¯ä»¥çœ‹åˆ°ã€‚注æ„:该消æ¯ä¸æ˜¯é€šè¿‡æ¯”特å¸ç½‘络传é€ã€‚</translation>
+ </message>
+ <message>
+ <source>An optional label to associate with the new receiving address.</source>
+ <translation type="unfinished">å¯ä¸ºæ–°å»ºçš„收款地å€æ·»åŠ ä¸€ä¸ªæ ‡ç­¾ã€‚</translation>
+ </message>
+ <message>
+ <source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
+ <translation type="unfinished">使用此表å•è¯·æ±‚付款。所有字段都是&lt;b&gt;å¯é€‰&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 type="unfinished">å¯é€‰çš„请求金é¢ã€‚留空或填零为ä¸è¦æ±‚具体金é¢ã€‚</translation>
+ </message>
+ <message>
+ <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
+ <translation type="unfinished">一个关è”到新收款地å€ï¼ˆè¢«æ‚¨ç”¨æ¥è¯†åˆ«å‘票)的å¯é€‰æ ‡ç­¾ã€‚它也会被附加到付款请求中。</translation>
+ </message>
+ <message>
+ <source>An optional message that is attached to the payment request and may be displayed to the sender.</source>
+ <translation type="unfinished">一æ¡é™„加到付款请求中的å¯é€‰æ¶ˆæ¯ï¼Œå¯ä»¥æ˜¾ç¤ºç»™ä»˜æ¬¾æ–¹ã€‚</translation>
+ </message>
+ <message>
+ <source>&amp;Create new receiving address</source>
+ <translation type="unfinished">新建收款地å€(&amp;C)</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation type="unfinished">清除此表å•çš„所有字段。</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation type="unfinished">清除</translation>
+ </message>
+ <message>
+ <source>Requested payments history</source>
+ <translation type="unfinished">付款请求历å²</translation>
+ </message>
+ <message>
+ <source>Show the selected request (does the same as double clicking an entry)</source>
+ <translation type="unfinished">显示选中的请求 (直接åŒå‡»é¡¹ç›®ä¹Ÿå¯ä»¥æ˜¾ç¤º)</translation>
+ </message>
+ <message>
+ <source>Show</source>
+ <translation type="unfinished">显示</translation>
+ </message>
+ <message>
+ <source>Remove the selected entries from the list</source>
+ <translation type="unfinished">从列表中移除选中的æ¡ç›®</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation type="unfinished">移除</translation>
+ </message>
+ <message>
+ <source>Copy &amp;URI</source>
+ <translation type="unfinished">å¤åˆ¶ &amp;URI</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">å¤åˆ¶åœ°å€(&amp;C)</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">å¤åˆ¶æ ‡ç­¾(&amp;L)</translation>
+ </message>
+ <message>
+ <source>Copy &amp;message</source>
+ <translation type="unfinished">å¤åˆ¶æ¶ˆæ¯(&amp;M)</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">å¤åˆ¶é‡‘é¢(&amp;A)</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished">无法解é”钱包。</translation>
+ </message>
+ <message>
+ <source>Could not generate new %1 address</source>
+ <translation type="unfinished">无法生æˆæ–°çš„%1地å€</translation>
+ </message>
+</context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Request payment to …</source>
+ <translation type="unfinished">请求支付至...</translation>
+ </message>
+ <message>
+ <source>Address:</source>
+ <translation type="unfinished">地å€:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">金é¢:</translation>
+ </message>
+ <message>
+ <source>Label:</source>
+ <translation type="unfinished">标签:</translation>
+ </message>
+ <message>
+ <source>Message:</source>
+ <translation type="unfinished">消æ¯:</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">钱包:</translation>
+ </message>
+ <message>
+ <source>Copy &amp;URI</source>
+ <translation type="unfinished">å¤åˆ¶ &amp;URI</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Address</source>
+ <translation type="unfinished">å¤åˆ¶åœ°å€(&amp;A)</translation>
+ </message>
+ <message>
+ <source>&amp;Verify</source>
+ <translation type="unfinished">验è¯(&amp;V)</translation>
+ </message>
+ <message>
+ <source>Verify this address on e.g. a hardware wallet screen</source>
+ <translation type="unfinished">在åƒæ˜¯ç¡¬ä»¶é’±åŒ…å±å¹•çš„地方检验这个地å€</translation>
+ </message>
+ <message>
+ <source>&amp;Save Image…</source>
+ <translation type="unfinished">ä¿å­˜å›¾åƒ(&amp;S)...</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation type="unfinished">付款信æ¯</translation>
+ </message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation type="unfinished">请求付款到 %1</translation>
+ </message>
+</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation type="unfinished">日期</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">标签</translation>
</message>
<message>
+ <source>Message</source>
+ <translation type="unfinished">消æ¯</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(无标签)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation type="unfinished">(无消æ¯)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation type="unfinished">(未填写请求金é¢)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation type="unfinished">请求金é¢</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
+ <message>
+ <source>Send Coins</source>
+ <translation type="unfinished">å‘å¸</translation>
+ </message>
+ <message>
+ <source>Coin Control Features</source>
+ <translation type="unfinished">手动选å¸åŠŸèƒ½</translation>
+ </message>
+ <message>
+ <source>automatically selected</source>
+ <translation type="unfinished">自动选择</translation>
+ </message>
+ <message>
+ <source>Insufficient funds!</source>
+ <translation type="unfinished">金é¢ä¸è¶³ï¼</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation type="unfinished">总é‡:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation type="unfinished">字节数:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation type="unfinished">金é¢:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation type="unfinished">费用:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation type="unfinished">加上交易费用åŽ:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation type="unfinished">找零:</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 type="unfinished">在激活该选项åŽï¼Œå¦‚果填写了无效的找零地å€ï¼Œæˆ–者干脆没填找零地å€ï¼Œæ‰¾é›¶èµ„金将会被转入新生æˆçš„地å€ã€‚</translation>
+ </message>
+ <message>
+ <source>Custom change address</source>
+ <translation type="unfinished">自定义找零地å€</translation>
+ </message>
+ <message>
+ <source>Transaction Fee:</source>
+ <translation type="unfinished">交易手续费:</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 type="unfinished">如果使用备用手续费设置,有å¯èƒ½ä¼šå¯¼è‡´äº¤æ˜“ç»è¿‡å‡ ä¸ªå°æ—¶ã€å‡ å¤©ï¼ˆç”šè‡³æ°¸è¿œï¼‰æ— æ³•è¢«ç¡®è®¤ã€‚请考虑手动选择手续费,或等待整个链完æˆéªŒè¯ã€‚</translation>
+ </message>
+ <message>
+ <source>Warning: Fee estimation is currently not possible.</source>
+ <translation type="unfinished">警告: ç›®å‰æ— æ³•è¿›è¡Œæ‰‹ç»­è´¹ä¼°è®¡ã€‚</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation type="unfinished">æ¯KB</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation type="unfinished">éšè—</translation>
+ </message>
+ <message>
+ <source>Recommended:</source>
+ <translation type="unfinished">推è:</translation>
+ </message>
+ <message>
+ <source>Custom:</source>
+ <translation type="unfinished">自定义:</translation>
+ </message>
+ <message>
+ <source>Send to multiple recipients at once</source>
+ <translation type="unfinished">一次å‘é€ç»™å¤šä¸ªæ”¶æ¬¾äºº</translation>
+ </message>
+ <message>
+ <source>Add &amp;Recipient</source>
+ <translation type="unfinished">添加收款人(&amp;R)</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation type="unfinished">清除此表å•çš„所有字段。</translation>
+ </message>
+ <message>
+ <source>Inputs…</source>
+ <translation type="unfinished">输入...</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation type="unfinished">粉尘:</translation>
+ </message>
+ <message>
+ <source>Choose…</source>
+ <translation type="unfinished">选择...</translation>
+ </message>
+ <message>
+ <source>Hide transaction fee settings</source>
+ <translation type="unfinished">éšè—交易手续费设置</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 rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation type="unfinished">指定交易虚拟大å°çš„æ¯kB (1,000字节) 自定义费率。
+
+附注:因为矿工费是按字节计费的,所以如果费率是“æ¯kvB支付100èªâ€ï¼Œé‚£ä¹ˆå¯¹äºŽä¸€ç¬”500虚拟字节 (1kvB的一åŠ) 的交易,最终将åªä¼šäº§ç”Ÿ50èªçš„矿工费。(译注:这里就是æ醒å•ä½æ˜¯å­—节,而ä¸æ˜¯åƒå­—节,如果æžé”™çš„è¯ï¼ŒçŸ¿å·¥è´¹ä¼šè¿‡ä½Žï¼Œå¯¼è‡´äº¤æ˜“长时间无法确认,或者压根无法å‘出)</translation>
+ </message>
+ <message>
+ <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>
+ <source>A too low fee might result in a never confirming transaction (read the tooltip)</source>
+ <translation type="unfinished">过低的手续费率å¯èƒ½å¯¼è‡´äº¤æ˜“永远无法确认(请阅读工具æ示)</translation>
+ </message>
+ <message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source>
+ <translation type="unfinished">(智能矿工费尚未被åˆå§‹åŒ–。这一般需è¦å‡ ä¸ªåŒºå—...)</translation>
+ </message>
+ <message>
+ <source>Confirmation time target:</source>
+ <translation type="unfinished">确认时间目标:</translation>
+ </message>
+ <message>
+ <source>Enable Replace-By-Fee</source>
+ <translation type="unfinished">å¯ç”¨æ‰‹ç»­è´¹è¿½åŠ </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 type="unfinished">手续费追加(Replace-By-Fee,BIP-125)å¯ä»¥è®©ä½ åœ¨é€å‡ºäº¤æ˜“åŽç»§ç»­è¿½åŠ æ‰‹ç»­è´¹ã€‚ä¸ç”¨è¿™ä¸ªåŠŸèƒ½çš„è¯ï¼Œå»ºè®®ä»˜æ¯”较高的手续费æ¥é™ä½Žäº¤æ˜“延迟的风险。</translation>
+ </message>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation type="unfinished">清除所有(&amp;A)</translation>
+ </message>
+ <message>
+ <source>Balance:</source>
+ <translation type="unfinished">ä½™é¢:</translation>
+ </message>
+ <message>
+ <source>Confirm the send action</source>
+ <translation type="unfinished">确认å‘é€æ“作</translation>
+ </message>
+ <message>
+ <source>S&amp;end</source>
+ <translation type="unfinished">å‘é€(&amp;E)</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation type="unfinished">å¤åˆ¶æ•°ç›®</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">å¤åˆ¶é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">å¤åˆ¶æ‰‹ç»­è´¹</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation type="unfinished">å¤åˆ¶å«äº¤æ˜“费的金é¢</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation type="unfinished">å¤åˆ¶å­—节数</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation type="unfinished">å¤åˆ¶ç²‰å°˜é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation type="unfinished">å¤åˆ¶æ‰¾é›¶é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>%1 (%2 blocks)</source>
+ <translation type="unfinished">%1 (%2个å—)</translation>
+ </message>
+ <message>
+ <source>Sign on device</source>
+ <extracomment>"device" usually means a hardware wallet.</extracomment>
+ <translation type="unfinished">在设备上签å</translation>
+ </message>
+ <message>
+ <source>Connect your hardware wallet first.</source>
+ <translation type="unfinished">请先连接您的硬件钱包。</translation>
+ </message>
+ <message>
+ <source>Set external signer script path in Options -&gt; Wallet</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">在 选项 -&gt; 钱包 中设置外部签å器脚本路径</translation>
+ </message>
+ <message>
+ <source>Cr&amp;eate Unsigned</source>
+ <translation type="unfinished">创建未签å交易(&amp;E)</translation>
+ </message>
+ <message>
+ <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <translation type="unfinished">创建一个“部分签å比特å¸äº¤æ˜“â€ï¼ˆPSBT),以用于诸如离线%1钱包,或是兼容PSBT的硬件钱包这类用途。</translation>
+ </message>
+ <message>
+ <source> from wallet '%1'</source>
+ <translation type="unfinished">从钱包%1</translation>
+ </message>
+ <message>
+ <source>%1 to '%2'</source>
+ <translation type="unfinished">%1 到 '%2'</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation type="unfinished">%1 到 %2</translation>
+ </message>
+ <message>
+ <source>To review recipient list click "Show Details…"</source>
+ <translation type="unfinished">点击“查看详情â€ä»¥å®¡æ ¸æ”¶æ¬¾äººåˆ—表</translation>
+ </message>
+ <message>
+ <source>Sign failed</source>
+ <translation type="unfinished">ç­¾å失败</translation>
+ </message>
+ <message>
+ <source>External signer not found</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">未找到外部签å器</translation>
+ </message>
+ <message>
+ <source>External signer failure</source>
+ <extracomment>"External signer" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">外部签å器失败</translation>
+ </message>
+ <message>
+ <source>Save Transaction Data</source>
+ <translation type="unfinished">ä¿å­˜äº¤æ˜“æ•°æ®</translation>
+ </message>
+ <message>
+ <source>Partially Signed Transaction (Binary)</source>
+ <extracomment>Expanded name of the binary PSBT file format. See: BIP 174.</extracomment>
+ <translation type="unfinished">部分签å交易(二进制)</translation>
+ </message>
+ <message>
+ <source>PSBT saved</source>
+ <translation type="unfinished">å·²ä¿å­˜PSBT</translation>
+ </message>
+ <message>
+ <source>External balance:</source>
+ <translation type="unfinished">外部余é¢:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished">或</translation>
+ </message>
+ <message>
+ <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
+ <translation type="unfinished">ä½ å¯ä»¥åŽæ¥å†è¿½åŠ æ‰‹ç»­è´¹ï¼ˆæ‰“上支æŒBIP-125手续费追加的标记)</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment>
+ <translation type="unfinished">请务必仔细检查您的交易请求。这会产生一个部分签å比特å¸äº¤æ˜“(PSBT),å¯ä»¥æŠŠä¿å­˜ä¸‹æ¥æˆ–å¤åˆ¶å‡ºåŽ»ï¼Œç„¶åŽå°±å¯ä»¥å¯¹å®ƒè¿›è¡Œç­¾å,比如用离线%1钱包,或是用兼容PSBT的硬件钱包。</translation>
+ </message>
+ <message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">è¦åˆ›å»ºè¿™ç¬”交易å—?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">请务必仔细检查您的交易。你å¯ä»¥åˆ›å»ºå¹¶å‘é€è¿™ç¬”交易;也å¯ä»¥åˆ›å»ºä¸€ä¸ªâ€œéƒ¨åˆ†ç­¾å比特å¸äº¤æ˜“(PSBT)â€ï¼Œå®ƒå¯ä»¥è¢«ä¿å­˜ä¸‹æ¥æˆ–被å¤åˆ¶å‡ºåŽ»ï¼Œç„¶åŽå°±å¯ä»¥å¯¹å®ƒè¿›è¡Œç­¾å,比如用离线%1钱包,或是用兼容PSBT的硬件钱包。</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
+ <translation type="unfinished">请检查您的交易。</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation type="unfinished">交易手续费</translation>
+ </message>
+ <message>
+ <source>Not signalling Replace-By-Fee, BIP-125.</source>
+ <translation type="unfinished">没有打上BIP-125手续费追加的标记。</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation type="unfinished">总é¢</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation type="unfinished">确认å‘å¸</translation>
+ </message>
+ <message>
+ <source>Watch-only balance:</source>
+ <translation type="unfinished">仅观察余é¢:</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation type="unfinished">接收人地å€æ— æ•ˆã€‚请é‡æ–°æ£€æŸ¥ã€‚</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation type="unfinished">支付金é¢å¿…须大于0。</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation type="unfinished">金é¢è¶…出您的余é¢ã€‚</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation type="unfinished">计入 %1 手续费åŽï¼Œé‡‘é¢è¶…出了您的余é¢ã€‚</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation type="unfinished">å‘现é‡å¤åœ°å€:æ¯ä¸ªåœ°å€åº”该åªä½¿ç”¨ä¸€æ¬¡ã€‚</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation type="unfinished">交易创建失败ï¼</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation type="unfinished">超过 %1 的手续费被视为高得离谱。</translation>
+ </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>预计%n个区å—内确认。</numerusform>
</translation>
</message>
<message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation type="unfinished">警告: 比特å¸åœ°å€æ— æ•ˆ</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation type="unfinished">警告:未知的找零地å€</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation type="unfinished">确认自定义找零地å€</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 type="unfinished">你选择的找零地å€æœªè¢«åŒ…å«åœ¨æœ¬é’±åŒ…中,你钱包中的部分或全部金é¢å°†è¢«å‘é€è‡³è¯¥åœ°å€ã€‚你确定è¦è¿™æ ·åšå—?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(无标签)</translation>
</message>
</context>
<context>
+ <name>SendCoinsEntry</name>
+ <message>
+ <source>A&amp;mount:</source>
+ <translation type="unfinished">金é¢(&amp;M)</translation>
+ </message>
+ <message>
+ <source>Pay &amp;To:</source>
+ <translation type="unfinished">付给(&amp;T):</translation>
+ </message>
+ <message>
+ <source>&amp;Label:</source>
+ <translation type="unfinished">标签(&amp;L):</translation>
+ </message>
+ <message>
+ <source>Choose previously used address</source>
+ <translation type="unfinished">选择以å‰ç”¨è¿‡çš„地å€</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to send the payment to</source>
+ <translation type="unfinished">付款目的地å€</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation type="unfinished">从剪贴æ¿ç²˜è´´åœ°å€</translation>
+ </message>
+ <message>
+ <source>Remove this entry</source>
+ <translation type="unfinished">移除此项</translation>
+ </message>
+ <message>
+ <source>The amount to send in the selected unit</source>
+ <translation type="unfinished">用被选å•ä½è¡¨ç¤ºçš„å¾…å‘é€é‡‘é¢</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 type="unfinished">交易费将从å‘é€é‡‘é¢ä¸­æ‰£é™¤ã€‚接收人收到的比特å¸å°†ä¼šæ¯”您在金é¢æ¡†ä¸­è¾“入的更少。如果选中了多个收件人,交易费平分。</translation>
+ </message>
+ <message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation type="unfinished">从金é¢ä¸­å‡åŽ»äº¤æ˜“è´¹(&amp;U)</translation>
+ </message>
+ <message>
+ <source>Use available balance</source>
+ <translation type="unfinished">使用全部å¯ç”¨ä½™é¢</translation>
+ </message>
+ <message>
+ <source>Message:</source>
+ <translation type="unfinished">消æ¯:</translation>
+ </message>
+ <message>
+ <source>Enter a label for this address to add it to the list of used addresses</source>
+ <translation type="unfinished">请为此地å€è¾“入一个标签以将它加入已用地å€åˆ—表</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 type="unfinished">bitcoin: URI 附带的备注信æ¯ï¼Œå°†ä¼šå’Œäº¤æ˜“一起存储,备查。 注æ„:该消æ¯ä¸ä¼šé€šè¿‡æ¯”特å¸ç½‘络传输。</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Send</source>
+ <translation type="unfinished">å‘é€</translation>
+ </message>
+ <message>
+ <source>Create Unsigned</source>
+ <translation type="unfinished">创建未签å交易</translation>
+ </message>
+</context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ <message>
+ <source>Signatures - Sign / Verify a Message</source>
+ <translation type="unfinished">ç­¾å - 为消æ¯ç­¾å/验è¯ç­¾å消æ¯</translation>
+ </message>
+ <message>
+ <source>&amp;Sign Message</source>
+ <translation type="unfinished">消æ¯ç­¾å(&amp;S)</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 type="unfinished">您å¯ä»¥ç”¨ä½ çš„地å€å¯¹æ¶ˆæ¯/å议进行签å,以è¯æ˜Žæ‚¨å¯ä»¥æŽ¥æ”¶å‘é€åˆ°è¯¥åœ°å€çš„比特å¸ã€‚注æ„ä¸è¦å¯¹ä»»ä½•æ¨¡æ£±ä¸¤å¯æˆ–者éšæœºçš„消æ¯è¿›è¡Œç­¾å,以å…é­å—é’“é±¼å¼æ”»å‡»ã€‚请确ä¿æ¶ˆæ¯å†…容准确的表达了您的真实æ„愿。</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to sign the message with</source>
+ <translation type="unfinished">用æ¥å¯¹æ¶ˆæ¯ç­¾å的地å€</translation>
+ </message>
+ <message>
+ <source>Choose previously used address</source>
+ <translation type="unfinished">选择以å‰ç”¨è¿‡çš„地å€</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation type="unfinished">从剪贴æ¿ç²˜è´´åœ°å€</translation>
+ </message>
+ <message>
+ <source>Enter the message you want to sign here</source>
+ <translation type="unfinished">在这里输入您想è¦ç­¾å的消æ¯</translation>
+ </message>
+ <message>
+ <source>Signature</source>
+ <translation type="unfinished">ç­¾å</translation>
+ </message>
+ <message>
+ <source>Copy the current signature to the system clipboard</source>
+ <translation type="unfinished">å¤åˆ¶å½“å‰ç­¾å至剪贴æ¿</translation>
+ </message>
+ <message>
+ <source>Sign the message to prove you own this Bitcoin address</source>
+ <translation type="unfinished">ç­¾å消æ¯ï¼Œä»¥è¯æ˜Žè¿™ä¸ªåœ°å€å±žäºŽæ‚¨</translation>
+ </message>
+ <message>
+ <source>Sign &amp;Message</source>
+ <translation type="unfinished">ç­¾å消æ¯(&amp;M)</translation>
+ </message>
+ <message>
+ <source>Reset all sign message fields</source>
+ <translation type="unfinished">清空所有签å消æ¯æ </translation>
+ </message>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation type="unfinished">清除所有(&amp;A)</translation>
+ </message>
+ <message>
+ <source>&amp;Verify Message</source>
+ <translation type="unfinished">消æ¯éªŒè¯(&amp;V)</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 type="unfinished">请在下é¢è¾“入接收者地å€ã€æ¶ˆæ¯ï¼ˆç¡®ä¿æ¢è¡Œç¬¦ã€ç©ºæ ¼ç¬¦ã€åˆ¶è¡¨ç¬¦ç­‰å®Œå…¨ç›¸åŒï¼‰å’Œç­¾å以验è¯æ¶ˆæ¯ã€‚请仔细核对签åä¿¡æ¯ï¼Œä»¥æ防中间人攻击。请注æ„,这åªæ˜¯è¯æ˜ŽæŽ¥æ”¶æ–¹å¯ä»¥ç”¨è¿™ä¸ªåœ°å€ç­¾å,它ä¸èƒ½è¯æ˜Žä»»ä½•äº¤æ˜“çš„å‘é€äººèº«ä»½ï¼</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address the message was signed with</source>
+ <translation type="unfinished">用æ¥ç­¾å消æ¯çš„地å€</translation>
+ </message>
+ <message>
+ <source>The signed message to verify</source>
+ <translation type="unfinished">待验è¯çš„已签å消æ¯</translation>
+ </message>
+ <message>
+ <source>The signature given when the message was signed</source>
+ <translation type="unfinished">对消æ¯è¿›è¡Œç­¾ç½²å¾—到的签åæ•°æ®</translation>
+ </message>
+ <message>
+ <source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
+ <translation type="unfinished">验è¯æ¶ˆæ¯ï¼Œç¡®ä¿æ¶ˆæ¯æ˜¯ç”±æŒ‡å®šçš„比特å¸åœ°å€ç­¾å过的。</translation>
+ </message>
+ <message>
+ <source>Verify &amp;Message</source>
+ <translation type="unfinished">验è¯æ¶ˆæ¯ç­¾å(&amp;M)</translation>
+ </message>
+ <message>
+ <source>Reset all verify message fields</source>
+ <translation type="unfinished">清空所有验è¯æ¶ˆæ¯æ </translation>
+ </message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation type="unfinished">å•å‡»â€œç­¾å消æ¯â€œäº§ç”Ÿç­¾å。</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation type="unfinished">输入的地å€æ— æ•ˆã€‚</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation type="unfinished">请检查地å€åŽé‡è¯•ã€‚</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation type="unfinished">找ä¸åˆ°ä¸Žè¾“入地å€ç›¸å…³çš„密钥。</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation type="unfinished">å·²å–消解é”钱包。</translation>
+ </message>
+ <message>
+ <source>No error</source>
+ <translation type="unfinished">没有错误</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation type="unfinished">找ä¸åˆ°è¾“入地å€å…³è”çš„ç§é’¥ã€‚</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation type="unfinished">消æ¯ç­¾å失败。</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation type="unfinished">消æ¯å·²ç­¾å。</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation type="unfinished">ç­¾å无法解ç ã€‚</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation type="unfinished">请检查签ååŽé‡è¯•ã€‚</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation type="unfinished">ç­¾å与消æ¯æ‘˜è¦ä¸åŒ¹é…。</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation type="unfinished">消æ¯éªŒè¯å¤±è´¥ã€‚</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation type="unfinished">消æ¯éªŒè¯æˆåŠŸã€‚</translation>
+ </message>
+</context>
+<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished">(按q退出并在以åŽç»§ç»­)</translation>
+ </message>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">按q键关闭并退出</translation>
+ </message>
+</context>
+<context>
<name>TransactionDesc</name>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
+ <translation type="unfinished">与一个有 %1 个确认的交易冲çª</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/未确认,在内存池中</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/未确认,ä¸åœ¨å†…存池中</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
+ <translation type="unfinished">已丢弃</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
+ <translation type="unfinished">%1/未确认</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
+ <translation type="unfinished">%1 个确认</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation type="unfinished">状æ€</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">日期</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation type="unfinished">æ¥æº</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation type="unfinished">挖矿生æˆ</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation type="unfinished">æ¥è‡ª</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished">未知</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation type="unfinished">到</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation type="unfinished">自己的地å€</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation type="unfinished">仅观察:</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation type="unfinished">标签</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation type="unfinished">收入</translation>
+ </message>
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>在%n个区å—内æˆç†Ÿ</numerusform>
</translation>
</message>
- </context>
+ <message>
+ <source>not accepted</source>
+ <translation type="unfinished">未被接å—</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation type="unfinished">支出</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation type="unfinished">总支出</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation type="unfinished">总收入</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation type="unfinished">交易手续费</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation type="unfinished">净é¢</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation type="unfinished">消æ¯</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation type="unfinished">备注</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation type="unfinished">交易 ID</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation type="unfinished">交易总大å°</translation>
+ </message>
+ <message>
+ <source>Transaction virtual size</source>
+ <translation type="unfinished">交易虚拟大å°</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation type="unfinished">输出索引</translation>
+ </message>
+ <message>
+ <source> (Certificate was not verified)</source>
+ <translation type="unfinished">(è¯ä¹¦æœªè¢«éªŒè¯)</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation type="unfinished">商家</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 type="unfinished">新挖出的比特å¸åœ¨å¯ä»¥ä½¿ç”¨å‰å¿…é¡»ç»è¿‡ %1 个区å—确认的æˆç†Ÿè¿‡ç¨‹ã€‚当您挖出此区å—åŽï¼Œå®ƒå°†è¢«å¹¿æ’­åˆ°ç½‘络中以加入区å—链。如果它未æˆåŠŸè¿›å…¥åŒºå—链,其状æ€å°†å˜æ›´ä¸ºâ€œä¸æŽ¥å—â€å¹¶ä¸”ä¸å¯ä½¿ç”¨ã€‚è¿™å¯èƒ½å¶å°”会å‘生,在å¦ä¸€ä¸ªèŠ‚点比你早几秒钟æˆåŠŸæŒ–出一个区å—时就会这样。</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation type="unfinished">调试信æ¯</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation type="unfinished">交易</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation type="unfinished">输入</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation type="unfinished">金é¢</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation type="unfinished">是</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation type="unfinished">å¦</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionDescDialog</name>
+ <message>
+ <source>This pane shows a detailed description of the transaction</source>
+ <translation type="unfinished">当å‰é¢æ¿æ˜¾ç¤ºäº†äº¤æ˜“的详细信æ¯</translation>
+ </message>
+ <message>
+ <source>Details for %1</source>
+ <translation type="unfinished">%1 详情</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation type="unfinished">日期</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation type="unfinished">类型</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">标签</translation>
</message>
<message>
+ <source>Unconfirmed</source>
+ <translation type="unfinished">未确认</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation type="unfinished">已丢弃</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation type="unfinished">确认中 (推è %2个确认,已ç»æœ‰ %1个确认)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation type="unfinished">已确认 (%1 个确认)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation type="unfinished">有冲çª</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation type="unfinished">未æˆç†Ÿ (%1 个确认,将在 %2 个åŽå¯ç”¨)</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation type="unfinished">已生æˆä½†æœªè¢«æŽ¥å—</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation type="unfinished">接收到</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation type="unfinished">接收自</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation type="unfinished">å‘é€åˆ°</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation type="unfinished">支付给自己</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation type="unfinished">挖矿所得</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation type="unfinished">仅观察:</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation type="unfinished">(ä¸å¯ç”¨)</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation type="unfinished">(无标签)</translation>
</message>
- </context>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation type="unfinished">交易状æ€ã€‚ 鼠标移到此区域å¯æ˜¾ç¤ºç¡®è®¤æ•°ã€‚</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation type="unfinished">交易被接收的时间和日期。</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation type="unfinished">交易类型。</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation type="unfinished">该交易中是å¦æ¶‰åŠä»…观察地å€ã€‚</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation type="unfinished">用户自定义的该交易的æ„图/目的。</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation type="unfinished">从余é¢å¢žåŠ æˆ–移除的金é¢ã€‚</translation>
+ </message>
+</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation type="unfinished">全部</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation type="unfinished">今天</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation type="unfinished">本周</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation type="unfinished">本月</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation type="unfinished">上个月</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation type="unfinished">今年</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation type="unfinished">接收到</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation type="unfinished">å‘é€åˆ°</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation type="unfinished">给自己</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation type="unfinished">挖矿所得</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation type="unfinished">其它</translation>
+ </message>
+ <message>
+ <source>Enter address, transaction id, or label to search</source>
+ <translation type="unfinished">输入地å€ã€äº¤æ˜“ID或标签进行æœç´¢</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation type="unfinished">最å°é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>Range…</source>
+ <translation type="unfinished">范围...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">å¤åˆ¶åœ°å€(&amp;C)</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">å¤åˆ¶æ ‡ç­¾(&amp;L)</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">å¤åˆ¶é‡‘é¢(&amp;A)</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">å¤åˆ¶äº¤æ˜“ &amp;ID</translation>
+ </message>
+ <message>
+ <source>Copy &amp;raw transaction</source>
+ <translation type="unfinished">å¤åˆ¶åŽŸå§‹äº¤æ˜“(&amp;R)</translation>
+ </message>
+ <message>
+ <source>Copy full transaction &amp;details</source>
+ <translation type="unfinished">å¤åˆ¶å®Œæ•´äº¤æ˜“详情(&amp;D)</translation>
+ </message>
+ <message>
+ <source>&amp;Show transaction details</source>
+ <translation type="unfinished">显示交易详情(&amp;S)</translation>
+ </message>
+ <message>
+ <source>Increase transaction &amp;fee</source>
+ <translation type="unfinished">增加矿工费(&amp;F)</translation>
+ </message>
+ <message>
+ <source>A&amp;bandon transaction</source>
+ <translation type="unfinished">放弃交易(&amp;B)</translation>
+ </message>
+ <message>
+ <source>&amp;Edit address label</source>
+ <translation type="unfinished">编辑地å€æ ‡ç­¾(&amp;E)</translation>
+ </message>
+ <message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">在 %1中显示</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation type="unfinished">导出交易历å²</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">逗å·åˆ†éš”文件</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation type="unfinished">已确认</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation type="unfinished">仅观察</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation type="unfinished">日期</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation type="unfinished">类型</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">标签</translation>
</message>
@@ -333,12 +4632,168 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Exporting Failed</source>
<translation type="unfinished">导出失败</translation>
</message>
- </context>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation type="unfinished">å°è¯•æŠŠäº¤æ˜“历å²ä¿å­˜åˆ° %1 æ—¶å‘生了错误。</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation type="unfinished">导出æˆåŠŸ</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation type="unfinished">å·²æˆåŠŸå°†äº¤æ˜“历å²ä¿å­˜åˆ° %1。</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation type="unfinished">范围:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation type="unfinished">到</translation>
+ </message>
+</context>
+<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.
+Go to File &gt; Open Wallet to load a wallet.
+- OR -</source>
+ <translation type="unfinished">未加载钱包。
+请转到“文件â€èœå• &gt; “打开钱包â€æ¥åŠ è½½ä¸€ä¸ªé’±åŒ…。
+- 或者 -</translation>
+ </message>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">创建一个新的钱包</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">错误</translation>
+ </message>
+ <message>
+ <source>Unable to decode PSBT from clipboard (invalid base64)</source>
+ <translation type="unfinished">无法从剪贴æ¿è§£ç PSBT(Base64值无效)</translation>
+ </message>
+ <message>
+ <source>Load Transaction Data</source>
+ <translation type="unfinished">加载交易数æ®</translation>
+ </message>
+ <message>
+ <source>Partially Signed Transaction (*.psbt)</source>
+ <translation type="unfinished">部分签å交易 (*.psbt)</translation>
+ </message>
+ <message>
+ <source>PSBT file must be smaller than 100 MiB</source>
+ <translation type="unfinished">PSBT文件必须å°äºŽ100MiB</translation>
+ </message>
+ <message>
+ <source>Unable to decode PSBT</source>
+ <translation type="unfinished">无法解ç PSBT</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation type="unfinished">å‘å¸</translation>
+ </message>
+ <message>
+ <source>Fee bump error</source>
+ <translation type="unfinished">追加手续费出错</translation>
+ </message>
+ <message>
+ <source>Increasing transaction fee failed</source>
+ <translation type="unfinished">追加交易手续费失败</translation>
+ </message>
+ <message>
+ <source>Do you want to increase the fee?</source>
+ <extracomment>Asks a user if they would like to manually increase the fee of a transaction that has already been created.</extracomment>
+ <translation type="unfinished">您想追加手续费å—?</translation>
+ </message>
+ <message>
+ <source>Current fee:</source>
+ <translation type="unfinished">当å‰æ‰‹ç»­è´¹:</translation>
+ </message>
+ <message>
+ <source>Increase:</source>
+ <translation type="unfinished">增加é‡:</translation>
+ </message>
+ <message>
+ <source>New fee:</source>
+ <translation type="unfinished">新交易费:</translation>
+ </message>
+ <message>
+ <source>Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
+ <translation type="unfinished">警告: 因为在必è¦çš„时候会å‡å°‘找零输出个数或增加输入个数,这å¯èƒ½è¦ä»˜å‡ºé¢å¤–的费用。在没有找零输出的情况下å¯èƒ½ä¼šæ–°å¢žä¸€ä¸ªã€‚这些å˜æ›´å¯èƒ½ä¼šå¯¼è‡´æ½œåœ¨çš„éšç§æ³„露。</translation>
+ </message>
+ <message>
+ <source>Confirm fee bump</source>
+ <translation type="unfinished">确认手续费追加</translation>
+ </message>
+ <message>
+ <source>Can't draft transaction.</source>
+ <translation type="unfinished">无法起è‰äº¤æ˜“。</translation>
+ </message>
+ <message>
+ <source>PSBT copied</source>
+ <translation type="unfinished">å·²å¤åˆ¶PSBT</translation>
+ </message>
+ <message>
+ <source>Can't sign transaction.</source>
+ <translation type="unfinished">无法签å交易</translation>
+ </message>
+ <message>
+ <source>Could not commit transaction</source>
+ <translation type="unfinished">无法æ交交易</translation>
+ </message>
+ <message>
+ <source>Can't display address</source>
+ <translation type="unfinished">无法显示地å€</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation type="unfinished">默认钱包</translation>
+ </message>
+</context>
<context>
<name>WalletView</name>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">导出</translation>
+ <translation type="unfinished">导出(&amp;E)</translation>
</message>
- </context>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">将当å‰æ ‡ç­¾é¡µæ•°æ®å¯¼å‡ºåˆ°æ–‡ä»¶</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation type="unfinished">备份钱包</translation>
+ </message>
+ <message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">钱包数æ®</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation type="unfinished">备份失败</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation type="unfinished">å°è¯•ä¿å­˜é’±åŒ…æ•°æ®è‡³ %1 æ—¶å‘生了错误。</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation type="unfinished">备份æˆåŠŸ</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation type="unfinished">å·²æˆåŠŸä¿å­˜é’±åŒ…æ•°æ®è‡³ %1。</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished">å–消</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_zh.ts b/src/qt/locale/bitcoin_zh.ts
index a91486f757..321497db53 100644
--- a/src/qt/locale/bitcoin_zh.ts
+++ b/src/qt/locale/bitcoin_zh.ts
@@ -1,6 +1,299 @@
<TS version="2.1" language="zh">
<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation type="unfinished">å³é”®å•å‡»æ¥ç¼–辑地å€æˆ–者标签</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation type="unfinished">创建新地å€</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation type="unfinished">新建(&amp;N)</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation type="unfinished">å¤åˆ¶å½“å‰é€‰ä¸­çš„地å€åˆ°ç³»ç»Ÿå‰ªè´´æ¿</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation type="unfinished">å¤åˆ¶(&amp;C)</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation type="unfinished">关闭(&amp;L)</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">从列表中删除当å‰å·²é€‰åœ°å€</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">输入è¦æœç´¢çš„地å€æˆ–标签</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">将当å‰é€‰é¡¹å¡ä¸­çš„æ•°æ®å¯¼å‡ºåˆ°æ–‡ä»¶</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">导出(&amp;E)</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation type="unfinished">删除(&amp;D)</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">选择收款人地å€</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">选择接收比特å¸åœ°å€</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation type="unfinished">选择(&amp;H)</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation type="unfinished">å‘é€åœ°å€</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation type="unfinished">接收地å€</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 type="unfinished">这些是你的比特å¸æ”¯ä»˜åœ°å€ã€‚在å‘é€ä¹‹å‰ï¼Œä¸€å®šè¦æ ¸å¯¹é‡‘é¢å’ŒæŽ¥æ”¶åœ°å€ã€‚</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.
+Signing is only possible with addresses of the type 'legacy'.</source>
+ <translation type="unfinished">你将使用下列比特å¸åœ°å€æŽ¥å—付款。选å–收款选项å¡ä¸­ “产生新收款地å€â€ 按钮æ¥ç”Ÿæˆæ–°åœ°å€ã€‚
+ç­¾ååªèƒ½ä½¿ç”¨â€œä¼ ç»Ÿâ€ç±»åž‹çš„地å€ã€‚</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished">&amp;å¤åˆ¶åœ°å€</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">å¤åˆ¶ &amp;标签</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;编辑</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">出å£åœ°å€åˆ—表</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">逗å·åˆ†éš”文件</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <extracomment>An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</extracomment>
+ <translation type="unfinished">试图将地å€åˆ—表ä¿å­˜åˆ° %1时出错,请å†è¯•ä¸€æ¬¡ã€‚</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">导出失败</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">标签</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">地å€</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation type="unfinished">(无标签)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation type="unfinished">密ç å¯¹è¯æ¡†</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation type="unfinished">输入密ç </translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation type="unfinished">新的密ç </translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation type="unfinished">é‡å¤æ–°å¯†ç </translation>
+ </message>
+ <message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">显示密ç </translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">加密钱包</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation type="unfinished">该æ“作需è¦æ‚¨çš„钱包密ç æ¥è§£é”钱包。</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation type="unfinished">打开钱包</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation type="unfinished">修改密ç </translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation type="unfinished">确认钱包加密</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 type="unfinished">注æ„: 如果你忘记了你的钱包,你将会丢失你的&lt;b&gt;密ç ï¼Œå¹¶ä¸”会丢失你的&lt;/b&gt;比特å¸ã€‚</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished">您确定è¦åŠ å¯†æ‚¨çš„钱包å—?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished">钱包加密</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase for 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 type="unfinished">输入钱包的新密ç ï¼Œ&lt;br/&gt;请使用&lt;b&gt;10个或以上éšæœºå­—符的密ç &lt;/b&gt;,&lt;b&gt;或者8个以上的å¤æ‚å•è¯&lt;/b&gt;。</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase for the wallet.</source>
+ <translation type="unfinished">输入钱包的旧密ç å’Œæ–°å¯†ç ã€‚</translation>
+ </message>
+ <message>
+ <source>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>
+ <source>Wallet to be encrypted</source>
+ <translation type="unfinished">加密钱包</translation>
+ </message>
+ <message>
+ <source>Your wallet is about to be encrypted. </source>
+ <translation type="unfinished">你的钱包è¦è¢«åŠ å¯†äº†ã€‚</translation>
+ </message>
+ <message>
+ <source>Your wallet is now encrypted. </source>
+ <translation type="unfinished">你的钱包现在被加密了。</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 type="unfinished">é‡è¦æ示:您之å‰å¯¹é’±åŒ…文件所åšçš„任何备份都应该替æ¢ä¸ºæ–°ç”Ÿæˆçš„加密钱包文件。出于安全原因,一旦开始使用新的加密钱包,以å‰æœªåŠ å¯†é’±åŒ…文件的备份就会失效。</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation type="unfinished">钱包加密失败</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation type="unfinished">由于内部错误,钱包加密失败。你的钱包没有加密æˆåŠŸã€‚</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">æ供的密ç ä¸åŒ¹é…。</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation type="unfinished">钱包打开失败</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation type="unfinished">钱包解密输入的密ç ä¸æ­£ç¡®ã€‚</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished">钱包密ç å·²æˆåŠŸæ›´æ”¹ã€‚</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished">警告:大写é”定键已打开!</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation type="unfinished">IP/å­ç½‘掩ç </translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation type="unfinished">被ç¦æ­¢ç›´åˆ°</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">设置文件%1å¯èƒ½å·²æŸå或无效。</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">失控的例外</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">å‘生了一个致命错误。%1ä¸èƒ½å†å®‰å…¨åœ°ç»§ç»­å¹¶å°†é€€å‡ºã€‚</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">内部错误</translation>
+ </message>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">å‘生内部错误。%1å°†å°è¯•å®‰å…¨ç»§ç»­ã€‚这是一个æ„外的错误,å¯ä»¥æŠ¥å‘Šå¦‚下所述。</translation>
+ </message>
+</context>
+<context>
<name>QObject</name>
+ <message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">è¦å°†è®¾ç½®é‡ç½®ä¸ºé»˜è®¤å€¼ï¼Œè¿˜æ˜¯ä¸åšä»»ä½•æ›´æ”¹å°±ä¸­æ­¢?</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">å‘生了一个致命错误。检查设置文件是å¦å¯å†™ï¼Œæˆ–者å°è¯•ä½¿ç”¨-nosettingsè¿è¡Œã€‚</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation type="unfinished">错误:指定的数æ®ç›®å½•â€œ%1“ä¸å­˜åœ¨ã€‚</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation type="unfinished">错误:无法解æžé…置文件:%1。</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">错误: %1</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1尚未安全退出…</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
@@ -39,8 +332,63 @@
</message>
</context>
<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">无法读å–设置文件</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">无法写入设置文件</translation>
+ </message>
+ </context>
+<context>
<name>BitcoinGUI</name>
<message>
+ <source>&amp;Overview</source>
+ <translation type="unfinished">&amp;概述</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation type="unfinished">显示钱包的总体概况</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation type="unfinished">&amp;交易</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation type="unfinished">æµè§ˆåŽ†å²äº¤æ˜“</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation type="unfinished">退&amp;出</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation type="unfinished">退出应用程åº</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation type="unfinished">&amp;关于 %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation type="unfinished">显示信æ¯å…³äºŽ%1</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">加密您的钱包ç§é’¥</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation type="unfinished">用您的比特å¸åœ°å€ç­¾åä¿¡æ¯ï¼Œä»¥è¯æ˜Žæ‹¥æœ‰å®ƒä»¬</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation type="unfinished">验è¯æ¶ˆæ¯ï¼Œç¡®ä¿å®ƒä»¬æ˜¯ç”¨æŒ‡å®šçš„比特å¸åœ°å€ç­¾åçš„</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation type="unfinished">&amp;文件</translation>
</message>
@@ -166,7 +514,7 @@
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
</translation>
</message>
</context>
@@ -176,19 +524,109 @@
<source>Copy amount</source>
<translation type="unfinished">å¤åˆ¶é‡‘é¢</translation>
</message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">å¤åˆ¶æ‰‹ç»­è´¹</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation type="unfinished">是</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished">当任何一个收款金é¢å°äºŽç›®å‰çš„粉尘金é¢é˜ˆå€¼æ—¶ï¼Œæ–‡å­—会å˜çº¢è‰²ã€‚</translation>
+ </message>
+ </context>
+<context>
+ <name>CreateWalletActivity</name>
+ <message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">正在创建钱包&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ </context>
+<context>
+ <name>OpenWalletActivity</name>
+ <message>
+ <source>Open Wallet</source>
+ <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
+ <translation type="unfinished">打开钱包</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletController</name>
+ <message>
+ <source>Close wallet</source>
+ <translation type="unfinished">关闭钱包</translation>
+ </message>
+ </context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit sending address</source>
+ <translation type="unfinished">编辑付款地å€</translation>
+ </message>
</context>
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(sufficient to restore backups %n day(s) old)</numerusform>
</translation>
</message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">错误</translation>
+ </message>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ <message>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;窗å£</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">错误</translation>
+ </message>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>Node window</source>
+ <translation type="unfinished">结点窗å£</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
+ <message>
+ <source>Copy amount</source>
+ <translation type="unfinished">å¤åˆ¶é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation type="unfinished">å¤åˆ¶æ‰‹ç»­è´¹</translation>
+ </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -205,4 +643,22 @@
</translation>
</message>
</context>
+<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">错误</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;导出</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">将当å‰é€‰é¡¹å¡ä¸­çš„æ•°æ®å¯¼å‡ºåˆ°æ–‡ä»¶</translation>
+ </message>
+ </context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts
index c4f84df359..279084b7fe 100644
--- a/src/qt/locale/bitcoin_zh_CN.ts
+++ b/src/qt/locale/bitcoin_zh_CN.ts
@@ -246,6 +246,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">设置文件%1å¯èƒ½å·²æŸå或无效。</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">未æ•èŽ·çš„异常</translation>
</message>
@@ -265,6 +269,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">è¦å°†è®¾ç½®é‡ç½®ä¸ºé»˜è®¤å€¼ï¼Œè¿˜æ˜¯è¦æ”¾å¼ƒæ›´æ”¹å¹¶ä¸­æ­¢ï¼Ÿ</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">出现致命错误。请检查设置文件是å¦å¯å†™ï¼Œæˆ–者å°è¯•å¸¦ -nosettings å‚æ•°è¿è¡Œã€‚</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">错误:指定的数æ®ç›®å½•â€œ%1â€ä¸å­˜åœ¨ã€‚</translation>
</message>
@@ -366,31 +380,31 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n秒</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n分钟</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n å°æ—¶</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n 天</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n 周</numerusform>
</translation>
</message>
<message>
@@ -400,7 +414,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nå¹´</numerusform>
</translation>
</message>
<message>
@@ -411,6 +425,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">无法读å–设置文件</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">无法写入设置文件</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">%s å¼€å‘者</translation>
</message>
@@ -443,6 +465,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">è¯»å– %s æ—¶å‘生错误ï¼æ‰€æœ‰çš„密钥都å¯ä»¥æ­£ç¡®è¯»å–,但是交易记录或地å€ç°¿æ•°æ®å¯èƒ½å·²ç»ä¸¢å¤±æˆ–出错。</translation>
</message>
<message>
+ <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
+ <translation type="unfinished">读å–%s出错ï¼äº¤æ˜“æ•°æ®å¯èƒ½ä¸¢å¤±æˆ–有误。é‡æ–°æ‰«æ钱包中。</translation>
+ </message>
+ <message>
<source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source>
<translation type="unfinished">错误: 转储文件格å¼ä¸æ­£ç¡®ã€‚得到是"%s",而预期本应得到的是 "format"。</translation>
</message>
@@ -459,10 +485,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">错误: 传统钱包åªæ”¯æŒ "legacy", "p2sh-segwit", å’Œ "bech32" 这三ç§åœ°å€ç±»åž‹</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">错误:监å¬å¤–部连接失败 (listen函数返回了错误 %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">手续费估计失败。而且备用手续费估计(fallbackfee)已被ç¦ç”¨ã€‚请å†ç­‰ä¸€äº›åŒºå—,或者通过-fallbackfeeå‚æ•°å¯ç”¨å¤‡ç”¨æ‰‹ç»­è´¹ä¼°è®¡ã€‚</translation>
</message>
@@ -475,6 +497,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">å‚æ•° -maxtxfee=&lt;amount&gt;: '%s' 指定了éžæ³•çš„é‡‘é¢ (手续费必须至少达到最å°è½¬å‘费率(minrelay fee) %s 以é¿å…交易å¡ç€å‘ä¸å‡ºåŽ»)</translation>
</message>
<message>
+ <source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
+ <translation type="unfinished">无效或æŸåçš„peers.dat (%s)。如果你确信这是一个bug,请å馈到%s。作为å˜é€šåŠžæ³•ï¼Œä½ å¯ä»¥æŠŠçŽ°æœ‰æ–‡ä»¶ (%s) 移开(é‡å‘½åã€ç§»åŠ¨æˆ–删除),这样就å¯ä»¥åœ¨ä¸‹æ¬¡å¯åŠ¨æ—¶åˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶äº†ã€‚</translation>
+ </message>
+ <message>
<source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
<translation type="unfinished">æ供多个洋葱路由绑定地å€ã€‚对自动创建的洋葱æœåŠ¡ç”¨%s</translation>
</message>
@@ -503,6 +529,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">修剪被设置得太å°ï¼Œå·²ç»ä½ŽäºŽæœ€å°å€¼%d MiB,请使用更大的数值。</translation>
</message>
<message>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished">修剪模å¼ä¸Ž -reindex-chainstate ä¸å…¼å®¹ã€‚请进行一次完整的 -reindex 。</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 type="unfinished">修剪:上次åŒæ­¥é’±åŒ…çš„ä½ç½®å·²ç»è¶…出(è½åŽäºŽï¼‰çŽ°æœ‰ä¿®å‰ªåŽæ•°æ®çš„范围。你需è¦è¿›è¡Œ-reindex(对于已ç»å¯ç”¨ä¿®å‰ªèŠ‚点,就需è¦é‡æ–°ä¸‹è½½æ•´ä¸ªåŒºå—链)</translation>
</message>
@@ -515,6 +545,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">区å—æ•°æ®åº“包å«æœªæ¥çš„交易,这å¯èƒ½æ˜¯ç”±æœ¬æœºé”™è¯¯çš„日期时间引起。若确认本机日期时间正确,请é‡æ–°å»ºç«‹åŒºå—æ•°æ®åº“。</translation>
</message>
<message>
+ <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
+ <translation type="unfinished">区å—索引数æ®åº“å«æœ‰åŽ†å²é—留的 'txindex' 。å¯ä»¥è¿è¡Œå®Œæ•´çš„ -reindex æ¥æ¸…ç†è¢«å ç”¨çš„ç£ç›˜ç©ºé—´ï¼›ä¹Ÿå¯ä»¥å¿½ç•¥è¿™ä¸ªé”™è¯¯ã€‚这个错误消æ¯å°†ä¸ä¼šå†æ¬¡æ˜¾ç¤ºã€‚</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished">这笔交易在扣除手续费åŽçš„金é¢å¤ªå°ï¼Œä»¥è‡³äºŽæ— æ³•é€å‡º</translation>
</message>
@@ -551,6 +585,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">æä¾›äº†æœªçŸ¥çš„é’±åŒ…æ ¼å¼ "%s" 。请使用 "bdb" 或 "sqlite" 中的一ç§ã€‚</translation>
</message>
<message>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished">找到了ä¸å—支æŒçš„ chainstate æ•°æ®åº“æ ¼å¼ã€‚请使用 -reindex-chainstate å‚æ•°é‡å¯ã€‚这将会é‡å»º chainstate æ•°æ®åº“。</translation>
+ </message>
+ <message>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished">钱包创建æˆåŠŸã€‚æ—§å¼é’±åŒ…已被弃用,未æ¥å°†ä¸å†æ”¯æŒåˆ›å»ºæˆ–打开旧å¼é’±åŒ…。</translation>
+ </message>
+ <message>
<source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source>
<translation type="unfinished">警告: è½¬å‚¨æ–‡ä»¶çš„é’±åŒ…æ ¼å¼ "%s" ä¸Žå‘½ä»¤è¡ŒæŒ‡å®šçš„æ ¼å¼ "%s" ä¸ç¬¦ã€‚</translation>
</message>
@@ -587,6 +629,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">æ— æ³•è§£æž - %s 地å€: '%s'</translation>
</message>
<message>
+ <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
+ <translation type="unfinished">在 -dnsseed 被设为 false 时无法将 -forcednsseed 设为 true 。</translation>
+ </message>
+ <message>
<source>Cannot set -peerblockfilters without -blockfilterindex.</source>
<translation type="unfinished">没有å¯ç”¨-blockfilterindex,就ä¸èƒ½å¯ç”¨-peerblockfilters。</translation>
</message>
@@ -595,6 +641,98 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ä¸èƒ½å†™å…¥åˆ°æ•°æ®ç›®å½•'%s';请检查文件æƒé™ã€‚</translation>
</message>
<message>
+ <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
+ <translation type="unfinished">无法完æˆç”±ä¹‹å‰ç‰ˆæœ¬å¯åŠ¨çš„ -txindex å‡çº§ã€‚请用之å‰çš„版本é‡æ–°å¯åŠ¨ï¼Œæˆ–者进行一次完整的 -reindex 。</translation>
+ </message>
+ <message>
+ <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished">%s请求监å¬ç«¯å£ %u。这个端å£è¢«è®¤ä¸ºæ˜¯â€œåçš„â€ï¼Œæ‰€ä»¥ä¸å¤ªå¯èƒ½æœ‰Bitcoin Core节点会连接到它。有关详细信æ¯å’Œå®Œæ•´åˆ—表,请å‚è§ doc/p2p-bad-ports.md 。</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">-reindex-chainstate 与 -blockfilterindex ä¸å…¼å®¹ã€‚请在进行 -reindex-chainstate 时临时ç¦ç”¨ blockfilterindex ,或者改用 -reindex (而ä¸æ˜¯ -reindex-chainstate )æ¥å®Œæ•´åœ°é‡å»ºæ‰€æœ‰ç´¢å¼•ã€‚</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">-reindex-chainstate 与 -coinstatsindex ä¸å…¼å®¹ã€‚请在进行 -reindex-chainstate 时临时ç¦ç”¨ coinstatsindex ,或者改用 -reindex (而ä¸æ˜¯ -reindex-chainstate )æ¥å®Œæ•´åœ°é‡å»ºæ‰€æœ‰ç´¢å¼•ã€‚</translation>
+ </message>
+ <message>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished">-reindex-chainstate 与 -txindex ä¸å…¼å®¹ã€‚请在进行 -reindex-chainstate 时临时ç¦ç”¨ txindex ,或者改用 -reindex (而ä¸æ˜¯ -reindex-chainstate )æ¥å®Œæ•´åœ°é‡å»ºæ‰€æœ‰ç´¢å¼•ã€‚</translation>
+ </message>
+ <message>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished">å‡å®šæœ‰æ•ˆï¼ˆassume-valid): 上次åŒæ­¥é’±åŒ…时进度越过了现有的区å—æ•°æ®ã€‚你需è¦ç­‰å¾…åŽå°éªŒè¯é“¾ä¸‹è½½æ›´å¤šçš„区å—。</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
+ <translation type="unfinished">在使用地å€ç®¡ç†å™¨(addrman)寻找出站连接时,无法åŒæ—¶æ供特定的连接。</translation>
+ </message>
+ <message>
+ <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source>
+ <translation type="unfinished">加载%s时出错: 编译时未å¯ç”¨å¤–部签å器支æŒï¼Œå´ä»ç„¶è¯•å›¾åŠ è½½å¤–部签å器钱包</translation>
+ </message>
+ <message>
+ <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">错误:钱包中的地å€ç°¿æ•°æ®æ— æ³•è¢«è¯†åˆ«ä¸ºå±žäºŽè¿ç§»åŽçš„钱包</translation>
+ </message>
+ <message>
+ <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
+ <translation type="unfinished">错误:è¿ç§»è¿‡ç¨‹ä¸­åˆ›å»ºäº†é‡å¤çš„输出æ述符。你的钱包å¯èƒ½å·²æŸå。</translation>
+ </message>
+ <message>
+ <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
+ <translation type="unfinished">错误:钱包中的交易%s无法被识别为属于è¿ç§»åŽçš„钱包</translation>
+ </message>
+ <message>
+ <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source>
+ <translation type="unfinished">错误:无法为这个é—留钱包生æˆè¾“出æ述符。请先确定钱包已被解é”</translation>
+ </message>
+ <message>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished">无法é‡å‘½å无效的 peers.dat 文件。 请移动或删除它,然åŽé‡è¯•ã€‚</translation>
+ </message>
+ <message>
+ <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
+ <translation type="unfinished">互ä¸å…¼å®¹çš„选项:-dnsseed=1 已被显å¼æŒ‡å®šï¼Œä½† -onlynet ç¦æ­¢äº†IPv4/IPv6 连接</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
+ <translation type="unfinished">出站连接被é™åˆ¶ä¸ºä»…使用 Tor (-onlynet=onion),但是到达 Tor 网络的代ç†è¢«æ˜¾å¼ç¦æ­¢ï¼š -onion=0</translation>
+ </message>
+ <message>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
+ <translation type="unfinished">出站连接被é™åˆ¶ä¸ºä»…使用 Tor (-onlynet=onion),但是未æ供到达 Tor 网络的代ç†ï¼šæ²¡æœ‰æä¾› -proxy=, -onion= 或 -listenonion å‚æ•°</translation>
+ </message>
+ <message>
+ <source>Unrecognized descriptor found. Loading wallet %s
+
+The wallet might had been created on a newer version.
+Please try running the latest software version.
+</source>
+ <translation type="unfinished">找到无法识别的输出æ述符。加载钱包%s
+
+钱包å¯èƒ½ç”±æ–°ç‰ˆè½¯ä»¶åˆ›å»ºï¼Œ
+请å°è¯•è¿è¡Œæœ€æ–°çš„软件版本。
+</translation>
+ </message>
+ <message>
+ <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
+ <translation type="unfinished">ä¸æ”¯æŒçš„类别é™å®šæ—¥å¿—等级 -loglevel=%s。预期å‚æ•° -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s。有效的类别: %s。</translation>
+ </message>
+ <message>
+ <source>
+Unable to cleanup failed migration</source>
+ <translation type="unfinished">
+无法清ç†å¤±è´¥çš„è¿ç§»</translation>
+ </message>
+ <message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+无法还原钱包备份</translation>
+ </message>
+ <message>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished">对 %s çš„é…置设置åªå¯¹ %s 网络生效,如果它ä½äºŽé…置的 [%s] 章节的è¯ã€‚</translation>
</message>
@@ -675,8 +813,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">从钱包数æ®åº“读å–下一æ¡è®°å½•æ—¶å‡ºé”™</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">å‡çº§é“¾çŠ¶æ€(chainstate)æ•°æ®åº“出错</translation>
+ <source>Error: Could not add watchonly tx to watchonly wallet</source>
+ <translation type="unfinished">错误:无法添加仅观察交易至仅观察钱包</translation>
+ </message>
+ <message>
+ <source>Error: Could not delete watchonly transactions</source>
+ <translation type="unfinished">错误:无法删除仅观察交易</translation>
</message>
<message>
<source>Error: Couldn't create cursor into database</source>
@@ -691,6 +833,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">错误: 转储文件的校验和ä¸ç¬¦ã€‚计算得到%s,预料中本应该得到%s</translation>
</message>
<message>
+ <source>Error: Failed to create new watchonly wallet</source>
+ <translation type="unfinished">错误:创建新仅观察钱包失败</translation>
+ </message>
+ <message>
<source>Error: Got key that was not hex: %s</source>
<translation type="unfinished">错误: 得到了ä¸æ˜¯å六进制的键:%s</translation>
</message>
@@ -711,10 +857,38 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">错误: 没有å¯ç”¨çš„%s地å€ã€‚</translation>
</message>
<message>
+ <source>Error: Not all watchonly txs could be deleted</source>
+ <translation type="unfinished">错误:有些仅观察交易无法被删除</translation>
+ </message>
+ <message>
+ <source>Error: This wallet already uses SQLite</source>
+ <translation type="unfinished">错误:此钱包已ç»åœ¨ä½¿ç”¨SQLite</translation>
+ </message>
+ <message>
+ <source>Error: This wallet is already a descriptor wallet</source>
+ <translation type="unfinished">错误:这个钱包已ç»æ˜¯è¾“出æ述符钱包</translation>
+ </message>
+ <message>
+ <source>Error: Unable to begin reading all records in the database</source>
+ <translation type="unfinished">错误:无法开始读å–这个数æ®åº“中的所有记录</translation>
+ </message>
+ <message>
+ <source>Error: Unable to make a backup of your wallet</source>
+ <translation type="unfinished">错误:无法为你的钱包创建备份</translation>
+ </message>
+ <message>
<source>Error: Unable to parse version %u as a uint32_t</source>
<translation type="unfinished">错误:无法把版本å·%u作为unit32_t解æž</translation>
</message>
<message>
+ <source>Error: Unable to read all records in the database</source>
+ <translation type="unfinished">错误:无法读å–这个数æ®åº“中的所有记录</translation>
+ </message>
+ <message>
+ <source>Error: Unable to remove watchonly address book data</source>
+ <translation type="unfinished">错误:无法移除仅观察地å€ç°¿æ•°æ®</translation>
+ </message>
+ <message>
<source>Error: Unable to write record to new wallet</source>
<translation type="unfinished">错误: 无法写入记录到新钱包</translation>
</message>
@@ -751,6 +925,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">åˆå§‹åŒ–完整性检查失败。%s å³å°†å…³é—­ã€‚</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">找ä¸åˆ°äº¤æ˜“输入项,å¯èƒ½å·²ç»è¢«èŠ±æŽ‰äº†</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">金é¢ä¸è¶³</translation>
</message>
@@ -791,6 +969,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">å‚æ•° -whitelist: '%s' 指定了无效的网络掩ç </translation>
</message>
<message>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished">监å¬å¤–部连接失败 (listen函数返回了错误 %s)</translation>
+ </message>
+ <message>
<source>Loading P2P addresses…</source>
<translation type="unfinished">加载P2P地å€...</translation>
</message>
@@ -807,12 +989,20 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">加载钱包...</translation>
</message>
<message>
+ <source>Missing amount</source>
+ <translation type="unfinished">找ä¸åˆ°é‡‘é¢</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">找ä¸åˆ°ç”¨äºŽä¼°è®¡äº¤æ˜“大å°çš„解答数æ®</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">-whitebind: '%s' 需è¦æŒ‡å®šä¸€ä¸ªç«¯å£</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">未指定代ç†æœåŠ¡å™¨ã€‚请使用 -proxy=&lt;ip&gt; 或 -proxy=&lt;ip:port&gt; 。</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">没有å¯ç”¨çš„地å€</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -823,10 +1013,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ä¸èƒ½æŠŠä¿®å‰ªé…ç½®æˆä¸€ä¸ªè´Ÿæ•°ã€‚</translation>
</message>
<message>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished">区å—修剪模å¼ä¸Ž coinstatsindex ä¸å…¼å®¹ã€‚</translation>
- </message>
- <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished">修剪模å¼ä¸Ž -txindex ä¸å…¼å®¹ã€‚</translation>
</message>
@@ -927,6 +1113,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">交易金é¢ä¸ä¸å¯ä¸ºè´Ÿæ•°</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">交易找零输出项编å·è¶…出范围</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">此交易在内存池中的存在过长的链æ¡</translation>
</message>
@@ -935,10 +1125,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">交易必须包å«è‡³å°‘一个收款人</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">交易需è¦ä¸€ä¸ªæ‰¾é›¶åœ°å€ï¼Œä½†æ˜¯æˆ‘们无法生æˆå®ƒã€‚</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">交易过大</translation>
</message>
<message>
+ <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source>
+ <translation type="unfinished">无法为 -maxsigcachesize: '%s' MiB 分é…内存</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation type="unfinished">无法在本机绑定%sç«¯å£ (bind函数返回了错误 %s)</translation>
</message>
@@ -951,6 +1149,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">无法创建PID文件'%s': %s</translation>
</message>
<message>
+ <source>Unable to find UTXO for external input</source>
+ <translation type="unfinished">无法为外部输入找到UTXO</translation>
+ </message>
+ <message>
<source>Unable to generate initial keys</source>
<translation type="unfinished">无法生æˆåˆå§‹å¯†é’¥</translation>
</message>
@@ -963,10 +1165,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">无法打开%s用于写入</translation>
</message>
<message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">æ— æ³•è§£æž -maxuploadtarget: '%s'</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">无法å¯åŠ¨HTTPæœåŠ¡ï¼ŒæŸ¥çœ‹æ—¥å¿—获å–更多信æ¯</translation>
</message>
<message>
+ <source>Unable to unload the wallet before migrating</source>
+ <translation type="unfinished">在è¿ç§»å‰æ— æ³•å¸è½½é’±åŒ…</translation>
+ </message>
+ <message>
<source>Unknown -blockfilterindex value %s.</source>
<translation type="unfinished">未知的 -blockfilterindex 数值 %s。</translation>
</message>
@@ -987,12 +1197,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ä¸æ˜Žçš„交易规则已ç»æ¿€æ´» (versionbit %i)</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">ä¸æ”¯æŒçš„日志分类 %s=%s。</translation>
+ <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
+ <translation type="unfinished">ä¸æ”¯æŒçš„全局日志等级 -loglevel=%s 。有效的数值:%s 。</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">正在å‡çº§UTXOæ•°æ®åº“</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">ä¸æ”¯æŒçš„日志分类 %s=%s。</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
@@ -1062,6 +1272,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">创建一个新的钱包</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">最å°åŒ–(&amp;M)</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">钱包:</translation>
</message>
@@ -1209,7 +1423,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>已处ç†%n个区å—的交易历å²ã€‚</numerusform>
</translation>
</message>
<message>
@@ -1249,6 +1463,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">加载部分签å比特å¸äº¤æ˜“(PSBT)</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">从剪贴æ¿åŠ è½½PSBT(&amp;C)...</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">从剪贴æ¿ä¸­åŠ è½½éƒ¨åˆ†ç­¾å比特å¸äº¤æ˜“(PSBT)</translation>
</message>
@@ -1285,6 +1503,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">å¸è½½é’±åŒ…</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">从备份文件æ¢å¤é’±åŒ…</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">关闭所有钱包</translation>
</message>
@@ -1309,6 +1537,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">没有å¯ç”¨çš„钱包</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">钱包数æ®</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">加载钱包备份</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">钱包å称</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation type="unfinished">窗å£(&amp;W)</translation>
</message>
@@ -1324,11 +1572,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 客户端</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">éšè—(&amp;H)</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">显示(&amp;H)</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n æ¡åˆ°æ¯”特å¸ç½‘络的活动连接</numerusform>
</translation>
</message>
<message>
@@ -1352,6 +1608,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">å¯ç”¨ç½‘络活动</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">预åŒæ­¥åŒºå—头 (%1%)…</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">错误: %1</translation>
</message>
@@ -1522,6 +1782,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">å¤åˆ¶é‡‘é¢(&amp;A)</translation>
</message>
<message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">å¤åˆ¶äº¤æ˜“&amp;ID和输出åºå·</translation>
+ </message>
+ <message>
<source>L&amp;ock unspent</source>
<translation type="unfinished">é”定未花费(&amp;O)</translation>
</message>
@@ -1610,6 +1874,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">无法列出签å器</translation>
</message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">找到的外部签å器太多</translation>
+ </message>
+</context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">加载钱包</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">加载钱包...</translation>
+ </message>
</context>
<context>
<name>OpenWalletActivity</name>
@@ -1637,6 +1918,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…&lt;b&gt;%1&lt;/b&gt;…</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…失败</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…警告</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">æ¢å¤é’±åŒ…消æ¯</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1815,13 +2124,23 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Bitcoin</source>
<translation type="unfinished">比特å¸</translation>
</message>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(éœ€è¦ %1 GB)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>å¯ç”¨ç©ºé—´ %n GB</numerusform>
+ </translation>
</message>
- <message>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished">(完整区å—é“¾éœ€è¦ %1 GB)</translation>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(éœ€è¦ %n GB的空间)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(ä¿å­˜å®Œæ•´çš„é“¾éœ€è¦ %n GB)</numerusform>
+ </translation>
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
@@ -1835,7 +2154,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(足以æ¢å¤ %n 天之内的备份)</numerusform>
</translation>
</message>
<message>
@@ -1867,10 +2186,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">由于这是第一次å¯åŠ¨æ­¤ç¨‹åºï¼Œæ‚¨å¯ä»¥é€‰æ‹©%1存储数æ®çš„ä½ç½®</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 type="unfinished">当你å•å‡»ç¡®è®¤åŽï¼Œ%1 将会在 %4 å¯åŠ¨æ—¶ä»Ž %3 中最早的交易开始,下载并处ç†å®Œæ•´çš„ %4 区å—链 (%2GB)。</translation>
- </message>
- <message>
<source>Limit block chain storage to</source>
<translation type="unfinished">将区å—链存储é™åˆ¶åˆ°</translation>
</message>
@@ -1883,6 +2198,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">åˆå§‹åŒ–åŒæ­¥è¿‡ç¨‹æ˜¯éžå¸¸åƒåŠ›çš„,åŒæ—¶å¯èƒ½ä¼šæš´éœ²æ‚¨ä¹‹å‰æ²¡æœ‰æ³¨æ„到的电脑硬件问题。你æ¯æ¬¡å¯åŠ¨%1时,它都会从之å‰ä¸­æ–­çš„地方继续下载。</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">当你å•å‡»ç¡®è®¤åŽï¼Œ%1 将会从%4在%3年创始时最早的交易开始,下载并处ç†å®Œæ•´çš„ %4 区å—链 (%2 GB)。</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 type="unfinished">如果你选择é™åˆ¶åŒºå—链存储大å°ï¼ˆåŒºå—链è£å‰ªæ¨¡å¼ï¼‰ï¼Œç¨‹åºä¾ç„¶ä¼šä¸‹è½½å¹¶å¤„ç†å…¨éƒ¨åŽ†å²æ•°æ®ï¼Œåªæ˜¯ä¸å¿…须的部分会在使用åŽè¢«åˆ é™¤ï¼Œä»¥å ç”¨æœ€å°‘的存储空间。</translation>
</message>
@@ -1975,6 +2294,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">未知。åŒæ­¥åŒºå—头(%1, %2%)...</translation>
</message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">未知。预åŒæ­¥åŒºå—头 (%1, %2%)…</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -2031,6 +2354,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">窗å£è¢«å…³é—­æ—¶æœ€å°åŒ–程åºè€Œä¸æ˜¯é€€å‡ºã€‚当此选项å¯ç”¨æ—¶ï¼Œåªæœ‰åœ¨èœå•ä¸­é€‰æ‹©â€œé€€å‡ºâ€æ—¶æ‰ä¼šè®©ç¨‹åºé€€å‡ºã€‚</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">这个对è¯æ¡†ä¸­çš„设置已被如下命令行选项覆盖:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">从工作目录下打开é…置文件 %1。</translation>
</message>
@@ -2059,14 +2386,44 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">警告:还原此设置需è¦é‡æ–°ä¸‹è½½æ•´ä¸ªåŒºå—链。</translation>
</message>
<message>
+ <source>Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
+ <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment>
+ <translation type="unfinished">æ•°æ®åº“缓存的最大大å°ã€‚加大缓存有助于加快åŒæ­¥ï¼Œä½†å¯¹äºŽå¤§å¤šæ•°ä½¿ç”¨åœºæ™¯æ¥è¯´ï¼Œç»§ç»­åŠ å¤§åŽæ”¶æ•ˆä¼šè¶Šæ¥è¶Šä¸æ˜Žæ˜¾ã€‚é™ä½Žç¼“存大å°å°†ä¼šå‡å°å†…存使用é‡ã€‚内存池中尚未被使用的那部分内存也会被共享用于这里的数æ®åº“缓存。</translation>
+ </message>
+ <message>
+ <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
+ <extracomment>Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</extracomment>
+ <translation type="unfinished">设置脚本验è¯çº¿ç¨‹çš„æ•°é‡ã€‚负值则表示你想è¦ä¿ç•™ç»™ç³»ç»Ÿçš„核心数é‡ã€‚</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished">(0 = 自动, &lt;0 = ä¿æŒæŒ‡å®šæ•°é‡çš„CPU核心空闲)</translation>
</message>
<message>
+ <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
+ <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment>
+ <translation type="unfinished">è¿™å…许作为用户的你或第三方工具通过命令行和JSON-RPC命令行与节点通信。</translation>
+ </message>
+ <message>
+ <source>Enable R&amp;PC server</source>
+ <extracomment>An Options window setting to enable the RPC server.</extracomment>
+ <translation type="unfinished">å¯ç”¨R&amp;PCæœåŠ¡å™¨</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation type="unfinished">钱包(&amp;A)</translation>
</message>
<message>
+ <source>Whether to set subtract fee from amount as default or not.</source>
+ <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">是å¦è¦é»˜è®¤ä»Žé‡‘é¢ä¸­å‡åŽ»æ‰‹ç»­è´¹ã€‚</translation>
+ </message>
+ <message>
+ <source>Subtract &amp;fee from amount by default</source>
+ <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment>
+ <translation type="unfinished">默认从金é¢ä¸­å‡åŽ»äº¤æ˜“手续费(&amp;F)</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation type="unfinished">专家</translation>
</message>
@@ -2083,6 +2440,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">动用尚未确认的找零资金(&amp;S)</translation>
</message>
<message>
+ <source>Enable &amp;PSBT controls</source>
+ <extracomment>An options window setting to enable PSBT controls.</extracomment>
+ <translation type="unfinished">å¯ç”¨&amp;PSBT控件</translation>
+ </message>
+ <message>
+ <source>Whether to show PSBT controls.</source>
+ <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment>
+ <translation type="unfinished">是å¦è¦æ˜¾ç¤ºPSBT控件</translation>
+ </message>
+ <message>
<source>External Signer (e.g. hardware wallet)</source>
<translation type="unfinished">外部签å器(例如硬件钱包)</translation>
</message>
@@ -2187,6 +2554,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">选择显示åŠå‘é€æ¯”特å¸æ—¶ä½¿ç”¨çš„最å°å•ä½ã€‚</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 type="unfinished">这个第三方网å€ï¼ˆæ¯”如区å—æµè§ˆå™¨ï¼‰ä¼šå‡ºçŽ°åœ¨äº¤æ˜“选项å¡çš„å³é”®èœå•ä¸­ã€‚ 网å€ä¸­çš„%s代表交易哈希。多个网å€éœ€è¦ç”¨ç«–线 | 相互分隔。</translation>
+ </message>
+ <message>
+ <source>&amp;Third-party transaction URLs</source>
+ <translation type="unfinished">第三方交易网å€(&amp;T)</translation>
+ </message>
+ <message>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished">是å¦æ˜¾ç¤ºæ‰‹åŠ¨é€‰å¸åŠŸèƒ½ã€‚</translation>
</message>
@@ -2204,17 +2579,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>embedded "%1"</source>
- <translation type="unfinished">嵌入了 “%1â€</translation>
+ <translation type="unfinished">嵌入的 "%1"</translation>
</message>
<message>
<source>closest matching "%1"</source>
<translation type="unfinished">与 "%1" 最接近的匹é…</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">这个对è¯æ¡†ä¸­çš„设置已被如下命令行选项或é…置文件项覆盖:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">确定(&amp;O)</translation>
</message>
@@ -2237,14 +2608,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">确认æ¢å¤é»˜è®¤è®¾ç½®</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">需è¦é‡å¯å®¢æˆ·ç«¯æ‰èƒ½ä½¿æ›´æ”¹ç”Ÿæ•ˆã€‚</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">当å‰è®¾ç½®å°†ä¼šè¢«å¤‡ä»½åˆ° "%1"。</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">客户端å³å°†å…³é—­ï¼Œæ‚¨æƒ³ç»§ç»­å—?</translation>
</message>
<message>
@@ -2258,6 +2637,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">é…置文件å¯ä»¥ç”¨æ¥è®¾ç½®é«˜çº§é€‰é¡¹ã€‚é…置文件会覆盖设置界é¢çª—å£ä¸­çš„选项。此外,命令行会覆盖é…置文件指定的选项。</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">继续</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">å–消</translation>
</message>
@@ -2279,6 +2662,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">无法读å–设置 "%1",%2。</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
@@ -2392,6 +2782,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">ç­¾å交易失败: %1</translation>
</message>
<message>
+ <source>Cannot sign inputs while wallet is locked.</source>
+ <translation type="unfinished">钱包已é”定,无法签å交易输入项。</translation>
+ </message>
+ <message>
<source>Could not sign any more inputs.</source>
<translation type="unfinished">没有交易输入项å¯ä¾›ç­¾å了。</translation>
</message>
@@ -2465,6 +2859,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">交易ä»ç„¶éœ€è¦ç­¾å。</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(但没有加载钱包。)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(但这个钱包ä¸èƒ½ç­¾å交易)</translation>
</message>
@@ -2529,6 +2927,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">节点</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">连接时间</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">æ–¹å‘</translation>
@@ -2716,6 +3119,10 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">å·²åŒæ­¥åŒºå—</translation>
</message>
<message>
+ <source>Last Transaction</source>
+ <translation type="unfinished">最近交易</translation>
+ </message>
+ <message>
<source>The mapped Autonomous System used for diversifying peer selection.</source>
<translation type="unfinished">映射到的自治系统,被用æ¥å¤šæ ·åŒ–选择节点</translation>
</message>
@@ -2724,6 +3131,36 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">映射到的AS</translation>
</message>
<message>
+ <source>Whether we relay addresses to this peer.</source>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">是å¦æŠŠåœ°å€è½¬å‘给这个节点。</translation>
+ </message>
+ <message>
+ <source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
+ <translation type="unfinished">地å€è½¬å‘</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">从这个节点接收并处ç†è¿‡çš„地å€æ€»æ•°ï¼ˆé™¤åŽ»å› é¢‘次é™åˆ¶è€Œä¸¢å¼ƒçš„那些地å€ï¼‰ã€‚</translation>
+ </message>
+ <message>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">从这个节点接收åŽåˆå› é¢‘次é™åˆ¶è€Œä¸¢å¼ƒï¼ˆæœªè¢«å¤„ç†ï¼‰çš„地å€æ€»æ•°ã€‚</translation>
+ </message>
+ <message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">已处ç†åœ°å€</translation>
+ </message>
+ <message>
+ <source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
+ <translation type="unfinished">被频率é™åˆ¶ä¸¢å¼ƒçš„地å€</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">用户代ç†</translation>
</message>
@@ -2932,6 +3369,11 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">1 å¹´(&amp;Y)</translation>
</message>
<message>
+ <source>&amp;Copy IP/Netmask</source>
+ <extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
+ <translation type="unfinished">å¤åˆ¶IP/网络掩ç (&amp;C)</translation>
+ </message>
+ <message>
<source>&amp;Unban</source>
<translation type="unfinished">解å°(&amp;U)</translation>
</message>
@@ -3460,6 +3902,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">请务必仔细检查您的交易请求。这会产生一个部分签å比特å¸äº¤æ˜“(PSBT),å¯ä»¥æŠŠä¿å­˜ä¸‹æ¥æˆ–å¤åˆ¶å‡ºåŽ»ï¼Œç„¶åŽå°±å¯ä»¥å¯¹å®ƒè¿›è¡Œç­¾å,比如用离线%1钱包,或是用兼容PSBT的硬件钱包。</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">è¦åˆ›å»ºè¿™ç¬”交易å—?</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
+ <extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</extracomment>
+ <translation type="unfinished">请务必仔细检查您的交易。你å¯ä»¥åˆ›å»ºå¹¶å‘é€è¿™ç¬”交易;也å¯ä»¥åˆ›å»ºä¸€ä¸ªâ€œéƒ¨åˆ†ç­¾å比特å¸äº¤æ˜“(PSBT)â€ï¼Œå®ƒå¯ä»¥è¢«ä¿å­˜ä¸‹æ¥æˆ–被å¤åˆ¶å‡ºåŽ»ï¼Œç„¶åŽå°±å¯ä»¥å¯¹å®ƒè¿›è¡Œç­¾å,比如用离线%1钱包,或是用兼容PSBT的硬件钱包。</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">请检查您的交易。</translation>
@@ -3512,14 +3964,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">超过 %1 的手续费被视为高得离谱。</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">支付请求已过期。</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>预计%n个区å—内确认。</numerusform>
</translation>
</message>
<message>
@@ -3594,14 +4042,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">消æ¯:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">这是一个未ç»éªŒè¯çš„支付请求。</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">这是一个已ç»éªŒè¯çš„支付请求。</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">请为此地å€è¾“入一个标签以将它加入已用地å€åˆ—表</translation>
</message>
@@ -3609,14 +4049,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<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 type="unfinished">bitcoin: URI 附带的备注信æ¯ï¼Œå°†ä¼šå’Œäº¤æ˜“一起存储,备查。 注æ„:该消æ¯ä¸ä¼šé€šè¿‡æ¯”特å¸ç½‘络传输。</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">支付给:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">附言:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3689,7 +4121,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
</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 type="unfinished">请在下é¢è¾“入接收者地å€ã€æ¶ˆæ¯ï¼ˆç¡®ä¿æ¢è¡Œç¬¦ã€ç©ºæ ¼ç¬¦ã€åˆ¶è¡¨ç¬¦ç­‰å®Œå…¨ç›¸åŒï¼‰å’Œç­¾å以验è¯æ¶ˆæ¯ã€‚请仔细核对签åä¿¡æ¯ï¼Œä»¥æ防中间人攻击。请注æ„,这åªæ˜¯è¯æ˜ŽæŽ¥æ”¶æ–¹å¯ä»¥ç”¨è¿™ä¸ªåœ°å€ç­¾å,它ä¸èƒ½è¯æ˜Žä»»ä½•äº¤æ˜“ï¼</translation>
+ <translation type="unfinished">请在下é¢è¾“入接收者地å€ã€æ¶ˆæ¯ï¼ˆç¡®ä¿æ¢è¡Œç¬¦ã€ç©ºæ ¼ç¬¦ã€åˆ¶è¡¨ç¬¦ç­‰å®Œå…¨ç›¸åŒï¼‰å’Œç­¾å以验è¯æ¶ˆæ¯ã€‚请仔细核对签åä¿¡æ¯ï¼Œä»¥æ防中间人攻击。请注æ„,这åªæ˜¯è¯æ˜ŽæŽ¥æ”¶æ–¹å¯ä»¥ç”¨è¿™ä¸ªåœ°å€ç­¾å,它ä¸èƒ½è¯æ˜Žä»»ä½•äº¤æ˜“çš„å‘é€äººèº«ä»½ï¼</translation>
</message>
<message>
<source>The Bitcoin address the message was signed with</source>
@@ -3778,35 +4210,41 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<source>(press q to shutdown and continue later)</source>
<translation type="unfinished">(按q退出并在以åŽç»§ç»­)</translation>
</message>
- </context>
+ <message>
+ <source>press q to shutdown</source>
+ <translation type="unfinished">按q键关闭并退出</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">与一个有 %1 个确认的交易冲çª</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0/未确认,%1</translation>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
+ <translation type="unfinished">0/未确认,在内存池中</translation>
</message>
<message>
- <source>in memory pool</source>
- <translation type="unfinished">在内存池中</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">ä¸åœ¨å†…存池中</translation>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
+ <translation type="unfinished">0/未确认,ä¸åœ¨å†…存池中</translation>
</message>
<message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">已丢弃</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1/未确认</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">%1 个确认</translation>
</message>
<message>
@@ -3856,7 +4294,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>在%n个区å—内æˆç†Ÿ</numerusform>
</translation>
</message>
<message>
@@ -4153,6 +4591,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos
<translation type="unfinished">编辑地å€æ ‡ç­¾(&amp;E)</translation>
</message>
<message>
+ <source>Show in %1</source>
+ <extracomment>Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</extracomment>
+ <translation type="unfinished">在 %1中显示</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">导出交易历å²</translation>
</message>
diff --git a/src/qt/locale/bitcoin_zh_HK.ts b/src/qt/locale/bitcoin_zh_HK.ts
index eff1971a9c..b6b5c2fe8c 100644
--- a/src/qt/locale/bitcoin_zh_HK.ts
+++ b/src/qt/locale/bitcoin_zh_HK.ts
@@ -499,6 +499,24 @@
<context>
<name>Intro</name>
<message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts
index 229e1ce8ce..e7411eb18b 100644
--- a/src/qt/locale/bitcoin_zh_TW.ts
+++ b/src/qt/locale/bitcoin_zh_TW.ts
@@ -35,7 +35,7 @@
</message>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">匯出(&amp;E)</translation>
+ <translation type="unfinished">&amp;匯出</translation>
</message>
<message>
<source>&amp;Delete</source>
@@ -50,6 +50,10 @@
<translation type="unfinished">é¸æ“‡è¦æŽ¥æ”¶å¹£çš„地å€</translation>
</message>
<message>
+ <source>C&amp;hoose</source>
+ <translation type="unfinished">é¸æ“‡ (&amp;h)</translation>
+ </message>
+ <message>
<source>Sending addresses</source>
<translation type="unfinished">發é€åœ°å€</translation>
</message>
@@ -168,7 +172,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Enter the new passphrase for 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 type="unfinished">輸入錢包的新密碼短語。&lt;br/&gt;請使用&lt;b&gt;個或10個以上隨機字符&lt;/b&gt;或&lt;b&gt;個8個以上單詞3的密碼。</translation>
+ <translation type="unfinished">輸入錢包的新密碼短語。&lt;br/&gt;請使用&lt;b&gt;個或10個以上隨機字符&lt;/b&gt;或&lt;b&gt;個8個以上單詞&lt;/b&gt;的密碼。</translation>
</message>
<message>
<source>Enter the old passphrase and new passphrase for the wallet.</source>
@@ -237,13 +241,35 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">設定檔%1å¯èƒ½å·²ç¶“失效或無效</translation>
+ </message>
+ <message>
+ <source>Runaway exception</source>
+ <translation type="unfinished">失控異常</translation>
+ </message>
+ <message>
<source>Internal error</source>
<translation type="unfinished">內部錯誤</translation>
</message>
- </context>
+ <message>
+ <source>An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
+ <translation type="unfinished">發生了內部錯誤%1 將嘗試安全地繼續。 這是一個æ„外錯誤,å¯ä»¥æŒ‰å¦‚下所述進行報告。</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
+ <source>Do you want to reset settings to default values, or to abort without making changes?</source>
+ <extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
+ <translation type="unfinished">您想將設置é‡ç½®ç‚ºé è¨­å€¼ï¼Œé‚„是在ä¸é€²è¡Œæ›´æ”¹çš„情æ³ä¸‹ä¸­æ­¢ï¼Ÿ</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">發生致命錯誤。檢查設置文件是å¦å¯å¯«å…¥ï¼Œæˆ–嘗試é‹è¡Œ -nosettings</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">错误:指定的数æ®ç›®å½•â€œ%1â€ä¸å­˜åœ¨ã€‚</translation>
</message>
@@ -256,6 +282,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">错误:%1</translation>
</message>
<message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1還沒有安全退出……</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation type="unfinished">未知</translation>
</message>
@@ -268,6 +298,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">輸入 æ¯”ç‰¹å¹£åœ°å€ (比如說 %1)</translation>
</message>
<message>
+ <source>Unroutable</source>
+ <translation type="unfinished">ä¸å¯è·¯ç”±</translation>
+ </message>
+ <message>
<source>Inbound</source>
<extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
<translation type="unfinished">進來</translation>
@@ -361,6 +395,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">設定檔案無法讀å–</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">設定檔案無法寫入</translation>
+ </message>
+ <message>
<source>The %s developers</source>
<translation type="unfinished">%s 開發人員</translation>
</message>
@@ -381,10 +423,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">讀å–錢包檔 %s 時發生錯誤ï¼æ‰€æœ‰çš„鑰匙都正確讀å–了,但是交易資料或地å€ç°¿è³‡æ–™å¯èƒ½æœƒç¼ºå°‘或ä¸æ­£ç¢ºã€‚</translation>
</message>
<message>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished">錯誤: è½å€™å¤–來連線失敗(回傳錯誤 %s)</translation>
- </message>
- <message>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished">計算é ä¼°æ‰‹çºŒè²»å¤±æ•—了,也沒有備用手續費(fallbackfee)å¯ç”¨ã€‚è«‹å†å¤šç­‰å¾…幾個å€å¡Šï¼Œæˆ–是啟用 -fallbackfee åƒæ•¸ã€‚</translation>
</message>
@@ -541,10 +579,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">讀å–資料庫時發生錯誤,è¦é—œé–‰äº†ã€‚</translation>
</message>
<message>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished">å‡ç´šå€å¡Šéˆç‹€æ…‹è³‡æ–™åº«æ™‚發生錯誤</translation>
- </message>
- <message>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished">错误: %s 所在的ç£ç›˜ç©ºé—´ä½Žã€‚</translation>
</message>
@@ -561,6 +595,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">åˆå§‹åŒ–時é‡æ–°æŽƒæ錢包失敗了</translation>
</message>
<message>
+ <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source>
+ <translation type="unfinished">手續費費率(%s) 低於最低費率設置(%s)</translation>
+ </message>
+ <message>
+ <source>Importing…</source>
+ <translation type="unfinished">匯入中...</translation>
+ </message>
+ <message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
<translation type="unfinished">創世å€å¡Šä¸æ­£ç¢ºæˆ–找ä¸åˆ°ã€‚資料目錄錯了嗎?</translation>
</message>
@@ -569,6 +611,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">åˆå§‹åŒ–時的基本檢查失敗了。%s å°±è¦é—œé–‰äº†ã€‚</translation>
</message>
<message>
+ <source>Input not found or already spent</source>
+ <translation type="unfinished">找ä¸åˆ°äº¤æ˜“項,或å¯èƒ½å·²ç¶“花掉了</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation type="unfinished">ç´¯ç©é‡‘é¡ä¸è¶³</translation>
</message>
@@ -586,31 +632,55 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">åƒæ•¸ -%s=&lt;金é¡&gt; 指定的金é¡ç„¡æ•ˆ: '%s'</translation>
+ <translation type="unfinished">無效金é¡çµ¦ -%s=&lt;amount&gt;:'%s'</translation>
</message>
<message>
<source>Invalid amount for -discardfee=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">設定 -discardfee=&lt;金é¡&gt; 的金é¡ç„¡æ•ˆ: '%s'</translation>
+ <translation type="unfinished">無效金é¡çµ¦ -丟棄費=&lt;amount&gt;; '%s' </translation>
</message>
<message>
<source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
- <translation type="unfinished">設定 -fallbackfee=&lt;金é¡&gt; 的金é¡ç„¡æ•ˆ: '%s'</translation>
+ <translation type="unfinished">無效金é¡çµ¦ -後備費用=&lt;amount&gt;: '%s'</translation>
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
- <translation type="unfinished">設定 -paytxfee=&lt;金é¡&gt; 的金é¡ç„¡æ•ˆ: '%s' (至少è¦æœ‰ %s)</translation>
+ <translation type="unfinished">無效金é¡çµ¦ -支付費用&lt;amount&gt;:'%s' (必須至少%s)</translation>
</message>
<message>
<source>Invalid netmask specified in -whitelist: '%s'</source>
<translation type="unfinished">指定在 -whitelist 的網段無效: '%s'</translation>
</message>
<message>
+ <source>Loading P2P addresses…</source>
+ <translation type="unfinished">載入P2P地å€ä¸­...</translation>
+ </message>
+ <message>
+ <source>Loading banlist…</source>
+ <translation type="unfinished">正在載入黑å單中...</translation>
+ </message>
+ <message>
+ <source>Loading block index…</source>
+ <translation type="unfinished">載入å€å¡Šç´¢å¼•ä¸­...</translation>
+ </message>
+ <message>
+ <source>Loading wallet…</source>
+ <translation type="unfinished">載入錢包中...</translation>
+ </message>
+ <message>
+ <source>Missing amount</source>
+ <translation type="unfinished">缺少金é¡</translation>
+ </message>
+ <message>
+ <source>Missing solving data for estimating transaction size</source>
+ <translation type="unfinished">缺少用於估計交易è¦æ¨¡çš„求解數據</translation>
+ </message>
+ <message>
<source>Need to specify a port with -whitebind: '%s'</source>
<translation type="unfinished">指定 -whitebind 時必須包å«é€šè¨ŠåŸ : '%s'</translation>
</message>
<message>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished">未指定代ç†ä¼ºæœå™¨ã€‚使用-proxy = &lt;ip&gt;或-proxy = &lt;ip:port&gt;。</translation>
+ <source>No addresses available</source>
+ <translation type="unfinished">沒有å¯ç”¨çš„地å€</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -625,10 +695,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">修剪模å¼å’Œ -txindex åƒæ•¸ä¸ç›¸å®¹ã€‚</translation>
</message>
<message>
+ <source>Pruning blockstore…</source>
+ <translation type="unfinished">修剪å€å¡Šè³‡æ–™åº«ä¸­...</translation>
+ </message>
+ <message>
<source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
<translation type="unfinished">因為系統的é™åˆ¶ï¼Œå°‡ -maxconnections åƒæ•¸å¾ž %d é™åˆ°äº† %d</translation>
</message>
<message>
+ <source>Replaying blocks…</source>
+ <translation type="unfinished">正在å°å€å¡Šé€²è¡Œé‡æ–°è¨ˆç®—...</translation>
+ </message>
+ <message>
+ <source>Rescanning…</source>
+ <translation type="unfinished">é‡æ–°æŽƒæ中...</translation>
+ </message>
+ <message>
<source>Section [%s] is not recognized.</source>
<translation type="unfinished">无法识别é…置章节 [%s]。</translation>
</message>
@@ -653,10 +735,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">指定的å€å¡Šç›®éŒ„ "%s" ä¸å­˜åœ¨ã€‚</translation>
</message>
<message>
+ <source>Starting network threads…</source>
+ <translation type="unfinished">正在開始網路線程...</translation>
+ </message>
+ <message>
<source>The source code is available from %s.</source>
<translation type="unfinished">原始碼å¯ä»¥åœ¨ %s å–得。</translation>
</message>
<message>
+ <source>The specified config file %s does not exist</source>
+ <translation type="unfinished">這個指定的é…置檔案%sä¸å­˜åœ¨</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to pay the fee</source>
<translation type="unfinished">交易金é¡å¤ªå°‘而付ä¸èµ·æ‰‹çºŒè²»</translation>
</message>
@@ -685,6 +775,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">交易金é¡ä¸èƒ½æ˜¯è² çš„</translation>
</message>
<message>
+ <source>Transaction change output index out of range</source>
+ <translation type="unfinished">交易尋找零輸出項超出範åœ</translation>
+ </message>
+ <message>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished">交易造æˆè¨˜æ†¶æ± ä¸­çš„交易éˆå¤ªé•·</translation>
</message>
@@ -693,6 +787,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">交易必須至少有一個收款人</translation>
</message>
<message>
+ <source>Transaction needs a change address, but we can't generate it.</source>
+ <translation type="unfinished">需è¦äº¤æ˜“一個找零地å€ï¼Œä½†æ˜¯æˆ‘們無法生æˆå®ƒã€‚</translation>
+ </message>
+ <message>
<source>Transaction too large</source>
<translation type="unfinished">交易ä½å…ƒé‡å¤ªå¤§</translation>
</message>
@@ -717,6 +815,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">沒辦法產生密鑰</translation>
</message>
<message>
+ <source>Unable to open %s for writing</source>
+ <translation type="unfinished">無法開啟%s來寫入</translation>
+ </message>
+ <message>
+ <source>Unable to parse -maxuploadtarget: '%s'</source>
+ <translation type="unfinished">無法解æž-最大上傳目標:'%s'</translation>
+ </message>
+ <message>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished">無法啟動 HTTP 伺æœå™¨ã€‚詳情請看除錯紀錄。</translation>
</message>
@@ -737,18 +843,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">在 -onlynet 指定了ä¸æ˜Žçš„網路別: '%s'</translation>
</message>
<message>
- <source>Unsupported logging category %s=%s.</source>
- <translation type="unfinished">ä¸æ”¯æ´çš„紀錄類別 %s=%s。</translation>
+ <source>Unknown new rules activated (versionbit %i)</source>
+ <translation type="unfinished">未知的交易已經有新è¦å‰‡æ¿€æ´» (versionbit %i)</translation>
</message>
<message>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished">正在å‡ç´š UTXO 資料庫</translation>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished">ä¸æ”¯æ´çš„紀錄類別 %s=%s。</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished">使用者代ç†è¨»è§£(%s)中å«æœ‰ä¸å®‰å…¨çš„字元。</translation>
</message>
<message>
+ <source>Verifying blocks…</source>
+ <translation type="unfinished">正在驗證å€å¡Šæ•¸æ“š...</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)…</source>
+ <translation type="unfinished">正在驗證錢包...</translation>
+ </message>
+ <message>
<source>Wallet needed to be rewritten: restart %s to complete</source>
<translation type="unfinished">錢包需è¦é‡å¯«: è«‹é‡æ–°å•“å‹• %s 來完æˆ</translation>
</message>
@@ -796,6 +910,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">創建一個新錢包</translation>
</message>
<message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;最å°åŒ–</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation type="unfinished">錢包:</translation>
</message>
@@ -829,18 +947,63 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">&amp;接收</translation>
</message>
<message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;é¸é …...</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;加密錢包...</translation>
+ </message>
+ <message>
<source>Encrypt the private keys that belong to your wallet</source>
<translation type="unfinished">將錢包中之密鑰加密</translation>
</message>
<message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;備用錢包</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;更改密碼短語...</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">ç°½å &amp;ä¿¡æ¯â€¦</translation>
+ </message>
+ <message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
<translation type="unfinished">用比特幣地å€ç°½å訊æ¯ä¾†è­‰æ˜Žä½å€æ˜¯ä½ çš„</translation>
</message>
<message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;é©—è­‰
+訊æ¯...</translation>
+ </message>
+ <message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
<translation type="unfinished">驗證訊æ¯æ˜¯ç”¨ä¾†ç¢ºå®šè¨Šæ¯æ˜¯ç”¨æŒ‡å®šçš„比特幣地å€ç°½åçš„</translation>
</message>
<message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">&amp;從檔案載入PSBT...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI…</source>
+ <translation type="unfinished">é–‹å•Ÿ &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">关钱包...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">创建钱包...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">关所有钱包...</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation type="unfinished">&amp;檔案</translation>
</message>
@@ -857,6 +1020,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">分é å·¥å…·åˆ—</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">åŒæ­¥å€å¡Šé ­ (%1%)…</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">正在與網絡åŒæ­¥â€¦</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">索引ç£ç›¤ä¸Šçš„索引塊中...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">處ç†ç£ç¢Ÿè£¡çš„å€å¡Šä¸­...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk…</source>
+ <translation type="unfinished">正在é‡æ–°ç´¢å¼•ç£ç›¤ä¸Šçš„å€å¡Š...</translation>
+ </message>
+ <message>
+ <source>Connecting to peers…</source>
+ <translation type="unfinished">连到åŒè¡Œ...</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished">è¦æ±‚付款(產生 QR Code å’Œ bitcoin 付款å”議的資æºè­˜åˆ¥ç¢¼: URI)</translation>
</message>
@@ -875,7 +1062,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>已處裡%n個å€å¡Šçš„交易紀錄</numerusform>
</translation>
</message>
<message>
@@ -883,6 +1070,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">è½å¾Œ %1</translation>
</message>
<message>
+ <source>Catching up…</source>
+ <translation type="unfinished">赶上...</translation>
+ </message>
+ <message>
<source>Last received block was generated %1 ago.</source>
<translation type="unfinished">最近收到的å€å¡Šæ˜¯åœ¨ %1 以å‰ç”Ÿå‡ºä¾†çš„。</translation>
</message>
@@ -911,6 +1102,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">載入部分簽å的比特幣交易</translation>
</message>
<message>
+ <source>Load PSBT from &amp;clipboard…</source>
+ <translation type="unfinished">從剪貼簿載入PSBT</translation>
+ </message>
+ <message>
<source>Load Partially Signed Bitcoin Transaction from clipboard</source>
<translation type="unfinished">從剪貼簿載入部分簽å的比特幣交易</translation>
</message>
@@ -947,6 +1142,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">關閉錢包</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">æ¢å¾©éŒ¢åŒ…...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">從備份檔案中æ¢å¾©éŒ¢åŒ…</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">關閉所有錢包</translation>
</message>
@@ -971,8 +1176,28 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">没有å¯ç”¨çš„钱包</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">錢包資料</translation>
+ </message>
+ <message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">載入錢包備份</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">æ¢å¾©éŒ¢åŒ…</translation>
+ </message>
+ <message>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished">錢包å稱</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
- <translation type="unfinished">視窗(&amp;W)</translation>
+ <translation type="unfinished">&amp;視窗</translation>
</message>
<message>
<source>Zoom</source>
@@ -986,14 +1211,46 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 client</source>
<translation type="unfinished">%1 客戶端</translation>
</message>
+ <message>
+ <source>&amp;Hide</source>
+ <translation type="unfinished">&amp;躲</translation>
+ </message>
+ <message>
+ <source>S&amp;how</source>
+ <translation type="unfinished">&amp;顯示</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>已處ç†%n個å€å¡Šçš„交易歷å²ã€‚</numerusform>
</translation>
</message>
<message>
+ <source>Click for more actions.</source>
+ <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment>
+ <translation type="unfinished">點擊查看更多æ“作</translation>
+ </message>
+ <message>
+ <source>Show Peers tab</source>
+ <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment>
+ <translation type="unfinished">顯示節點é¸é …å¡</translation>
+ </message>
+ <message>
+ <source>Disable network activity</source>
+ <extracomment>A context menu item.</extracomment>
+ <translation type="unfinished">關閉網路紀錄</translation>
+ </message>
+ <message>
+ <source>Enable network activity</source>
+ <extracomment>A context menu item. The network activity was disabled previously.</extracomment>
+ <translation type="unfinished">關閉網路紀錄</translation>
+ </message>
+ <message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">é å…ˆåŒæ­¥æ¨™é ­(%1%)</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">错误:%1</translation>
</message>
@@ -1152,6 +1409,30 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">複製金é¡</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;å¤åˆ¶åœ°å€</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">å¤åˆ¶å’Œæ ‡ç­¾</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">å¤åˆ¶å’Œæ•°é‡</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID and output index</source>
+ <translation type="unfinished">複製交易&amp;ID與輸出åºè™Ÿ</translation>
+ </message>
+ <message>
+ <source>L&amp;ock unspent</source>
+ <translation type="unfinished">鎖定未消費金é¡é¡</translation>
+ </message>
+ <message>
+ <source>&amp;Unlock unspent</source>
+ <translation type="unfinished">解鎖未花費金é¡</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation type="unfinished">複製數目</translation>
</message>
@@ -1216,6 +1497,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">新增錢包</translation>
</message>
<message>
+ <source>Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment>
+ <translation type="unfinished">正在創建錢包&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
<source>Create wallet failed</source>
<translation type="unfinished">創建錢包失敗&lt;br&gt;</translation>
</message>
@@ -1223,7 +1509,28 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Create wallet warning</source>
<translation type="unfinished">產生錢包警告:</translation>
</message>
- </context>
+ <message>
+ <source>Can't list signers</source>
+ <translation type="unfinished">無法列出簽å器</translation>
+ </message>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">åµæ¸¬åˆ°çš„外接簽å器éŽå¤š</translation>
+ </message>
+</context>
+<context>
+ <name>LoadWalletsActivity</name>
+ <message>
+ <source>Load Wallets</source>
+ <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
+ <translation type="unfinished">載入錢包</translation>
+ </message>
+ <message>
+ <source>Loading wallets…</source>
+ <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment>
+ <translation type="unfinished">正在載入錢包...</translation>
+ </message>
+</context>
<context>
<name>OpenWalletActivity</name>
<message>
@@ -1243,7 +1550,40 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<extracomment>Title of window indicating the progress of opening of a wallet.</extracomment>
<translation type="unfinished">打開錢包</translation>
</message>
- </context>
+ <message>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment>
+ <translation type="unfinished">正在打開錢包&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+</context>
+<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">æ¢å¾©éŒ¢åŒ…</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">正在æ¢å¾©éŒ¢åŒ…&lt;b&gt;%1&lt;/b&gt;...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">æ¢å¾©éŒ¢åŒ…失敗</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">æ¢å¾©éŒ¢åŒ…警告</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">æ¢å¾©éŒ¢åŒ…訊æ¯</translation>
+ </message>
+</context>
<context>
<name>WalletController</name>
<message>
@@ -1314,10 +1654,24 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">æ述符錢包</translation>
</message>
<message>
+ <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
+ <translation type="unfinished">使用外接簽åè£ç½®(例如: 實體錢包)。
+請先在設定é¸é …中設定好外接簽åè£ç½®ã€‚</translation>
+ </message>
+ <message>
+ <source>External signer</source>
+ <translation type="unfinished">外接簽åè£ç½®</translation>
+ </message>
+ <message>
<source>Create</source>
<translation type="unfinished">產生</translation>
</message>
- </context>
+ <message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">編譯時沒有外接簽å器支æ´(外接簽å必須有此功能)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -1394,6 +1748,24 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</context>
<context>
<name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform>%nGBå¯ç”¨</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(éœ€è¦ %n GB)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(完整å€å¡Šéˆéœ€è¦ï¼…n GB)</numerusform>
+ </translation>
+ </message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished">在這個目錄中至少會存放 %1 GB 的資料,並且還會隨時間增加。</translation>
@@ -1406,7 +1778,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(足以æ¢å¾©%n天內的備份)</numerusform>
</translation>
</message>
<message>
@@ -1438,18 +1810,26 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">因為這是程å¼ç¬¬ä¸€æ¬¡å•“動,你å¯ä»¥é¸æ“‡ %1 儲存資料的地方。</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 type="unfinished">在你按下「好ã€ä¹‹å¾Œï¼Œ%1 就會開始下載並處ç†æ•´å€‹ %4 å€å¡Šéˆ(大å°æ˜¯ %2GB),也就是從 %3 å¹´ %4 剛剛起步時的最åˆäº¤æ˜“開始。</translation>
+ <source>Limit block chain storage to</source>
+ <translation type="unfinished">å°‡å€å¡Šéˆå„²å­˜é™åˆ¶ç‚º</translation>
</message>
<message>
<source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<translation type="unfinished">還原此設置需è¦é‡æ–°ä¸‹è¼‰æ•´å€‹å€å¡Šéˆã€‚首先下載完整的éˆï¼Œç„¶å¾Œå†ä¿®å‰ªå®ƒæ˜¯æ›´å¿«çš„。ç¦ç”¨æŸäº›é«˜ç´šåŠŸèƒ½ã€‚</translation>
</message>
<message>
+ <source> GB</source>
+ <translation type="unfinished">GB</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 type="unfinished">一開始的åŒæ­¥ä½œæ¥­éžå¸¸çš„耗費資æºï¼Œä¸¦ä¸”å¯èƒ½æœƒæš´éœ²å‡ºä¹‹å‰æ²’被發ç¾çš„電腦硬體å•é¡Œã€‚æ¯æ¬¡åŸ·è¡Œ %1 的時候都會繼續先å‰æœªå®Œæˆçš„下載。</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">當你點擊「確èªã€ï¼Œ%1會開始下載,並從%3年最早的交易,處裡整個%4å€å¡Šéˆ(大å°:%2GB)</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 type="unfinished">如果你é¸æ“‡è¦é™åˆ¶å€å¡Šéˆå„²å­˜ç©ºé–“的大å°(修剪模å¼),還是需è¦ä¸‹è¼‰å’Œè™•ç†éŽåŽ»çš„æ­·å²è³‡æ–™è¢«ï¼Œä½†æ˜¯ä¹‹å¾Œå°±æœƒæŠŠå®ƒåˆªæŽ‰ä¾†ç¯€çœç£ç¢Ÿä½¿ç”¨é‡ã€‚</translation>
</message>
@@ -1480,6 +1860,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down…</source>
+ <translation type="unfinished">%1正在關機</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation type="unfinished">在這個視窗ä¸è¦‹ä»¥å‰ï¼Œè«‹ä¸è¦é—œæŽ‰é›»è…¦ã€‚</translation>
</message>
@@ -1503,6 +1887,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">剩餘å€å¡Šæ•¸</translation>
</message>
<message>
+ <source>Unknown…</source>
+ <translation type="unfinished">ä¸æ˜Ž...</translation>
+ </message>
+ <message>
+ <source>calculating…</source>
+ <translation type="unfinished">计算...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation type="unfinished">最近å€å¡Šæ™‚é–“</translation>
</message>
@@ -1526,7 +1918,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Esc</source>
<translation type="unfinished">離開éµ</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">ä¸æ˜Žã€‚正在åŒæ­¥æ¨™é ­(%1, %2%)...</translation>
+ </message>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">ä¸æ˜Žã€‚正在é å…ˆåŒæ­¥æ¨™é ­(%1, %2%)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -1675,7 +2075,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>&amp;Window</source>
- <translation type="unfinished">視窗(&amp;W)</translation>
+ <translation type="unfinished">&amp;視窗</translation>
</message>
<message>
<source>Show only a tray icon after minimizing the window.</source>
@@ -1722,10 +2122,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">使用個別的SOCKS&5代ç†ä»‹ç”±Tor onionæœå‹™åˆ°é”peers:</translation>
</message>
<message>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished">这个对è¯æ¡†ä¸­çš„设置已被如下命令行选项或é…置文件项覆盖:</translation>
- </message>
- <message>
<source>&amp;OK</source>
<translation type="unfinished">好(&amp;O)</translation>
</message>
@@ -1734,6 +2130,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">å–消(&amp;C)</translation>
</message>
<message>
+ <source>Compiled without external signing support (required for external signing)</source>
+ <extracomment>"External signing" means using devices such as hardware wallets.</extracomment>
+ <translation type="unfinished">編譯時沒有外接簽å器支æ´(外接簽å必須有此功能)</translation>
+ </message>
+ <message>
<source>default</source>
<translation type="unfinished">é è¨­å€¼</translation>
</message>
@@ -1743,14 +2144,17 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
<message>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation type="unfinished">確èªé‡è¨­é¸é …</translation>
</message>
<message>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
<translation type="unfinished">需è¦é‡æ–°é–‹å§‹å®¢æˆ¶ç«¯è»Ÿé«”來讓改變生效。</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">客戶端軟體就è¦é—œæŽ‰äº†ã€‚繼續åšä¸‹åŽ»å—Žï¼Ÿ</translation>
</message>
<message>
@@ -1764,6 +2168,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">設定檔å¯ä»¥ç”¨ä¾†æŒ‡å®šé€²éšŽçš„使用é¸é …,並且會覆蓋掉圖形介é¢çš„設定。ä¸éŽï¼Œå‘½ä»¤åˆ—çš„é¸é …也會覆蓋掉設定檔中的é¸é …。</translation>
</message>
<message>
+ <source>Continue</source>
+ <translation type="unfinished">继续</translation>
+ </message>
+ <message>
<source>Cancel</source>
<translation type="unfinished">å–消</translation>
</message>
@@ -1882,6 +2290,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">複製到剪貼簿</translation>
</message>
<message>
+ <source>Save…</source>
+ <translation type="unfinished">拯救...</translation>
+ </message>
+ <message>
<source>Close</source>
<translation type="unfinished">關閉</translation>
</message>
@@ -1990,6 +2402,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Ping 時間</translation>
</message>
<message>
+ <source>Peer</source>
+ <extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
+ <translation type="unfinished">åŒè¡Œ</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">æ–¹å‘</translation>
@@ -2276,6 +2693,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">去:</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <extracomment>Context menu action to copy the address of a peer.</extracomment>
+ <translation type="unfinished">&amp;å¤åˆ¶åœ°å€</translation>
+ </message>
+ <message>
<source>&amp;Disconnect</source>
<translation type="unfinished">æ–·ç·š(&amp;D)</translation>
</message>
@@ -2411,6 +2833,18 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">複製 &amp;URI</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;å¤åˆ¶åœ°å€</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">å¤åˆ¶å’Œæ ‡ç­¾</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">å¤åˆ¶å’Œæ•°é‡</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation type="unfinished">沒辦法把錢包解鎖。</translation>
</message>
@@ -2740,10 +3174,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished">高於 %1 的手續費會被èªç‚ºæ˜¯ä¸åˆç†ã€‚</translation>
</message>
- <message>
- <source>Payment request expired.</source>
- <translation type="unfinished">付款的è¦æ±‚éŽæœŸäº†ã€‚</translation>
- </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
@@ -2822,14 +3252,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">訊æ¯:</translation>
</message>
<message>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished">這是個沒有驗證éŽèº«ä»½çš„付款è¦æ±‚。</translation>
- </message>
- <message>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished">這是個已經驗證éŽèº«ä»½çš„付款è¦æ±‚。</translation>
- </message>
- <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished">請輸入這個地å€çš„標籤,來把它加進去已使用éŽåœ°å€æ¸…單。</translation>
</message>
@@ -2837,14 +3259,6 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<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 type="unfinished">附加在 Bitcoin 付款å”議的資æºè­˜åˆ¥ç¢¼(URI)中的訊æ¯ï¼Œæœƒå’Œäº¤æ˜“內容一起存起來,給你自己åšåƒè€ƒã€‚注æ„: 這個訊æ¯ä¸æœƒé€åˆ° Bitcoin 網路上。</translation>
</message>
- <message>
- <source>Pay To:</source>
- <translation type="unfinished">付給:</translation>
- </message>
- <message>
- <source>Memo:</source>
- <translation type="unfinished">備註:</translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
@@ -3011,30 +3425,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<name>TransactionDesc</name>
<message>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished">跟一個目å‰ç¢ºèª %1 次的交易互相è¡çª</translation>
</message>
<message>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished">0 次/未確èªï¼Œ%1</translation>
- </message>
- <message>
- <source>in memory pool</source>
- <translation type="unfinished">在記憶池中</translation>
- </message>
- <message>
- <source>not in memory pool</source>
- <translation type="unfinished">ä¸åœ¨è¨˜æ†¶æ± ä¸­</translation>
- </message>
- <message>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished">已中止</translation>
</message>
<message>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished">%1 次/未確èª</translation>
</message>
<message>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished">ç¢ºèª %1 次</translation>
</message>
<message>
@@ -3337,6 +3743,22 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">最å°é‡‘é¡</translation>
</message>
<message>
+ <source>&amp;Copy address</source>
+ <translation type="unfinished">&amp;å¤åˆ¶åœ°å€</translation>
+ </message>
+ <message>
+ <source>Copy &amp;label</source>
+ <translation type="unfinished">å¤åˆ¶å’Œæ ‡ç­¾</translation>
+ </message>
+ <message>
+ <source>Copy &amp;amount</source>
+ <translation type="unfinished">å¤åˆ¶å’Œæ•°é‡</translation>
+ </message>
+ <message>
+ <source>Copy transaction &amp;ID</source>
+ <translation type="unfinished">複製交易 &amp;ID</translation>
+ </message>
+ <message>
<source>Export Transaction History</source>
<translation type="unfinished">匯出交易記錄</translation>
</message>
@@ -3497,7 +3919,7 @@ Go to File &gt; Open Wallet to load a wallet.
<name>WalletView</name>
<message>
<source>&amp;Export</source>
- <translation type="unfinished">匯出(&amp;E)</translation>
+ <translation type="unfinished">&amp;匯出</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
@@ -3508,6 +3930,11 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished">備份錢包</translation>
</message>
<message>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished">錢包資料</translation>
+ </message>
+ <message>
<source>Backup Failed</source>
<translation type="unfinished">備份失敗</translation>
</message>
diff --git a/src/qt/locale/bitcoin_zu.ts b/src/qt/locale/bitcoin_zu.ts
index bcae817b16..6b8cc821c9 100644
--- a/src/qt/locale/bitcoin_zu.ts
+++ b/src/qt/locale/bitcoin_zu.ts
@@ -2,6 +2,18 @@
<context>
<name>AddressBookPage</name>
<message>
+ <source>&amp;New</source>
+ <translation type="unfinished">&amp;Okusha</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation type="unfinished">&amp;Kopisha</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation type="unfinished">Amakheli ukuthola</translation>
+ </message>
+ <message>
<source>Comma separated file</source>
<extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
<translation type="unfinished">Ifayela elehlukaniswe ngo khefana.</translation>
@@ -72,6 +84,13 @@
</message>
</context>
<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Error: Missing checksum</source>
+ <translation type="unfinished">Iphutha: iChecksum engekho</translation>
+ </message>
+ </context>
+<context>
<name>BitcoinGUI</name>
<message>
<source>&amp;Options…</source>
@@ -112,8 +131,8 @@
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
+ <numerusform>%n active connection(s) to Bitcoin network.</numerusform>
</translation>
</message>
<message>
@@ -133,7 +152,7 @@
<source>Can't list signers</source>
<translation type="unfinished">Akukwazi ukwenza uhlu lwabasayini.</translation>
</message>
-</context>
+ </context>
<context>
<name>CreateWalletDialog</name>
<message>
@@ -143,9 +162,26 @@
</context>
<context>
<name>Intro</name>
- <message>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished">(ku %1 GB odingakalayo)</translation>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ </translation>
</message>
<message numerus="yes">
<source>(sufficient to restore backups %n day(s) old)</source>
@@ -166,6 +202,10 @@
</context>
<context>
<name>SendCoinsDialog</name>
+ <message>
+ <source>Sign failed</source>
+ <translation type="unfinished">Uphawu lwehlulekile</translation>
+ </message>
<message numerus="yes">
<source>Estimated to begin confirmation within %n block(s).</source>
<translation type="unfinished">
diff --git a/src/qt/main.cpp b/src/qt/main.cpp
index e8f39584ad..c84dd78b44 100644
--- a/src/qt/main.cpp
+++ b/src/qt/main.cpp
@@ -1,12 +1,12 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <qt/bitcoin.h>
+#include <common/url.h>
#include <compat/compat.h>
#include <util/translation.h>
-#include <util/url.h>
#include <QCoreApplication>
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp
index dfa33764f6..b09e230bce 100644
--- a/src/qt/modaloverlay.cpp
+++ b/src/qt/modaloverlay.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,13 +12,10 @@
#include <QPropertyAnimation>
#include <QResizeEvent>
-ModalOverlay::ModalOverlay(bool enable_wallet, QWidget *parent) :
-QWidget(parent),
-ui(new Ui::ModalOverlay),
-bestHeaderHeight(0),
-bestHeaderDate(QDateTime()),
-layerIsVisible(false),
-userClosed(false)
+ModalOverlay::ModalOverlay(bool enable_wallet, QWidget* parent)
+ : QWidget(parent),
+ ui(new Ui::ModalOverlay),
+ bestHeaderDate(QDateTime())
{
ui->setupUi(this);
connect(ui->closeButton, &QPushButton::clicked, this, &ModalOverlay::closeClicked);
diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h
index 682c94cd01..40e487b249 100644
--- a/src/qt/modaloverlay.h
+++ b/src/qt/modaloverlay.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2020 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -45,11 +45,11 @@ protected:
private:
Ui::ModalOverlay *ui;
- int bestHeaderHeight; //best known height (based on the headers)
+ int bestHeaderHeight{0}; // best known height (based on the headers)
QDateTime bestHeaderDate;
QVector<QPair<qint64, double> > blockProcessTime;
- bool layerIsVisible;
- bool userClosed;
+ bool layerIsVisible{false};
+ bool userClosed{false};
QPropertyAnimation m_animation;
void UpdateHeaderSyncLabel();
void UpdateHeaderPresyncLabel(int height, const QDateTime& blockDate);
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index b2dc7fd65a..b789e6a958 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020 The Bitcoin Core developers
+// Copyright (c) 2014-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index b311a9f32e..88bc33098a 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -32,11 +32,7 @@ Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon
QObject(_parent),
parent(_parent),
programName(_programName),
- mode(None),
trayIcon(_trayIcon)
-#ifdef USE_DBUS
- ,interface(nullptr)
-#endif
{
if(_trayIcon && _trayIcon->supportsMessages())
{
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index 642d2b29ae..1fd8181a22 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -61,10 +61,10 @@ private:
UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */
};
QString programName;
- Mode mode;
+ Mode mode{None};
QSystemTrayIcon *trayIcon;
#ifdef USE_DBUS
- QDBusInterface *interface;
+ QDBusInterface* interface{nullptr};
void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout);
#endif
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 2b6711ca40..6dec4b2e42 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -31,11 +31,9 @@
#include <QSystemTrayIcon>
#include <QTimer>
-OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
- QDialog(parent, GUIUtil::dialog_flags),
- ui(new Ui::OptionsDialog),
- model(nullptr),
- mapper(nullptr)
+OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet)
+ : QDialog(parent, GUIUtil::dialog_flags),
+ ui(new Ui::OptionsDialog)
{
ui->setupUi(this);
@@ -91,7 +89,9 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
ui->thirdPartyTxUrls->setVisible(false);
}
-#ifndef ENABLE_EXTERNAL_SIGNER
+#ifdef ENABLE_EXTERNAL_SIGNER
+ ui->externalSignerPath->setToolTip(ui->externalSignerPath->toolTip().arg(PACKAGE_NAME));
+#else
//: "External signing" means using devices such as hardware wallets.
ui->externalSignerPath->setToolTip(tr("Compiled without external signing support (required for external signing)"));
ui->externalSignerPath->setEnabled(false);
@@ -406,24 +406,21 @@ void OptionsDialog::updateProxyValidationState()
void OptionsDialog::updateDefaultProxyNets()
{
+ CNetAddr ui_proxy_netaddr;
+ LookupHost(ui->proxyIp->text().toStdString(), ui_proxy_netaddr, /*fAllowLookup=*/false);
+ const CService ui_proxy{ui_proxy_netaddr, ui->proxyPort->text().toUShort()};
+
Proxy proxy;
- std::string strProxy;
- QString strDefaultProxyGUI;
-
- model->node().getProxy(NET_IPV4, proxy);
- strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
- strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
- (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv4->setChecked(true) : ui->proxyReachIPv4->setChecked(false);
-
- model->node().getProxy(NET_IPV6, proxy);
- strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
- strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
- (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv6->setChecked(true) : ui->proxyReachIPv6->setChecked(false);
-
- model->node().getProxy(NET_ONION, proxy);
- strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
- strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
- (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachTor->setChecked(true) : ui->proxyReachTor->setChecked(false);
+ bool has_proxy;
+
+ has_proxy = model->node().getProxy(NET_IPV4, proxy);
+ ui->proxyReachIPv4->setChecked(has_proxy && proxy.proxy == ui_proxy);
+
+ has_proxy = model->node().getProxy(NET_IPV6, proxy);
+ ui->proxyReachIPv6->setChecked(has_proxy && proxy.proxy == ui_proxy);
+
+ has_proxy = model->node().getProxy(NET_ONION, proxy);
+ ui->proxyReachTor->setChecked(has_proxy && proxy.proxy == ui_proxy);
}
ProxyAddressValidator::ProxyAddressValidator(QObject *parent) :
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index e5a19d5025..031e4d3163 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -75,8 +75,8 @@ Q_SIGNALS:
private:
Ui::OptionsDialog *ui;
ClientModel* m_client_model{nullptr};
- OptionsModel *model;
- QDataWidgetMapper *mapper;
+ OptionsModel* model{nullptr};
+ QDataWidgetMapper* mapper{nullptr};
};
#endif // BITCOIN_QT_OPTIONSDIALOG_H
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 0b4359a917..bee8fafddc 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,6 +18,7 @@
#include <netbase.h>
#include <txdb.h> // for -dbcache defaults
#include <util/string.h>
+#include <util/system.h>
#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
#include <wallet/wallet.h> // For DEFAULT_SPEND_ZEROCONF_CHANGE
@@ -31,7 +32,7 @@
const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
-static const QString GetDefaultProxyAddress();
+static QString GetDefaultProxyAddress();
/** Map GUI option ID to node setting name. */
static const char* SettingName(OptionsModel::OptionID option)
@@ -59,7 +60,7 @@ static const char* SettingName(OptionsModel::OptionID option)
}
/** Call node.updateRwSetting() with Bitcoin 22.x workaround. */
-static void UpdateRwSetting(interfaces::Node& node, OptionsModel::OptionID option, const util::SettingsValue& value)
+static void UpdateRwSetting(interfaces::Node& node, OptionsModel::OptionID option, const std::string& suffix, const util::SettingsValue& value)
{
if (value.isNum() &&
(option == OptionsModel::DatabaseCache ||
@@ -73,9 +74,9 @@ static void UpdateRwSetting(interfaces::Node& node, OptionsModel::OptionID optio
// in later releases by https://github.com/bitcoin/bitcoin/pull/24498.
// If new numeric settings are added, they can be written as numbers
// instead of strings, because bitcoin 22.x will not try to read these.
- node.updateRwSetting(SettingName(option), value.getValStr());
+ node.updateRwSetting(SettingName(option) + suffix, value.getValStr());
} else {
- node.updateRwSetting(SettingName(option), value);
+ node.updateRwSetting(SettingName(option) + suffix, value);
}
}
@@ -131,13 +132,6 @@ void OptionsModel::addOverriddenOption(const std::string &option)
bool OptionsModel::Init(bilingual_str& error)
{
// Initialize display settings from stored settings.
- m_prune_size_gb = PruneSizeGB(node().getPersistentSetting("prune"));
- ProxySetting proxy = ParseProxyString(SettingToString(node().getPersistentSetting("proxy"), GetDefaultProxyAddress().toStdString()));
- m_proxy_ip = proxy.ip;
- m_proxy_port = proxy.port;
- ProxySetting onion = ParseProxyString(SettingToString(node().getPersistentSetting("onion"), GetDefaultProxyAddress().toStdString()));
- m_onion_ip = onion.ip;
- m_onion_port = onion.port;
language = QString::fromStdString(SettingToString(node().getPersistentSetting("lang"), ""));
checkAndMigrate();
@@ -227,6 +221,8 @@ bool OptionsModel::Init(bilingual_str& error)
m_use_embedded_monospaced_font = settings.value("UseEmbeddedMonospacedFont").toBool();
Q_EMIT useEmbeddedMonospacedFontChanged(m_use_embedded_monospaced_font);
+ m_mask_values = settings.value("mask_values", false).toBool();
+
return true;
}
@@ -308,7 +304,7 @@ static std::string ProxyString(bool is_set, QString ip, QString port)
return is_set ? QString(ip + ":" + port).toStdString() : "";
}
-static const QString GetDefaultProxyAddress()
+static QString GetDefaultProxyAddress()
{
return QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST).arg(DEFAULT_GUI_PROXY_PORT);
}
@@ -318,8 +314,6 @@ void OptionsModel::SetPruneTargetGB(int prune_target_gb)
const util::SettingsValue cur_value = node().getPersistentSetting("prune");
const util::SettingsValue new_value = PruneSetting(prune_target_gb > 0, prune_target_gb);
- m_prune_size_gb = prune_target_gb;
-
// Force setting to take effect. It is still safe to change the value at
// this point because this function is only called after the intro screen is
// shown, before the node starts.
@@ -332,7 +326,12 @@ void OptionsModel::SetPruneTargetGB(int prune_target_gb)
PruneSizeGB(cur_value) != PruneSizeGB(new_value)) {
// Call UpdateRwSetting() instead of setOption() to avoid setting
// RestartRequired flag
- UpdateRwSetting(node(), Prune, new_value);
+ UpdateRwSetting(node(), Prune, "", new_value);
+ }
+
+ // Keep previous pruning size, if pruning was disabled.
+ if (PruneEnabled(cur_value)) {
+ UpdateRwSetting(node(), Prune, "-prev", PruneEnabled(new_value) ? util::SettingsValue{} : cur_value);
}
}
@@ -360,9 +359,9 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
return successful;
}
-QVariant OptionsModel::getOption(OptionID option) const
+QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) const
{
- auto setting = [&]{ return node().getPersistentSetting(SettingName(option)); };
+ auto setting = [&]{ return node().getPersistentSetting(SettingName(option) + suffix); };
QSettings settings;
switch (option) {
@@ -389,19 +388,30 @@ QVariant OptionsModel::getOption(OptionID option) const
// default proxy
case ProxyUse:
+ case ProxyUseTor:
return ParseProxyString(SettingToString(setting(), "")).is_set;
case ProxyIP:
- return m_proxy_ip;
+ case ProxyIPTor: {
+ ProxySetting proxy = ParseProxyString(SettingToString(setting(), ""));
+ if (proxy.is_set) {
+ return proxy.ip;
+ } else if (suffix.empty()) {
+ return getOption(option, "-prev");
+ } else {
+ return ParseProxyString(GetDefaultProxyAddress().toStdString()).ip;
+ }
+ }
case ProxyPort:
- return m_proxy_port;
-
- // separate Tor proxy
- case ProxyUseTor:
- return ParseProxyString(SettingToString(setting(), "")).is_set;
- case ProxyIPTor:
- return m_onion_ip;
- case ProxyPortTor:
- return m_onion_port;
+ case ProxyPortTor: {
+ ProxySetting proxy = ParseProxyString(SettingToString(setting(), ""));
+ if (proxy.is_set) {
+ return proxy.port;
+ } else if (suffix.empty()) {
+ return getOption(option, "-prev");
+ } else {
+ return ParseProxyString(GetDefaultProxyAddress().toStdString()).port;
+ }
+ }
#ifdef ENABLE_WALLET
case SpendZeroConfChange:
@@ -426,7 +436,9 @@ QVariant OptionsModel::getOption(OptionID option) const
case Prune:
return PruneEnabled(setting());
case PruneSize:
- return m_prune_size_gb;
+ return PruneEnabled(setting()) ? PruneSizeGB(setting()) :
+ suffix.empty() ? getOption(option, "-prev") :
+ DEFAULT_PRUNE_TARGET_GB;
case DatabaseCache:
return qlonglong(SettingToInt(setting(), nDefaultDbCache));
case ThreadsScriptVerif:
@@ -435,15 +447,17 @@ QVariant OptionsModel::getOption(OptionID option) const
return SettingToBool(setting(), DEFAULT_LISTEN);
case Server:
return SettingToBool(setting(), false);
+ case MaskValues:
+ return m_mask_values;
default:
return QVariant();
}
}
-bool OptionsModel::setOption(OptionID option, const QVariant& value)
+bool OptionsModel::setOption(OptionID option, const QVariant& value, const std::string& suffix)
{
- auto changed = [&] { return value.isValid() && value != getOption(option); };
- auto update = [&](const util::SettingsValue& value) { return UpdateRwSetting(node(), option, value); };
+ auto changed = [&] { return value.isValid() && value != getOption(option, suffix); };
+ auto update = [&](const util::SettingsValue& value) { return UpdateRwSetting(node(), option, suffix, value); };
bool successful = true; /* set to false on parse error */
QSettings settings;
@@ -481,52 +495,60 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value)
// default proxy
case ProxyUse:
if (changed()) {
- update(ProxyString(value.toBool(), m_proxy_ip, m_proxy_port));
- setRestartRequired(true);
+ if (suffix.empty() && !value.toBool()) setOption(option, true, "-prev");
+ update(ProxyString(value.toBool(), getOption(ProxyIP).toString(), getOption(ProxyPort).toString()));
+ if (suffix.empty() && value.toBool()) UpdateRwSetting(node(), option, "-prev", {});
+ if (suffix.empty()) setRestartRequired(true);
}
break;
case ProxyIP:
if (changed()) {
- m_proxy_ip = value.toString();
- if (getOption(ProxyUse).toBool()) {
- update(ProxyString(true, m_proxy_ip, m_proxy_port));
- setRestartRequired(true);
+ if (suffix.empty() && !getOption(ProxyUse).toBool()) {
+ setOption(option, value, "-prev");
+ } else {
+ update(ProxyString(true, value.toString(), getOption(ProxyPort).toString()));
}
+ if (suffix.empty() && getOption(ProxyUse).toBool()) setRestartRequired(true);
}
break;
case ProxyPort:
if (changed()) {
- m_proxy_port = value.toString();
- if (getOption(ProxyUse).toBool()) {
- update(ProxyString(true, m_proxy_ip, m_proxy_port));
- setRestartRequired(true);
+ if (suffix.empty() && !getOption(ProxyUse).toBool()) {
+ setOption(option, value, "-prev");
+ } else {
+ update(ProxyString(true, getOption(ProxyIP).toString(), value.toString()));
}
+ if (suffix.empty() && getOption(ProxyUse).toBool()) setRestartRequired(true);
}
break;
// separate Tor proxy
case ProxyUseTor:
if (changed()) {
- update(ProxyString(value.toBool(), m_onion_ip, m_onion_port));
- setRestartRequired(true);
+ if (suffix.empty() && !value.toBool()) setOption(option, true, "-prev");
+ update(ProxyString(value.toBool(), getOption(ProxyIPTor).toString(), getOption(ProxyPortTor).toString()));
+ if (suffix.empty() && value.toBool()) UpdateRwSetting(node(), option, "-prev", {});
+ if (suffix.empty()) setRestartRequired(true);
}
break;
case ProxyIPTor:
if (changed()) {
- m_onion_ip = value.toString();
- if (getOption(ProxyUseTor).toBool()) {
- update(ProxyString(true, m_onion_ip, m_onion_port));
- setRestartRequired(true);
+ if (suffix.empty() && !getOption(ProxyUseTor).toBool()) {
+ setOption(option, value, "-prev");
+ } else {
+ update(ProxyString(true, value.toString(), getOption(ProxyPortTor).toString()));
}
+ if (suffix.empty() && getOption(ProxyUseTor).toBool()) setRestartRequired(true);
}
break;
case ProxyPortTor:
if (changed()) {
- m_onion_port = value.toString();
- if (getOption(ProxyUseTor).toBool()) {
- update(ProxyString(true, m_onion_ip, m_onion_port));
- setRestartRequired(true);
+ if (suffix.empty() && !getOption(ProxyUseTor).toBool()) {
+ setOption(option, value, "-prev");
+ } else {
+ update(ProxyString(true, getOption(ProxyIPTor).toString(), value.toString()));
}
+ if (suffix.empty() && getOption(ProxyUseTor).toBool()) setRestartRequired(true);
}
break;
@@ -580,17 +602,20 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value)
break;
case Prune:
if (changed()) {
- update(PruneSetting(value.toBool(), m_prune_size_gb));
- setRestartRequired(true);
+ if (suffix.empty() && !value.toBool()) setOption(option, true, "-prev");
+ update(PruneSetting(value.toBool(), getOption(PruneSize).toInt()));
+ if (suffix.empty() && value.toBool()) UpdateRwSetting(node(), option, "-prev", {});
+ if (suffix.empty()) setRestartRequired(true);
}
break;
case PruneSize:
if (changed()) {
- m_prune_size_gb = ParsePruneSizeGB(value);
- if (getOption(Prune).toBool()) {
- update(PruneSetting(true, m_prune_size_gb));
- setRestartRequired(true);
+ if (suffix.empty() && !getOption(Prune).toBool()) {
+ setOption(option, value, "-prev");
+ } else {
+ update(PruneSetting(true, ParsePruneSizeGB(value)));
}
+ if (suffix.empty() && getOption(Prune).toBool()) setRestartRequired(true);
}
break;
case DatabaseCache:
@@ -612,6 +637,10 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value)
setRestartRequired(true);
}
break;
+ case MaskValues:
+ m_mask_values = value.toBool();
+ settings.setValue("mask_values", m_mask_values);
+ break;
default:
break;
}
@@ -640,6 +669,11 @@ bool OptionsModel::isRestartRequired() const
return settings.value("fRestartRequired", false).toBool();
}
+bool OptionsModel::hasSigner()
+{
+ return gArgs.GetArg("-signer", "") != "";
+}
+
void OptionsModel::checkAndMigrate()
{
// Migration of default values
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 42b89c5029..f28a1087ba 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -72,6 +72,7 @@ public:
Listen, // bool
Server, // bool
EnablePSBTControls, // bool
+ MaskValues, // bool
OptionIDRowCount,
};
@@ -81,8 +82,8 @@ public:
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) override;
- QVariant getOption(OptionID option) const;
- bool setOption(OptionID option, const QVariant& value);
+ QVariant getOption(OptionID option, const std::string& suffix="") const;
+ bool setOption(OptionID option, const QVariant& value, const std::string& suffix="");
/** Updates current unit in memory, settings and emits displayUnitChanged(new_unit) signal */
void setDisplayUnit(const QVariant& new_unit);
@@ -98,6 +99,9 @@ public:
bool getEnablePSBTControls() const { return m_enable_psbt_controls; }
const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; }
+ /** Whether -signer was set or not */
+ bool hasSigner();
+
/* Explicit setters */
void SetPruneTargetGB(int prune_target_gb);
@@ -120,15 +124,7 @@ private:
bool fCoinControlFeatures;
bool m_sub_fee_from_amount;
bool m_enable_psbt_controls;
-
- //! In-memory settings for display. These are stored persistently by the
- //! bitcoin node but it's also nice to store them in memory to prevent them
- //! getting cleared when enable/disable toggles are used in the GUI.
- int m_prune_size_gb;
- QString m_proxy_ip;
- QString m_proxy_port;
- QString m_onion_ip;
- QString m_onion_port;
+ bool m_mask_values;
/* settings that were overridden by command-line */
QString strOverriddenByCommandLine;
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 85a3c36f39..0f00d167f7 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -140,8 +140,6 @@ private:
OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent),
ui(new Ui::OverviewPage),
- clientModel(nullptr),
- walletModel(nullptr),
m_platform_style{platformStyle},
txdelegate(new TxViewDelegate(platformStyle, this))
{
@@ -175,6 +173,7 @@ void OverviewPage::handleTransactionClicked(const QModelIndex &index)
void OverviewPage::setPrivacy(bool privacy)
{
m_privacy = privacy;
+ clientModel->getOptionsModel()->setOption(OptionsModel::OptionID::MaskValues, privacy);
const auto& balances = walletModel->getCachedBalance();
if (balances.balance != -1) {
setBalance(balances);
@@ -264,7 +263,6 @@ void OverviewPage::setWalletModel(WalletModel *model)
// Set up transaction list
filter.reset(new TransactionFilterProxy());
filter->setSourceModel(model->getTransactionTableModel());
- filter->setLimit(NUM_ITEMS);
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->setShowInactive(false);
@@ -273,6 +271,10 @@ void OverviewPage::setWalletModel(WalletModel *model)
ui->listTransactions->setModel(filter.get());
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
+ connect(filter.get(), &TransactionFilterProxy::rowsInserted, this, &OverviewPage::LimitTransactionRows);
+ connect(filter.get(), &TransactionFilterProxy::rowsRemoved, this, &OverviewPage::LimitTransactionRows);
+ connect(filter.get(), &TransactionFilterProxy::rowsMoved, this, &OverviewPage::LimitTransactionRows);
+ LimitTransactionRows();
// Keep up to date with wallet
setBalance(model->getCachedBalance());
connect(model, &WalletModel::balanceChanged, this, &OverviewPage::setBalance);
@@ -301,6 +303,16 @@ void OverviewPage::changeEvent(QEvent* e)
QWidget::changeEvent(e);
}
+// Only show most recent NUM_ITEMS rows
+void OverviewPage::LimitTransactionRows()
+{
+ if (filter && ui->listTransactions && ui->listTransactions->model() && filter.get() == ui->listTransactions->model()) {
+ for (int i = 0; i < filter->rowCount(); ++i) {
+ ui->listTransactions->setRowHidden(i, i >= NUM_ITEMS);
+ }
+ }
+}
+
void OverviewPage::updateDisplayUnit()
{
if (walletModel && walletModel->getOptionsModel()) {
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 56f45907db..5c487ee116 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -50,8 +50,8 @@ protected:
private:
Ui::OverviewPage *ui;
- ClientModel *clientModel;
- WalletModel *walletModel;
+ ClientModel* clientModel{nullptr};
+ WalletModel* walletModel{nullptr};
bool m_privacy{false};
const PlatformStyle* m_platform_style;
@@ -60,6 +60,7 @@ private:
std::unique_ptr<TransactionFilterProxy> filter;
private Q_SLOTS:
+ void LimitTransactionRows();
void updateDisplayUnit();
void handleTransactionClicked(const QModelIndex &index);
void updateAlerts(const QString &warnings);
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 9f87c15c94..3f9d1b040b 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -126,11 +126,8 @@ bool PaymentServer::ipcSendCommandLine()
return fResult;
}
-PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
- QObject(parent),
- saveURIs(true),
- uriServer(nullptr),
- optionsModel(nullptr)
+PaymentServer::PaymentServer(QObject* parent, bool startLocalServer)
+ : QObject(parent)
{
// Install global event filter to catch QFileOpenEvents
// on Mac: sent when you click bitcoin: links
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 08b83244ab..63f4faa772 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -101,9 +101,9 @@ protected:
bool eventFilter(QObject *object, QEvent *event) override;
private:
- bool saveURIs; // true during startup
- QLocalServer* uriServer;
- OptionsModel *optionsModel;
+ bool saveURIs{true}; // true during startup
+ QLocalServer* uriServer{nullptr};
+ OptionsModel* optionsModel{nullptr};
};
#endif // BITCOIN_QT_PAYMENTSERVER_H
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index b7de88225e..9f47213ed9 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,10 +14,9 @@
#include <QList>
#include <QTimer>
-PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) :
- QAbstractTableModel(parent),
- m_node(node),
- timer(nullptr)
+PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent)
+ : QAbstractTableModel(parent),
+ m_node(node)
{
// set up timer for auto refresh
timer = new QTimer(this);
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index e2515de775..a0174c3af4 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -110,7 +110,7 @@ private:
/*: Title of Peers Table column which contains the peer's
User Agent string. */
tr("User Agent")};
- QTimer *timer;
+ QTimer* timer{nullptr};
};
#endif // BITCOIN_QT_PEERTABLEMODEL_H
diff --git a/src/qt/peertablesortproxy.cpp b/src/qt/peertablesortproxy.cpp
index d87f10c365..a70b5d4e29 100644
--- a/src/qt/peertablesortproxy.cpp
+++ b/src/qt/peertablesortproxy.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index 89e022a067..a430650096 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -83,8 +83,8 @@ QColor PlatformStyle::TextColor() const
QColor PlatformStyle::SingleColor() const
{
if (colorizeIcons) {
- const QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight));
- const QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText));
+ QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight));
+ QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText));
const QColor colorText(QApplication::palette().color(QPalette::WindowText));
const int colorTextLightness = colorText.lightness();
if (abs(colorHighlightBg.lightness() - colorTextLightness) < abs(colorHighlightFg.lightness() - colorTextLightness)) {
diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp
index 333766ce21..17a65be0fe 100644
--- a/src/qt/psbtoperationsdialog.cpp
+++ b/src/qt/psbtoperationsdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -56,7 +56,7 @@ void PSBTOperationsDialog::openWithPSBT(PartiallySignedTransaction psbtx)
bool complete = FinalizePSBT(psbtx); // Make sure all existing signatures are fully combined before checking for completeness.
if (m_wallet_model) {
size_t n_could_sign;
- TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, &n_could_sign, m_transaction_data, complete);
+ TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, &n_could_sign, m_transaction_data, complete);
if (err != TransactionError::OK) {
showStatus(tr("Failed to load transaction: %1")
.arg(QString::fromStdString(TransactionErrorString(err).translated)),
@@ -80,7 +80,7 @@ void PSBTOperationsDialog::signTransaction()
WalletModel::UnlockContext ctx(m_wallet_model->requestUnlock());
- TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, true /* sign */, true /* bip32derivs */, &n_signed, m_transaction_data, complete);
+ TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/true, /*bip32derivs=*/true, &n_signed, m_transaction_data, complete);
if (err != TransactionError::OK) {
showStatus(tr("Failed to sign transaction: %1")
@@ -245,7 +245,7 @@ size_t PSBTOperationsDialog::couldSignInputs(const PartiallySignedTransaction &p
size_t n_signed;
bool complete;
- TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, false /* bip32derivs */, &n_signed, m_transaction_data, complete);
+ TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/false, &n_signed, m_transaction_data, complete);
if (err != TransactionError::OK) {
return 0;
diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp
index 05a67117b6..00f928b355 100644
--- a/src/qt/qrimagewidget.cpp
+++ b/src/qt/qrimagewidget.cpp
@@ -23,8 +23,8 @@
#include <qrencode.h>
#endif
-QRImageWidget::QRImageWidget(QWidget *parent):
- QLabel(parent), contextMenu(nullptr)
+QRImageWidget::QRImageWidget(QWidget* parent)
+ : QLabel(parent)
{
contextMenu = new QMenu(this);
contextMenu->addAction(tr("&Save Image…"), this, &QRImageWidget::saveImage);
diff --git a/src/qt/qrimagewidget.h b/src/qt/qrimagewidget.h
index 5dbba074a1..d9ca2b899f 100644
--- a/src/qt/qrimagewidget.h
+++ b/src/qt/qrimagewidget.h
@@ -41,7 +41,7 @@ protected:
virtual void contextMenuEvent(QContextMenuEvent *event) override;
private:
- QMenu *contextMenu;
+ QMenu* contextMenu{nullptr};
};
#endif // BITCOIN_QT_QRIMAGEWIDGET_H
diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp
index bd4df75d23..b646332001 100644
--- a/src/qt/qvalidatedlineedit.cpp
+++ b/src/qt/qvalidatedlineedit.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,10 +7,8 @@
#include <qt/bitcoinaddressvalidator.h>
#include <qt/guiconstants.h>
-QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) :
- QLineEdit(parent),
- valid(true),
- checkValidator(nullptr)
+QValidatedLineEdit::QValidatedLineEdit(QWidget* parent)
+ : QLineEdit(parent)
{
connect(this, &QValidatedLineEdit::textChanged, this, &QValidatedLineEdit::markValid);
}
diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h
index 12d35aa264..b1ae013957 100644
--- a/src/qt/qvalidatedlineedit.h
+++ b/src/qt/qvalidatedlineedit.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -25,8 +25,8 @@ protected:
void focusOutEvent(QFocusEvent *evt) override;
private:
- bool valid;
- const QValidator *checkValidator;
+ bool valid{true};
+ const QValidator* checkValidator{nullptr};
public Q_SLOTS:
void setText(const QString&);
diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp
index f94486a2f3..c163ba56dc 100644
--- a/src/qt/qvaluecombobox.cpp
+++ b/src/qt/qvaluecombobox.cpp
@@ -4,8 +4,8 @@
#include <qt/qvaluecombobox.h>
-QValueComboBox::QValueComboBox(QWidget *parent) :
- QComboBox(parent), role(Qt::UserRole)
+QValueComboBox::QValueComboBox(QWidget* parent)
+ : QComboBox(parent)
{
connect(this, qOverload<int>(&QComboBox::currentIndexChanged), this, &QValueComboBox::handleSelectionChanged);
}
diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h
index bde9c0d1a6..14379dd612 100644
--- a/src/qt/qvaluecombobox.h
+++ b/src/qt/qvaluecombobox.h
@@ -28,7 +28,7 @@ Q_SIGNALS:
void valueChanged();
private:
- int role;
+ int role{Qt::UserRole};
private Q_SLOTS:
void handleSelectionChanged(int idx);
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 3c80c01160..22eb642ecd 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -25,7 +25,6 @@
ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::ReceiveCoinsDialog),
- model(nullptr),
platformStyle(_platformStyle)
{
ui->setupUi(this);
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index a089b8aa6a..0bb02ebcf2 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -51,7 +51,7 @@ public Q_SLOTS:
private:
Ui::ReceiveCoinsDialog *ui;
- WalletModel *model;
+ WalletModel* model{nullptr};
QMenu *contextMenu;
QAction* copyLabelAction;
QAction* copyMessageAction;
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index c0135283b1..3453857f98 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -18,10 +18,9 @@
#include <config/bitcoin-config.h> /* for USE_QRCODE */
#endif
-ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) :
- QDialog(parent, GUIUtil::dialog_flags),
- ui(new Ui::ReceiveRequestDialog),
- model(nullptr)
+ReceiveRequestDialog::ReceiveRequestDialog(QWidget* parent)
+ : QDialog(parent, GUIUtil::dialog_flags),
+ ui(new Ui::ReceiveRequestDialog)
{
ui->setupUi(this);
GUIUtil::handleCloseWindowShortcut(this);
diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h
index c861680761..d64fee3663 100644
--- a/src/qt/receiverequestdialog.h
+++ b/src/qt/receiverequestdialog.h
@@ -33,7 +33,7 @@ private Q_SLOTS:
private:
Ui::ReceiveRequestDialog *ui;
- WalletModel *model;
+ WalletModel* model{nullptr};
SendCoinsRecipient info;
};
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 061513b58f..52d4e45d49 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -175,7 +175,7 @@ void RecentRequestsTableModel::addNewRequest(const SendCoinsRecipient &recipient
newEntry.date = QDateTime::currentDateTime();
newEntry.recipient = recipient;
- CDataStream ss(SER_DISK, CLIENT_VERSION);
+ DataStream ss{};
ss << newEntry;
if (!walletModel->wallet().setAddressReceiveRequest(DecodeDestination(recipient.address.toStdString()), ToString(newEntry.id), ss.str()))
@@ -188,7 +188,7 @@ void RecentRequestsTableModel::addNewRequest(const SendCoinsRecipient &recipient
void RecentRequestsTableModel::addNewRequest(const std::string &recipient)
{
std::vector<uint8_t> data(recipient.begin(), recipient.end());
- CDataStream ss(data, SER_DISK, CLIENT_VERSION);
+ DataStream ss{data};
RecentRequestEntry entry;
ss >> entry;
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index cf7cd24ce2..151f8322a8 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -18,11 +18,11 @@ class WalletModel;
class RecentRequestEntry
{
public:
- RecentRequestEntry() : nVersion(RecentRequestEntry::CURRENT_VERSION), id(0) { }
+ RecentRequestEntry() : nVersion(RecentRequestEntry::CURRENT_VERSION) {}
static const int CURRENT_VERSION = 1;
int nVersion;
- int64_t id;
+ int64_t id{0};
QDateTime date;
SendCoinsRecipient recipient;
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 295450d6b7..0e712062af 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,7 +11,6 @@
#include <chainparams.h>
#include <interfaces/node.h>
-#include <netbase.h>
#include <qt/bantablemodel.h>
#include <qt/clientmodel.h>
#include <qt/guiutil.h>
@@ -780,8 +779,8 @@ void RPCConsole::addWallet(WalletModel * const walletModel)
{
// use name for text and wallet model for internal data object (to allow to move to a wallet id later)
ui->WalletSelector->addItem(walletModel->getDisplayName(), QVariant::fromValue(walletModel));
- if (ui->WalletSelector->count() == 2 && !isVisible()) {
- // First wallet added, set to default so long as the window isn't presently visible (and potentially in use)
+ if (ui->WalletSelector->count() == 2) {
+ // First wallet added, set to default to match wallet RPC behavior
ui->WalletSelector->setCurrentIndex(1);
}
if (ui->WalletSelector->count() > 2) {
@@ -1178,8 +1177,12 @@ void RPCConsole::updateDetailWidget()
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.m_last_ping_time));
ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.m_min_ping_time));
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
- ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
- ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
+ if (stats->nodeStats.nVersion) {
+ ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
+ }
+ if (!stats->nodeStats.cleanSubVer.empty()) {
+ ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
+ }
ui->peerConnectionType->setText(GUIUtil::ConnectionTypeToQString(stats->nodeStats.m_conn_type, /*prepend_direction=*/true));
ui->peerNetwork->setText(GUIUtil::NetworkToQString(stats->nodeStats.m_network));
if (stats->nodeStats.m_permission_flags == NetPermissionFlags::None) {
@@ -1304,17 +1307,13 @@ void RPCConsole::unbanSelectedNode()
// Get selected ban addresses
QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->banlistWidget, BanTableModel::Address);
- for(int i = 0; i < nodes.count(); i++)
- {
- // Get currently selected ban address
- QString strNode = nodes.at(i).data().toString();
- CSubNet possibleSubnet;
-
- LookupSubNet(strNode.toStdString(), possibleSubnet);
- if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet))
- {
- clientModel->getBanTableModel()->refresh();
- }
+ BanTableModel* ban_table_model{clientModel->getBanTableModel()};
+ bool unbanned{false};
+ for (const auto& node_index : nodes) {
+ unbanned |= ban_table_model->unban(node_index);
+ }
+ if (unbanned) {
+ ban_table_model->refresh();
}
}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index a3c713e966..32a7520491 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 53c352b393..89dd0ada62 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -64,11 +64,7 @@ int getIndexForConfTarget(int target) {
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::SendCoinsDialog),
- clientModel(nullptr),
- model(nullptr),
m_coin_control(new CCoinControl),
- fNewRecipientAllowed(true),
- fFeeMinimized(true),
platformStyle(_platformStyle)
{
ui->setupUi(this);
@@ -207,7 +203,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
if (model->wallet().hasExternalSigner()) {
//: "device" usually means a hardware wallet.
ui->sendButton->setText(tr("Sign on device"));
- if (gArgs.GetArg("-signer", "") != "") {
+ if (model->getOptionsModel()->hasSigner()) {
ui->sendButton->setEnabled(true);
ui->sendButton->setToolTip(tr("Connect your hardware wallet first."));
} else {
@@ -289,7 +285,9 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
updateCoinControlState();
- prepareStatus = model->prepareTransaction(*m_current_transaction, *m_coin_control);
+ CCoinControl coin_control = *m_coin_control;
+ coin_control.m_allow_other_inputs = !coin_control.HasSelected(); // future, could introduce a checkbox to customize this value.
+ prepareStatus = model->prepareTransaction(*m_current_transaction, coin_control);
// process prepareStatus and on error generate message shown to user
processSendCoinsReturn(prepareStatus,
@@ -701,7 +699,7 @@ void SendCoinsDialog::setBalance(const interfaces::WalletBalances& balances)
CAmount balance = balances.balance;
if (model->wallet().hasExternalSigner()) {
ui->labelBalanceName->setText(tr("External balance:"));
- } else if (model->wallet().privateKeysDisabled()) {
+ } else if (model->wallet().isLegacy() && model->wallet().privateKeysDisabled()) {
balance = balances.watch_only_balance;
ui->labelBalanceName->setText(tr("Watch-only balance:"));
}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index dcdf189532..2fcdf5b32a 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -62,12 +62,12 @@ Q_SIGNALS:
private:
Ui::SendCoinsDialog *ui;
- ClientModel *clientModel;
- WalletModel *model;
+ ClientModel* clientModel{nullptr};
+ WalletModel* model{nullptr};
std::unique_ptr<wallet::CCoinControl> m_coin_control;
std::unique_ptr<WalletModelTransaction> m_current_transaction;
- bool fNewRecipientAllowed;
- bool fFeeMinimized;
+ bool fNewRecipientAllowed{true};
+ bool fFeeMinimized{true};
const PlatformStyle *platformStyle;
// Copy PSBT to clipboard and offer to save it.
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index af514d5a43..0536635c84 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,7 +22,6 @@
SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *parent) :
QWidget(parent),
ui(new Ui::SendCoinsEntry),
- model(nullptr),
platformStyle(_platformStyle)
{
ui->setupUi(this);
diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h
index ea9d58fbf8..0edc0d1203 100644
--- a/src/qt/sendcoinsentry.h
+++ b/src/qt/sendcoinsentry.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -73,7 +73,7 @@ protected:
private:
SendCoinsRecipient recipient;
Ui::SendCoinsEntry *ui;
- WalletModel *model;
+ WalletModel* model{nullptr};
const PlatformStyle *platformStyle;
bool updateLabel(const QString &address);
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 1f4b30534b..0e725acb33 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -21,7 +21,6 @@
SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::SignVerifyMessageDialog),
- model(nullptr),
platformStyle(_platformStyle)
{
ui->setupUi(this);
diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h
index 1a3708bf8f..4072707b61 100644
--- a/src/qt/signverifymessagedialog.h
+++ b/src/qt/signverifymessagedialog.h
@@ -35,7 +35,7 @@ protected:
private:
Ui::SignVerifyMessageDialog *ui;
- WalletModel *model;
+ WalletModel* model{nullptr};
const PlatformStyle *platformStyle;
private Q_SLOTS:
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index bf04a6dd5f..096f8a0ded 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -28,7 +28,7 @@
SplashScreen::SplashScreen(const NetworkStyle* networkStyle)
- : QWidget(), curAlignment(0)
+ : QWidget()
{
// set reference point, paddings
int paddingRight = 50;
@@ -161,16 +161,6 @@ bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) {
return QObject::eventFilter(obj, ev);
}
-void SplashScreen::finish()
-{
- /* If the window is minimized, hide() will be ignored. */
- /* Make sure we de-minimize the splashscreen window before hiding */
- if (isMinimized())
- showNormal();
- hide();
- deleteLater(); // No more need for this
-}
-
static void InitMessage(SplashScreen *splash, const std::string &message)
{
bool invoked = QMetaObject::invokeMethod(splash, "showMessage",
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index c14fc521a7..2356bbacd3 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -37,9 +37,6 @@ protected:
void closeEvent(QCloseEvent *event) override;
public Q_SLOTS:
- /** Hide the splash screen window and schedule the splash screen object for deletion */
- void finish();
-
/** Show message and progress */
void showMessage(const QString &message, int alignment, const QColor &color);
@@ -60,7 +57,7 @@ private:
QPixmap pixmap;
QString curMessage;
QColor curColor;
- int curAlignment;
+ int curAlignment{0};
interfaces::Node* m_node = nullptr;
bool m_shutdown = false;
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 581735263d..d005e08d14 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -75,7 +75,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
test.m_node.wallet_loader = wallet_loader.get();
node.setContext(&test.m_node);
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", gArgs, CreateMockWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
{
diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp
index 6fc7a52435..000bbe65be 100644
--- a/src/qt/test/apptests.cpp
+++ b/src/qt/test/apptests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -72,7 +72,7 @@ void AppTests::appTests()
qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
m_app.parameterSetup();
- QVERIFY(m_app.createOptionsModel(true /* reset settings */));
+ QVERIFY(m_app.createOptionsModel(/*resetSettings=*/true));
QScopedPointer<const NetworkStyle> style(NetworkStyle::instantiate(Params().NetworkIDString()));
m_app.setupPlatformStyle();
m_app.createWindow(style.data());
diff --git a/src/qt/test/optiontests.cpp b/src/qt/test/optiontests.cpp
index 17ffeb220b..dc7c8928c5 100644
--- a/src/qt/test/optiontests.cpp
+++ b/src/qt/test/optiontests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/optiontests.h b/src/qt/test/optiontests.h
index 57ec8bd0f2..0c458c97a6 100644
--- a/src/qt/test/optiontests.h
+++ b/src/qt/test/optiontests.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 846fa519ee..2d069f76a0 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -79,8 +79,6 @@ int main(int argc, char* argv[])
setenv("QT_QPA_PLATFORM", "minimal", 0 /* overwrite */);
#endif
- // Don't remove this, it's needed to access
- // QApplication:: and QCoreApplication:: in the tests
BitcoinApplication app;
app.setApplicationName("Bitcoin-Qt-test");
app.createNode(*init);
diff --git a/src/qt/test/util.cpp b/src/qt/test/util.cpp
index 635dbcd1c5..c5ed20d967 100644
--- a/src/qt/test/util.cpp
+++ b/src/qt/test/util.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/util.h b/src/qt/test/util.h
index f50a6b6c61..13170c89ea 100644
--- a/src/qt/test/util.h
+++ b/src/qt/test/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index b71dfb0e9f..62f2019438 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -159,7 +159,7 @@ void TestGUI(interfaces::Node& node)
auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
test.m_node.wallet_loader = wallet_loader.get();
node.setContext(&test.m_node);
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", gArgs, CreateMockWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
{
@@ -210,17 +210,17 @@ void TestGUI(interfaces::Node& node)
// Send two transactions, and verify they are added to transaction list.
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
QCOMPARE(transactionTableModel->rowCount({}), 105);
- uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, false /* rbf */);
- uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, true /* rbf */);
+ uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false);
+ uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true);
QCOMPARE(transactionTableModel->rowCount({}), 107);
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
// Call bumpfee. Test disabled, canceled, enabled, then failing cases.
- BumpFee(transactionView, txid1, true /* expect disabled */, "not BIP 125 replaceable" /* expected error */, false /* cancel */);
- BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, true /* cancel */);
- BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */);
- BumpFee(transactionView, txid2, true /* expect disabled */, "already bumped" /* expected error */, false /* cancel */);
+ BumpFee(transactionView, txid1, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false);
+ BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
+ BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/false);
+ BumpFee(transactionView, txid2, /*expectDisabled=*/true, /*expectError=*/"already bumped", /*cancel=*/false);
// Check current balance on OverviewPage
OverviewPage overviewPage(platformStyle.get());
@@ -289,7 +289,7 @@ void TestGUI(interfaces::Node& node)
std::vector<std::string> requests = walletModel.wallet().getAddressReceiveRequests();
QCOMPARE(requests.size(), size_t{1});
RecentRequestEntry entry;
- CDataStream{MakeUCharSpan(requests[0]), SER_DISK, CLIENT_VERSION} >> entry;
+ DataStream{MakeUCharSpan(requests[0])} >> entry;
QCOMPARE(entry.nVersion, int{1});
QCOMPARE(entry.id, int64_t{1});
QVERIFY(entry.date.isValid());
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index aebd44d5f7..08789c1048 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -19,15 +19,10 @@
#define XMARGIN 10
#define YMARGIN 10
-TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) :
- QWidget(parent),
- timer(nullptr),
- fMax(0.0f),
- vSamplesIn(),
- vSamplesOut(),
- nLastBytesIn(0),
- nLastBytesOut(0),
- clientModel(nullptr)
+TrafficGraphWidget::TrafficGraphWidget(QWidget* parent)
+ : QWidget(parent),
+ vSamplesIn(),
+ vSamplesOut()
{
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &TrafficGraphWidget::updateRates);
diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h
index a40b734540..5e5557ec82 100644
--- a/src/qt/trafficgraphwidget.h
+++ b/src/qt/trafficgraphwidget.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -37,14 +37,14 @@ public Q_SLOTS:
private:
void paintPath(QPainterPath &path, QQueue<float> &samples);
- QTimer *timer;
- float fMax;
+ QTimer* timer{nullptr};
+ float fMax{0.0f};
std::chrono::minutes m_range{0};
QQueue<float> vSamplesIn;
QQueue<float> vSamplesOut;
- quint64 nLastBytesIn;
- quint64 nLastBytesOut;
- ClientModel *clientModel;
+ quint64 nLastBytesIn{0};
+ quint64 nLastBytesOut{0};
+ ClientModel* clientModel{nullptr};
};
#endif // BITCOIN_QT_TRAFFICGRAPHWIDGET_H
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index a61d5407b3..2ced44241f 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h
index 803e41b699..e64f2cace1 100644
--- a/src/qt/transactiondesc.h
+++ b/src/qt/transactiondesc.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp
index 3be7e1a969..173fd326a3 100644
--- a/src/qt/transactionfilterproxy.cpp
+++ b/src/qt/transactionfilterproxy.cpp
@@ -11,14 +11,10 @@
#include <cstdlib>
#include <optional>
-TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
- QSortFilterProxyModel(parent),
- m_search_string(),
- typeFilter(ALL_TYPES),
- watchOnlyFilter(WatchOnlyFilter_All),
- minAmount(0),
- limitRows(-1),
- showInactive(true)
+TransactionFilterProxy::TransactionFilterProxy(QObject* parent)
+ : QSortFilterProxyModel(parent),
+ m_search_string(),
+ typeFilter(ALL_TYPES)
{
}
@@ -92,25 +88,8 @@ void TransactionFilterProxy::setWatchOnlyFilter(WatchOnlyFilter filter)
invalidateFilter();
}
-void TransactionFilterProxy::setLimit(int limit)
-{
- this->limitRows = limit;
-}
-
void TransactionFilterProxy::setShowInactive(bool _showInactive)
{
this->showInactive = _showInactive;
invalidateFilter();
}
-
-int TransactionFilterProxy::rowCount(const QModelIndex &parent) const
-{
- if(limitRows != -1)
- {
- return std::min(QSortFilterProxyModel::rowCount(parent), limitRows);
- }
- else
- {
- return QSortFilterProxyModel::rowCount(parent);
- }
-}
diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h
index fd9be52842..73c4f21426 100644
--- a/src/qt/transactionfilterproxy.h
+++ b/src/qt/transactionfilterproxy.h
@@ -42,14 +42,9 @@ public:
void setMinAmount(const CAmount& minimum);
void setWatchOnlyFilter(WatchOnlyFilter filter);
- /** Set maximum number of rows returned, -1 if unlimited. */
- void setLimit(int limit);
-
/** Set whether to show conflicted transactions. */
void setShowInactive(bool showInactive);
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
-
protected:
bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override;
@@ -58,10 +53,9 @@ private:
std::optional<QDateTime> dateTo;
QString m_search_string;
quint32 typeFilter;
- WatchOnlyFilter watchOnlyFilter;
- CAmount minAmount;
- int limitRows;
- bool showInactive;
+ WatchOnlyFilter watchOnlyFilter{WatchOnlyFilter_All};
+ CAmount minAmount{0};
+ bool showInactive{true};
};
#endif // BITCOIN_QT_TRANSACTIONFILTERPROXY_H
diff --git a/src/qt/transactionoverviewwidget.cpp b/src/qt/transactionoverviewwidget.cpp
index 360a1364fb..24b96c861f 100644
--- a/src/qt/transactionoverviewwidget.cpp
+++ b/src/qt/transactionoverviewwidget.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactionoverviewwidget.h b/src/qt/transactionoverviewwidget.h
index 0572e84090..eb9d661996 100644
--- a/src/qt/transactionoverviewwidget.h
+++ b/src/qt/transactionoverviewwidget.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 26144ba197..5f981ea250 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index d8748d7dc9..36cfb422e8 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -76,12 +76,12 @@ public:
static const int RecommendedNumConfirmations = 6;
TransactionRecord():
- hash(), time(0), type(Other), address(""), debit(0), credit(0), idx(0)
+ hash(), time(0), type(Other), debit(0), credit(0), idx(0)
{
}
TransactionRecord(uint256 _hash, qint64 _time):
- hash(_hash), time(_time), type(Other), address(""), debit(0),
+ hash(_hash), time(_time), type(Other), debit(0),
credit(0), idx(0)
{
}
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 4312b3cd24..25d54bdce6 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -93,10 +93,7 @@ public:
TransactionTableModel *parent;
- /* Local cache of wallet.
- * As it is in the same order as the CWallet, by definition
- * this is sorted by sha256.
- */
+ //! Local cache of wallet sorted by transaction hash
QList<TransactionRecord> cachedWallet;
/** True when model finishes loading all wallet transactions on start */
@@ -253,7 +250,6 @@ TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle
QAbstractTableModel(parent),
walletModel(parent),
priv(new TransactionTablePriv(this)),
- fProcessingQueuedTransactions(false),
platformStyle(_platformStyle)
{
subscribeToCoreSignals();
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index f8576edd59..92ba9bf894 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -89,7 +89,7 @@ private:
std::unique_ptr<interfaces::Handler> m_handler_show_progress;
QStringList columns;
TransactionTablePriv *priv;
- bool fProcessingQueuedTransactions;
+ bool fProcessingQueuedTransactions{false};
const PlatformStyle *platformStyle;
void subscribeToCoreSignals();
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index b7432a0d77..351305f3fa 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -421,9 +421,6 @@ void TransactionView::abandonTx()
// Abandon the wallet transaction over the walletModel
model->wallet().abandonTransaction(hash);
-
- // Update the table
- model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
}
void TransactionView::bumpFee([[maybe_unused]] bool checked)
@@ -534,6 +531,7 @@ void TransactionView::showDetails()
{
TransactionDescDialog *dlg = new TransactionDescDialog(selection.at(0));
dlg->setAttribute(Qt::WA_DeleteOnClose);
+ m_opened_dialogs.append(dlg);
dlg->show();
}
}
@@ -640,6 +638,11 @@ bool TransactionView::eventFilter(QObject *obj, QEvent *event)
return true;
}
}
+ if (event->type() == QEvent::EnabledChange) {
+ if (!isEnabled()) {
+ closeOpenedDialogs();
+ }
+ }
return QWidget::eventFilter(obj, event);
}
@@ -649,3 +652,12 @@ void TransactionView::updateWatchOnlyColumn(bool fHaveWatchOnly)
watchOnlyWidget->setVisible(fHaveWatchOnly);
transactionView->setColumnHidden(TransactionTableModel::Watchonly, !fHaveWatchOnly);
}
+
+void TransactionView::closeOpenedDialogs()
+{
+ // close all dialogs opened from this view
+ for (QDialog* dlg : m_opened_dialogs) {
+ dlg->close();
+ }
+ m_opened_dialogs.clear();
+}
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index fe6e3ac7c0..29fb722afe 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -13,6 +13,7 @@
#include <QKeyEvent>
class PlatformStyle;
+class TransactionDescDialog;
class TransactionFilterProxy;
class WalletModel;
@@ -90,6 +91,8 @@ private:
const PlatformStyle* m_platform_style;
+ QList<TransactionDescDialog*> m_opened_dialogs;
+
private Q_SLOTS:
void contextualMenu(const QPoint &);
void dateRangeChanged();
@@ -121,6 +124,7 @@ public Q_SLOTS:
void changedAmount();
void changedSearch();
void exportClicked();
+ void closeOpenedDialogs();
void focusTransaction(const QModelIndex&);
void focusTransaction(const uint256& txid);
};
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 331487b51d..eb2ab12a66 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index 8762ba9ab3..d782838d6f 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 8dc97e66a2..43411370a2 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -212,7 +212,7 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard)
return;
}
std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary};
- data.assign(std::istream_iterator<unsigned char>{in}, {});
+ data.assign(std::istreambuf_iterator<char>{in}, {});
// Some psbt files may be base64 strings in the file rather than binary data
std::string b64_str{data.begin(), data.end()};
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index c6f3f5b00c..3c69d46b7e 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -46,10 +46,6 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel
m_client_model(&client_model),
m_node(client_model.node()),
optionsModel(client_model.getOptionsModel()),
- addressTableModel(nullptr),
- transactionTableModel(nullptr),
- recentRequestsTableModel(nullptr),
- cachedEncryptionStatus(Unencrypted),
timer(new QTimer(this))
{
fHaveWatchOnly = m_wallet->haveWatchOnly();
@@ -212,12 +208,12 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return AmountExceedsBalance;
}
- {
+ try {
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
auto& newTx = transaction.getWtx();
- const auto& res = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired);
+ const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired);
newTx = res ? *res : nullptr;
transaction.setTransactionFee(nFeeRequired);
if (fSubtractFeeFromAmount && newTx)
@@ -240,6 +236,11 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
if (nFeeRequired > m_wallet->getDefaultMaxTxFee()) {
return AbsurdFee;
}
+ } catch (const std::runtime_error& err) {
+ // Something unexpected happened, instruct user to report this bug.
+ Q_EMIT message(tr("Send Coins"), QString::fromStdString(err.what()),
+ CClientUIInterface::MSG_ERROR);
+ return TransactionCreationFailed;
}
return SendCoinsReturn(OK);
@@ -258,7 +259,7 @@ void WalletModel::sendCoins(WalletModelTransaction& transaction)
}
auto& newTx = transaction.getWtx();
- wallet().commitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm));
+ wallet().commitTransaction(newTx, /*value_map=*/{}, std::move(vOrderForm));
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << *newTx;
@@ -476,13 +477,6 @@ WalletModel::UnlockContext::~UnlockContext()
}
}
-void WalletModel::UnlockContext::CopyFrom(UnlockContext&& rhs)
-{
- // Transfer context; old object no longer relocks wallet
- *this = rhs;
- rhs.relock = false;
-}
-
bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
{
CCoinControl coin_control;
@@ -522,7 +516,9 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
questionString.append(tr("Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy."));
}
- auto confirmationDialog = new SendConfirmationDialog(tr("Confirm fee bump"), questionString, "", "", SEND_CONFIRM_DELAY, !m_wallet->privateKeysDisabled(), getOptionsModel()->getEnablePSBTControls(), nullptr);
+ const bool enable_send{!wallet().privateKeysDisabled() || wallet().hasExternalSigner()};
+ const bool always_show_unsigned{getOptionsModel()->getEnablePSBTControls()};
+ auto confirmationDialog = new SendConfirmationDialog(tr("Confirm fee bump"), questionString, "", "", SEND_CONFIRM_DELAY, enable_send, always_show_unsigned, nullptr);
confirmationDialog->setAttribute(Qt::WA_DeleteOnClose);
// TODO: Replace QDialog::exec() with safer QDialog::show().
const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec());
@@ -540,9 +536,10 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
// Short-circuit if we are returning a bumped transaction PSBT to clipboard
if (retval == QMessageBox::Save) {
+ // "Create Unsigned" clicked
PartiallySignedTransaction psbtx(mtx);
bool complete = false;
- const TransactionError err = wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, nullptr, psbtx, complete);
+ const TransactionError err = wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, nullptr, psbtx, complete);
if (err != TransactionError::OK || complete) {
QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't draft transaction."));
return false;
@@ -555,7 +552,7 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
return true;
}
- assert(!m_wallet->privateKeysDisabled());
+ assert(!m_wallet->privateKeysDisabled() || wallet().hasExternalSigner());
// sign bumped transaction
if (!m_wallet->signBumpTransaction(mtx)) {
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 73dfe0386a..17a39349f3 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -111,7 +111,7 @@ public:
bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString());
bool changePassphrase(const SecureString &oldPass, const SecureString &newPass);
- // RAI object for unlocking wallet, returned by requestUnlock()
+ // RAII object for unlocking wallet, returned by requestUnlock()
class UnlockContext
{
public:
@@ -120,18 +120,16 @@ public:
bool isValid() const { return valid; }
- // Copy constructor is disabled.
+ // Disable unused copy/move constructors/assignments explicitly.
UnlockContext(const UnlockContext&) = delete;
- // Move operator and constructor transfer the context
- UnlockContext(UnlockContext&& obj) { CopyFrom(std::move(obj)); }
- UnlockContext& operator=(UnlockContext&& rhs) { CopyFrom(std::move(rhs)); return *this; }
+ UnlockContext(UnlockContext&&) = delete;
+ UnlockContext& operator=(const UnlockContext&) = delete;
+ UnlockContext& operator=(UnlockContext&&) = delete;
+
private:
WalletModel *wallet;
- bool valid;
- mutable bool relock; // mutable, as it can be set to false by copying
-
- UnlockContext& operator=(const UnlockContext&) = default;
- void CopyFrom(UnlockContext&& rhs);
+ const bool valid;
+ const bool relock;
};
UnlockContext requestUnlock();
@@ -181,13 +179,13 @@ private:
// (transaction fee, for example)
OptionsModel *optionsModel;
- AddressTableModel *addressTableModel;
- TransactionTableModel *transactionTableModel;
- RecentRequestsTableModel *recentRequestsTableModel;
+ AddressTableModel* addressTableModel{nullptr};
+ TransactionTableModel* transactionTableModel{nullptr};
+ RecentRequestsTableModel* recentRequestsTableModel{nullptr};
// Cache some values to be able to detect changes
interfaces::WalletBalances m_cached_balances;
- EncryptionStatus cachedEncryptionStatus;
+ EncryptionStatus cachedEncryptionStatus{Unencrypted};
QTimer* timer;
// Block hash denoting when the last balance update was done.
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index b5538b644f..61ccd9dd82 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Copyright (c) 2011-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,9 +10,8 @@
#include <policy/policy.h>
-WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) :
- recipients(_recipients),
- fee(0)
+WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient>& _recipients)
+ : recipients(_recipients)
{
}
diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h
index 28fb551364..0e6ed8be49 100644
--- a/src/qt/walletmodeltransaction.h
+++ b/src/qt/walletmodeltransaction.h
@@ -41,7 +41,7 @@ public:
private:
QList<SendCoinsRecipient> recipients;
CTransactionRef wtx;
- CAmount fee;
+ CAmount fee{0};
};
#endif // BITCOIN_QT_WALLETMODELTRANSACTION_H
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 10fc0fb6d0..09e0771534 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -31,7 +31,6 @@
WalletView::WalletView(WalletModel* wallet_model, const PlatformStyle* _platformStyle, QWidget* parent)
: QStackedWidget(parent),
- clientModel(nullptr),
walletModel(wallet_model),
platformStyle(_platformStyle)
{
@@ -94,6 +93,7 @@ WalletView::WalletView(WalletModel* wallet_model, const PlatformStyle* _platform
connect(transactionView, &TransactionView::message, this, &WalletView::message);
connect(this, &WalletView::setPrivacy, overviewPage, &OverviewPage::setPrivacy);
+ connect(this, &WalletView::setPrivacy, this, &WalletView::disableTransactionView);
// Receive and pass through messages from wallet model
connect(walletModel, &WalletModel::message, this, &WalletView::message);
@@ -279,3 +279,8 @@ void WalletView::showProgress(const QString &title, int nProgress)
}
}
}
+
+void WalletView::disableTransactionView(bool disable)
+{
+ transactionView->setDisabled(disable);
+}
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index 301084ffa9..475085044d 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -50,7 +50,7 @@ public:
void showOutOfSyncWarning(bool fShow);
private:
- ClientModel *clientModel;
+ ClientModel* clientModel{nullptr};
//!
//! The wallet model represents a bitcoin wallet, and offers access to
@@ -107,6 +107,9 @@ public Q_SLOTS:
/** Show progress dialog e.g. for rescan */
void showProgress(const QString &title, int nProgress);
+private Q_SLOTS:
+ void disableTransactionView(bool disable);
+
Q_SIGNALS:
void setPrivacy(bool privacy);
void transactionClicked();
diff --git a/src/random.cpp b/src/random.cpp
index eab54630b1..f4c51574cc 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,23 +8,22 @@
#include <compat/cpuid.h>
#include <crypto/sha256.h>
#include <crypto/sha512.h>
-#include <support/cleanse.h>
-#ifdef WIN32
-#include <compat/compat.h>
-#include <wincrypt.h>
-#endif
#include <logging.h>
#include <randomenv.h>
-#include <support/allocators/secure.h>
#include <span.h>
-#include <sync.h> // for Mutex
-#include <util/time.h> // for GetTimeMicros()
+#include <support/allocators/secure.h>
+#include <support/cleanse.h>
+#include <sync.h>
+#include <util/time.h>
#include <cmath>
#include <cstdlib>
#include <thread>
-#ifndef WIN32
+#ifdef WIN32
+#include <windows.h>
+#include <wincrypt.h>
+#else
#include <fcntl.h>
#include <sys/time.h>
#endif
@@ -62,7 +61,7 @@ static inline int64_t GetPerformanceCounter() noexcept
__asm__ volatile ("rdtsc" : "=a"(r1), "=d"(r2)); // Constrain r1 to rax and r2 to rdx.
return (r2 << 32) | r1;
#else
- // Fall back to using C++11 clock (usually microsecond or nanosecond precision)
+ // Fall back to using standard library clock (usually microsecond or nanosecond precision)
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
}
@@ -222,14 +221,14 @@ static void SeedHardwareSlow(CSHA512& hasher) noexcept {
}
/** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */
-static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA512& hasher) noexcept
+static void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration dur, CSHA512& hasher) noexcept
{
CSHA512 inner_hasher;
inner_hasher.Write(seed, sizeof(seed));
// Hash loop
unsigned char buffer[64];
- int64_t stop = GetTimeMicros() + microseconds;
+ const auto stop{SteadyClock::now() + dur};
do {
for (int i = 0; i < 1000; ++i) {
inner_hasher.Finalize(buffer);
@@ -239,7 +238,7 @@ static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA51
// Benchmark operation and feed it into outer hasher.
int64_t perf = GetPerformanceCounter();
hasher.Write((const unsigned char*)&perf, sizeof(perf));
- } while (GetTimeMicros() < stop);
+ } while (SteadyClock::now() < stop);
// Produce output from inner state and feed it to outer hasher.
inner_hasher.Finalize(buffer);
@@ -438,7 +437,7 @@ public:
RNGState& GetRNGState() noexcept
{
- // This C++11 idiom relies on the guarantee that static variable are initialized
+ // This 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];
@@ -493,13 +492,13 @@ static void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept
}
/** Extract entropy from rng, strengthen it, and feed it into hasher. */
-static void SeedStrengthen(CSHA512& hasher, RNGState& rng, int microseconds) noexcept
+static void SeedStrengthen(CSHA512& hasher, RNGState& rng, SteadyClock::duration dur) noexcept
{
// Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher.
unsigned char strengthen_seed[32];
rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false);
// Strengthen the seed, and feed it into hasher.
- Strengthen(strengthen_seed, microseconds, hasher);
+ Strengthen(strengthen_seed, dur, hasher);
}
static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept
@@ -519,7 +518,7 @@ static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept
LogPrint(BCLog::RAND, "Feeding %i bytes of dynamic environment data into RNG\n", hasher.Size() - old_size);
// Strengthen for 10 ms
- SeedStrengthen(hasher, rng, 10000);
+ SeedStrengthen(hasher, rng, 10ms);
}
static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept
@@ -539,7 +538,7 @@ static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept
LogPrint(BCLog::RAND, "Feeding %i bytes of environment data into RNG\n", hasher.Size() - old_size);
// Strengthen for 100 ms
- SeedStrengthen(hasher, rng, 100000);
+ SeedStrengthen(hasher, rng, 100ms);
}
enum class RNGLevel {
@@ -599,18 +598,15 @@ uint256 GetRandHash() noexcept
void FastRandomContext::RandomSeed()
{
uint256 seed = GetRandHash();
- rng.SetKey(seed.begin(), 32);
+ rng.SetKey32(seed.begin());
requires_seed = false;
}
uint256 FastRandomContext::rand256() noexcept
{
- if (bytebuf_size < 32) {
- FillByteBuffer();
- }
+ if (requires_seed) RandomSeed();
uint256 ret;
- memcpy(ret.begin(), bytebuf + 64 - bytebuf_size, 32);
- bytebuf_size -= 32;
+ rng.Keystream(ret.data(), ret.size());
return ret;
}
@@ -624,9 +620,9 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
return ret;
}
-FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bytebuf_size(0), bitbuf_size(0)
+FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bitbuf_size(0)
{
- rng.SetKey(seed.begin(), 32);
+ rng.SetKey32(seed.begin());
}
bool Random_SanityCheck()
@@ -637,7 +633,7 @@ bool Random_SanityCheck()
* GetOSRand() overwrites all 32 bytes of the output given a maximum
* number of tries.
*/
- static const ssize_t MAX_TRIES = 1024;
+ static constexpr int MAX_TRIES{1024};
uint8_t data[NUM_OS_RANDOM_BYTES];
bool overwritten[NUM_OS_RANDOM_BYTES] = {}; /* Tracks which bytes have been overwritten at least once */
int num_overwritten;
@@ -675,25 +671,22 @@ bool Random_SanityCheck()
return true;
}
-FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0)
+FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), bitbuf_size(0)
{
if (!fDeterministic) {
return;
}
uint256 seed;
- rng.SetKey(seed.begin(), 32);
+ rng.SetKey32(seed.begin());
}
FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexcept
{
requires_seed = from.requires_seed;
rng = from.rng;
- std::copy(std::begin(from.bytebuf), std::end(from.bytebuf), std::begin(bytebuf));
- bytebuf_size = from.bytebuf_size;
bitbuf = from.bitbuf;
bitbuf_size = from.bitbuf_size;
from.requires_seed = true;
- from.bytebuf_size = 0;
from.bitbuf_size = 0;
return *this;
}
diff --git a/src/random.h b/src/random.h
index 5fe20c5f76..49c0dff5bf 100644
--- a/src/random.h
+++ b/src/random.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,6 +15,7 @@
#include <chrono>
#include <cstdint>
#include <limits>
+#include <vector>
/**
* Overall design of the RNG and entropy sources.
@@ -145,23 +146,11 @@ private:
bool requires_seed;
ChaCha20 rng;
- unsigned char bytebuf[64];
- int bytebuf_size;
-
uint64_t bitbuf;
int bitbuf_size;
void RandomSeed();
- void FillByteBuffer()
- {
- if (requires_seed) {
- RandomSeed();
- }
- rng.Keystream(bytebuf, sizeof(bytebuf));
- bytebuf_size = sizeof(bytebuf);
- }
-
void FillBitBuffer()
{
bitbuf = rand64();
@@ -185,10 +174,10 @@ public:
/** Generate a random 64-bit integer. */
uint64_t rand64() noexcept
{
- if (bytebuf_size < 8) FillByteBuffer();
- uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size);
- bytebuf_size -= 8;
- return ret;
+ if (requires_seed) RandomSeed();
+ unsigned char buf[8];
+ rng.Keystream(buf, 8);
+ return ReadLE64(buf);
}
/** Generate a random (bits)-bit integer. */
@@ -200,7 +189,7 @@ public:
return rand64() >> (64 - bits);
} else {
if (bitbuf_size < bits) FillBitBuffer();
- uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits));
+ uint64_t ret = bitbuf & (~uint64_t{0} >> (64 - bits));
bitbuf >>= bits;
bitbuf_size -= bits;
return ret;
@@ -250,7 +239,7 @@ public:
/* interval [0..0] */ Dur{0};
};
- // Compatibility with the C++11 UniformRandomBitGenerator concept
+ // Compatibility with the 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(); }
diff --git a/src/randomenv.cpp b/src/randomenv.cpp
index 9e58180b7a..3e4d5a587d 100644
--- a/src/randomenv.cpp
+++ b/src/randomenv.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,21 +13,21 @@
#include <compat/cpuid.h>
#include <crypto/sha512.h>
#include <support/cleanse.h>
-#include <util/time.h> // for GetTime()
-#ifdef WIN32
-#include <compat/compat.h>
-#endif
+#include <util/time.h>
#include <algorithm>
#include <atomic>
+#include <cstdint>
+#include <cstring>
#include <chrono>
#include <climits>
#include <thread>
#include <vector>
-#include <stdint.h>
-#include <string.h>
-#ifndef WIN32
+#ifdef WIN32
+#include <windows.h>
+#include <winreg.h>
+#else
#include <sys/types.h> // must go before a number of other headers
#include <fcntl.h>
#include <netinet/in.h>
@@ -250,7 +250,7 @@ void RandAddDynamicEnv(CSHA512& hasher)
gettimeofday(&tv, nullptr);
hasher << tv;
#endif
- // Probably redundant, but also use all the clocks C++11 provides:
+ // Probably redundant, but also use all the standard library clocks:
hasher << std::chrono::system_clock::now().time_since_epoch().count();
hasher << std::chrono::steady_clock::now().time_since_epoch().count();
hasher << std::chrono::high_resolution_clock::now().time_since_epoch().count();
diff --git a/src/rest.cpp b/src/rest.cpp
index 7f00db2222..fa119ddfb7 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -236,7 +236,7 @@ static bool rest_headers(const std::any& context,
switch (rf) {
case RESTResponseFormat::BINARY: {
- CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ssHeader{};
for (const CBlockIndex *pindex : headers) {
ssHeader << pindex->GetBlockHeader();
}
@@ -248,7 +248,7 @@ static bool rest_headers(const std::any& context,
}
case RESTResponseFormat::HEX: {
- CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ssHeader{};
for (const CBlockIndex *pindex : headers) {
ssHeader << pindex->GetBlockHeader();
}
@@ -305,8 +305,10 @@ static bool rest_block(const std::any& context,
if (chainman.m_blockman.IsBlockPruned(pblockindex))
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
- if (!ReadBlockFromDisk(block, pblockindex, chainman.GetParams().GetConsensus()))
- return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
+ }
+
+ if (!ReadBlockFromDisk(block, pblockindex, chainman.GetParams().GetConsensus())) {
+ return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
switch (rf) {
@@ -433,7 +435,7 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const
switch (rf) {
case RESTResponseFormat::BINARY: {
- CDataStream ssHeader{SER_NETWORK, PROTOCOL_VERSION};
+ DataStream ssHeader{};
for (const uint256& header : filter_headers) {
ssHeader << header;
}
@@ -444,7 +446,7 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const
return true;
}
case RESTResponseFormat::HEX: {
- CDataStream ssHeader{SER_NETWORK, PROTOCOL_VERSION};
+ DataStream ssHeader{};
for (const uint256& header : filter_headers) {
ssHeader << header;
}
@@ -532,7 +534,7 @@ static bool rest_block_filter(const std::any& context, HTTPRequest* req, const s
switch (rf) {
case RESTResponseFormat::BINARY: {
- CDataStream ssResp{SER_NETWORK, PROTOCOL_VERSION};
+ DataStream ssResp{};
ssResp << filter;
std::string binaryResp = ssResp.str();
@@ -541,7 +543,7 @@ static bool rest_block_filter(const std::any& context, HTTPRequest* req, const s
return true;
}
case RESTResponseFormat::HEX: {
- CDataStream ssResp{SER_NETWORK, PROTOCOL_VERSION};
+ DataStream ssResp{};
ssResp << filter;
std::string strHex = HexStr(ssResp) + "\n";
@@ -590,6 +592,48 @@ static bool rest_chaininfo(const std::any& context, HTTPRequest* req, const std:
}
}
+
+RPCHelpMan getdeploymentinfo();
+
+static bool rest_deploymentinfo(const std::any& context, HTTPRequest* req, const std::string& str_uri_part)
+{
+ if (!CheckWarmup(req)) return false;
+
+ std::string hash_str;
+ const RESTResponseFormat rf = ParseDataFormat(hash_str, str_uri_part);
+
+ switch (rf) {
+ case RESTResponseFormat::JSON: {
+ JSONRPCRequest jsonRequest;
+ jsonRequest.context = context;
+ jsonRequest.params = UniValue(UniValue::VARR);
+
+ if (!hash_str.empty()) {
+ uint256 hash;
+ if (!ParseHashStr(hash_str, hash)) {
+ return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hash_str);
+ }
+
+ const ChainstateManager* chainman = GetChainman(context, req);
+ if (!chainman) return false;
+ if (!WITH_LOCK(::cs_main, return chainman->m_blockman.LookupBlockIndex(ParseHashV(hash_str, "blockhash")))) {
+ return RESTERR(req, HTTP_BAD_REQUEST, "Block not found");
+ }
+
+ jsonRequest.params.pushKV("blockhash", hash_str);
+ }
+
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(HTTP_OK, getdeploymentinfo().HandleRequest(jsonRequest).write() + "\n");
+ return true;
+ }
+ default: {
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
+ }
+ }
+
+}
+
static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::string& str_uri_part)
{
if (!CheckWarmup(req))
@@ -608,7 +652,20 @@ static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::s
case RESTResponseFormat::JSON: {
std::string str_json;
if (param == "contents") {
- str_json = MempoolToJSON(*mempool, true).write() + "\n";
+ const std::string raw_verbose{req->GetQueryParameter("verbose").value_or("true")};
+ if (raw_verbose != "true" && raw_verbose != "false") {
+ return RESTERR(req, HTTP_BAD_REQUEST, "The \"verbose\" query parameter must be either \"true\" or \"false\".");
+ }
+ const std::string raw_mempool_sequence{req->GetQueryParameter("mempool_sequence").value_or("false")};
+ if (raw_mempool_sequence != "true" && raw_mempool_sequence != "false") {
+ return RESTERR(req, HTTP_BAD_REQUEST, "The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
+ }
+ const bool verbose{raw_verbose == "true"};
+ const bool mempool_sequence{raw_mempool_sequence == "true"};
+ if (verbose && mempool_sequence) {
+ return RESTERR(req, HTTP_BAD_REQUEST, "Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
+ }
+ str_json = MempoolToJSON(*mempool, verbose, mempool_sequence).write() + "\n";
} else {
str_json = MempoolInfoToJSON(*mempool).write() + "\n";
}
@@ -749,7 +806,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA
return RESTERR(req, HTTP_BAD_REQUEST, "Combination of URI scheme inputs and raw post data is not allowed");
- CDataStream oss(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream oss{};
oss << strRequestMutable;
oss >> fCheckMemPool;
oss >> vOutPoints;
@@ -822,7 +879,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
case RESTResponseFormat::BINARY: {
// serialize data
// use exact same output as mentioned in Bip64
- CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ssGetUTXOResponse{};
ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
@@ -832,7 +889,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
}
case RESTResponseFormat::HEX: {
- CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ssGetUTXOResponse{};
ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
std::string strHex = HexStr(ssGetUTXOResponse) + "\n";
@@ -902,7 +959,7 @@ static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req,
}
switch (rf) {
case RESTResponseFormat::BINARY: {
- CDataStream ss_blockhash(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ss_blockhash{};
ss_blockhash << pblockindex->GetBlockHash();
req->WriteHeader("Content-Type", "application/octet-stream");
req->WriteReply(HTTP_OK, ss_blockhash.str());
@@ -939,6 +996,8 @@ static const struct {
{"/rest/mempool/", rest_mempool},
{"/rest/headers/", rest_headers},
{"/rest/getutxos", rest_getutxos},
+ {"/rest/deploymentinfo/", rest_deploymentinfo},
+ {"/rest/deploymentinfo", rest_deploymentinfo},
{"/rest/blockhashbyheight/", rest_blockhash_by_height},
};
diff --git a/src/reverse_iterator.h b/src/reverse_iterator.h
index 729d8c11cc..4db001c04b 100644
--- a/src/reverse_iterator.h
+++ b/src/reverse_iterator.h
@@ -4,7 +4,7 @@
#define BITCOIN_REVERSE_ITERATOR_H
/**
- * Template used for reverse iteration in C++11 range-based for loops.
+ * Template used for reverse iteration in range-based for loops.
*
* std::vector<int> v = {1, 2, 3, 4, 5};
* for (auto x : reverse_iterate(v))
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 93d11c8276..1a9b265fbe 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -25,6 +25,7 @@
#include <net_processing.h>
#include <node/blockstorage.h>
#include <node/context.h>
+#include <node/transaction.h>
#include <node/utxo_snapshot.h>
#include <primitives/transaction.h>
#include <rpc/server.h>
@@ -181,7 +182,8 @@ UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIn
case TxVerbosity::SHOW_DETAILS:
case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
CBlockUndo blockUndo;
- const bool have_undo{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))};
+ const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
+ const bool have_undo{is_not_pruned && UndoReadFromDisk(blockUndo, blockindex)};
for (size_t i = 0; i < block.vtx.size(); ++i) {
const CTransactionRef& tx = block.vtx.at(i);
@@ -428,7 +430,10 @@ static RPCHelpMan getblockfrompeer()
"getblockfrompeer",
"Attempt to fetch block from a given peer.\n\n"
"We must have the header for this block, e.g. using submitheader.\n"
- "Subsequent calls for the same block and a new peer will cause the response from the previous peer to be ignored.\n\n"
+ "Subsequent calls for the same block and a new peer will cause the response from the previous peer to be ignored.\n"
+ "Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n"
+ "When a peer does not respond with a block, we will disconnect.\n"
+ "Note: The block could be re-pruned as soon as it is received.\n\n"
"Returns an empty JSON object if the request was successfully scheduled.",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"},
@@ -441,11 +446,6 @@ static RPCHelpMan getblockfrompeer()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {
- UniValue::VSTR, // blockhash
- UniValue::VNUM, // peer_id
- });
-
const NodeContext& node = EnsureAnyNodeContext(request.context);
ChainstateManager& chainman = EnsureChainman(node);
PeerManager& peerman = EnsurePeerman(node);
@@ -459,6 +459,12 @@ static RPCHelpMan getblockfrompeer()
throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
}
+ // Fetching blocks before the node has syncing past their height can prevent block files from
+ // being pruned, so we avoid it if the node is in prune mode.
+ if (chainman.m_blockman.IsPruneMode() && index->nHeight > WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()->nHeight)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "In prune mode, only blocks that the node has already synced previously can be fetched from a peer");
+ }
+
const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA);
if (block_has_data) {
throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
@@ -560,7 +566,7 @@ static RPCHelpMan getblockheader()
if (!fVerbose)
{
- CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ssBlock{};
ssBlock << pblockindex->GetBlockHeader();
std::string strHex = HexStr(ssBlock);
return strHex;
@@ -571,30 +577,38 @@ static RPCHelpMan getblockheader()
};
}
-static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
+static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
{
- AssertLockHeld(::cs_main);
CBlock block;
- if (blockman.IsBlockPruned(pblockindex)) {
- throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
+ {
+ LOCK(cs_main);
+ if (blockman.IsBlockPruned(pblockindex)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
+ }
}
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) {
// Block not found on disk. This could be because we have the block
// header in our index but not yet have the block or did not accept the
- // block.
+ // block. Or if the block was pruned right after we released the lock above.
throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
}
return block;
}
-static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
{
- AssertLockHeld(::cs_main);
CBlockUndo blockUndo;
- if (blockman.IsBlockPruned(pblockindex)) {
- throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
+
+ // The Genesis block does not have undo data
+ if (pblockindex->nHeight == 0) return blockUndo;
+
+ {
+ LOCK(cs_main);
+ if (blockman.IsBlockPruned(pblockindex)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
+ }
}
if (!UndoReadFromDisk(blockUndo, pblockindex)) {
@@ -637,7 +651,8 @@ static RPCHelpMan getblock()
"If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).\n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
- {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs"},
+ {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs",
+ RPCArgOptions{.skip_type_check = true}},
},
{
RPCResult{"for verbosity = 0",
@@ -709,7 +724,6 @@ static RPCHelpMan getblock()
}
}
- CBlock block;
const CBlockIndex* pblockindex;
const CBlockIndex* tip;
ChainstateManager& chainman = EnsureAnyChainman(request.context);
@@ -721,10 +735,10 @@ static RPCHelpMan getblock()
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
-
- block = GetBlockChecked(chainman.m_blockman, pblockindex);
}
+ const CBlock block{GetBlockChecked(chainman.m_blockman, pblockindex)};
+
if (verbosity <= 0)
{
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
@@ -762,10 +776,11 @@ static RPCHelpMan pruneblockchain()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- if (!node::fPruneMode)
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
+ if (!chainman.m_blockman.IsPruneMode()) {
throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
+ }
- ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
Chainstate& active_chainstate = chainman.ActiveChainstate();
CChain& active_chain = active_chainstate.m_chain;
@@ -856,7 +871,11 @@ static RPCHelpMan gettxoutsetinfo()
"Note this call may take some time if you are not using coinstatsindex.\n",
{
{"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_2"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."},
- {"hash_or_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"the current best block"}, "The block hash or height of the target height (only available with coinstatsindex).", RPCArgOptions{.type_str={"", "string or numeric"}}},
+ {"hash_or_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"the current best block"}, "The block hash or height of the target height (only available with coinstatsindex).",
+ RPCArgOptions{
+ .skip_type_check = true,
+ .type_str = {"", "string or numeric"},
+ }},
{"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."},
},
RPCResult{
@@ -1092,7 +1111,7 @@ static RPCHelpMan verifychain()
{"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
},
RPCResult{
- RPCResult::Type::BOOL, "", "Verified or not"},
+ RPCResult::Type::BOOL, "", "Verification finished successfully. If false, check debug.log for reason."},
RPCExamples{
HelpExampleCli("verifychain", "")
+ HelpExampleRpc("verifychain", "")
@@ -1107,7 +1126,7 @@ static RPCHelpMan verifychain()
Chainstate& active_chainstate = chainman.ActiveChainstate();
return CVerifyDB().VerifyDB(
- active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth);
+ active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth) == VerifyDBResult::SUCCESS;
},
};
}
@@ -1230,7 +1249,6 @@ RPCHelpMan getblockchaininfo()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- const ArgsManager& args{EnsureAnyArgsman(request.context)};
ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
Chainstate& active_chainstate = chainman.ActiveChainstate();
@@ -1249,15 +1267,14 @@ RPCHelpMan getblockchaininfo()
obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
obj.pushKV("chainwork", tip.nChainWork.GetHex());
obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
- obj.pushKV("pruned", node::fPruneMode);
- if (node::fPruneMode) {
+ obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
+ if (chainman.m_blockman.IsPruneMode()) {
obj.pushKV("pruneheight", chainman.m_blockman.GetFirstStoredBlock(tip)->nHeight);
- // if 0, execution bypasses the whole if block.
- bool automatic_pruning{args.GetIntArg("-prune", 0) != 1};
+ const bool automatic_pruning{chainman.m_blockman.GetPruneTarget() != BlockManager::PRUNE_TARGET_MANUAL};
obj.pushKV("automatic_pruning", automatic_pruning);
if (automatic_pruning) {
- obj.pushKV("prune_target_size", node::nPruneTarget);
+ obj.pushKV("prune_target_size", chainman.m_blockman.GetPruneTarget());
}
}
@@ -1307,7 +1324,7 @@ UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager&
}
} // anon namespace
-static RPCHelpMan getdeploymentinfo()
+RPCHelpMan getdeploymentinfo()
{
return RPCHelpMan{"getdeploymentinfo",
"Returns an object containing various state info regarding deployments of consensus changes.",
@@ -1726,7 +1743,11 @@ static RPCHelpMan getblockstats()
"\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
"It won't work for some heights with pruning.\n",
{
- {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", RPCArgOptions{.type_str={"", "string or numeric"}}},
+ {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block",
+ RPCArgOptions{
+ .skip_type_check = true,
+ .type_str = {"", "string or numeric"},
+ }},
{"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)",
{
{"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
@@ -1771,8 +1792,10 @@ static RPCHelpMan getblockstats()
{RPCResult::Type::NUM, "total_weight", /*optional=*/true, "Total weight of all non-coinbase transactions"},
{RPCResult::Type::NUM, "totalfee", /*optional=*/true, "The fee total"},
{RPCResult::Type::NUM, "txs", /*optional=*/true, "The number of transactions (including coinbase)"},
- {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs"},
+ {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs (not discounting op_return and similar)"},
{RPCResult::Type::NUM, "utxo_size_inc", /*optional=*/true, "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
+ {RPCResult::Type::NUM, "utxo_increase_actual", /*optional=*/true, "The increase/decrease in the number of unspent outputs, not counting unspendables"},
+ {RPCResult::Type::NUM, "utxo_size_inc_actual", /*optional=*/true, "The increase/decrease in size for the utxo index, not counting unspendables"},
}},
RPCExamples{
HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
@@ -1783,7 +1806,6 @@ static RPCHelpMan getblockstats()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
ChainstateManager& chainman = EnsureAnyChainman(request.context);
- LOCK(cs_main);
const CBlockIndex& pindex{*CHECK_NONFATAL(ParseHashOrHeight(request.params[0], chainman))};
std::set<std::string> stats;
@@ -1803,7 +1825,7 @@ static RPCHelpMan getblockstats()
const bool do_medianfee = do_all || stats.count("medianfee") != 0;
const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0;
const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
- SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
+ SetHasKeys(stats, "utxo_increase", "utxo_increase_actual", "utxo_size_inc", "utxo_size_inc_actual", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
const bool loop_outputs = do_all || loop_inputs || stats.count("total_out");
const bool do_calculate_size = do_mediantxsize ||
SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
@@ -1825,7 +1847,9 @@ static RPCHelpMan getblockstats()
int64_t swtxs = 0;
int64_t total_size = 0;
int64_t total_weight = 0;
+ int64_t utxos = 0;
int64_t utxo_size_inc = 0;
+ int64_t utxo_size_inc_actual = 0;
std::vector<CAmount> fee_array;
std::vector<std::pair<CAmount, int64_t>> feerate_array;
std::vector<int64_t> txsize_array;
@@ -1838,7 +1862,18 @@ static RPCHelpMan getblockstats()
if (loop_outputs) {
for (const CTxOut& out : tx->vout) {
tx_total_out += out.nValue;
- utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
+
+ size_t out_size = GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
+ utxo_size_inc += out_size;
+
+ // The Genesis block and the repeated BIP30 block coinbases don't change the UTXO
+ // set counts, so they have to be excluded from the statistics
+ if (pindex.nHeight == 0 || (IsBIP30Repeat(pindex) && tx->IsCoinBase())) continue;
+ // Skip unspendable outputs since they are not included in the UTXO set
+ if (out.scriptPubKey.IsUnspendable()) continue;
+
+ ++utxos;
+ utxo_size_inc_actual += out_size;
}
}
@@ -1880,7 +1915,9 @@ static RPCHelpMan getblockstats()
const CTxOut& prevoutput = coin.out;
tx_total_in += prevoutput.nValue;
- utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
+ size_t prevout_size = GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
+ utxo_size_inc -= prevout_size;
+ utxo_size_inc_actual -= prevout_size;
}
CAmount txfee = tx_total_in - tx_total_out;
@@ -1940,6 +1977,8 @@ static RPCHelpMan getblockstats()
ret_all.pushKV("txs", (int64_t)block.vtx.size());
ret_all.pushKV("utxo_increase", outputs - inputs);
ret_all.pushKV("utxo_size_inc", utxo_size_inc);
+ ret_all.pushKV("utxo_increase_actual", utxos - inputs);
+ ret_all.pushKV("utxo_size_inc_actual", utxo_size_inc_actual);
if (do_all) {
return ret_all;
@@ -2019,6 +2058,40 @@ public:
}
};
+static const auto scan_action_arg_desc = RPCArg{
+ "action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
+ "\"start\" for starting a scan\n"
+ "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
+ "\"status\" for progress report (in %) of the current scan"
+};
+
+static const auto scan_objects_arg_desc = RPCArg{
+ "scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
+ "Every scan object is either a string descriptor or an object:",
+ {
+ {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
+ {
+ {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
+ {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
+ }},
+ },
+ RPCArgOptions{.oneline_description="[scanobjects,...]"},
+};
+
+static const auto scan_result_abort = RPCResult{
+ "when action=='abort'", RPCResult::Type::BOOL, "success",
+ "True if scan will be aborted (not necessarily before this RPC returns), or false if there is no scan to abort"
+};
+static const auto scan_result_status_none = RPCResult{
+ "when action=='status' and no scan is in progress - possibly already completed", RPCResult::Type::NONE, "", ""
+};
+static const auto scan_result_status_some = RPCResult{
+ "when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "",
+ {{RPCResult::Type::NUM, "progress", "Approximate percent complete"},}
+};
+
+
static RPCHelpMan scantxoutset()
{
// scriptPubKey corresponding to mainnet address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S
@@ -2032,27 +2105,18 @@ static RPCHelpMan scantxoutset()
" combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
" pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
" sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
+ " tr(<pubkey>) P2TR\n"
+ " tr(<pubkey>,{pk(<pubkey>)}) P2TR with single fallback pubkey in tapscript\n"
+ " rawtr(<pubkey>) P2TR with the specified key as output key rather than inner\n"
+ " wsh(and_v(v:pk(<pubkey>),after(2))) P2WSH miniscript with mandatory pubkey and a timelock\n"
"\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
"or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
"unhardened or hardened child keys.\n"
"In the latter case, a range needs to be specified by below if different from 1000.\n"
"For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
{
- {"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
- "\"start\" for starting a scan\n"
- "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
- "\"status\" for progress report (in %) of the current scan"},
- {"scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
- "Every scan object is either a string descriptor or an object:",
- {
- {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
- {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
- {
- {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
- {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
- }},
- },
- RPCArgOptions{.oneline_description="[scanobjects,...]"}},
+ scan_action_arg_desc,
+ scan_objects_arg_desc,
},
{
RPCResult{"when action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
@@ -2069,17 +2133,15 @@ static RPCHelpMan scantxoutset()
{RPCResult::Type::STR_HEX, "scriptPubKey", "The script key"},
{RPCResult::Type::STR, "desc", "A specialized descriptor for the matched scriptPubKey"},
{RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
+ {RPCResult::Type::BOOL, "coinbase", "Whether this is a coinbase output"},
{RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
}},
}},
{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
}},
- RPCResult{"when action=='abort'", RPCResult::Type::BOOL, "success", "True if scan will be aborted (not necessarily before this RPC returns), or false if there is no scan to abort"},
- RPCResult{"when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "",
- {
- {RPCResult::Type::NUM, "progress", "Approximate percent complete"},
- }},
- RPCResult{"when action=='status' and no scan is in progress - possibly already completed", RPCResult::Type::NONE, "", ""},
+ scan_result_abort,
+ scan_result_status_some,
+ scan_result_status_none,
},
RPCExamples{
HelpExampleCli("scantxoutset", "start \'[\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]\'") +
@@ -2091,8 +2153,6 @@ static RPCHelpMan scantxoutset()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
-
UniValue result(UniValue::VOBJ);
if (request.params[0].get_str() == "status") {
CoinsViewScanReserver reserver;
@@ -2172,6 +2232,7 @@ static RPCHelpMan scantxoutset()
unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
unspent.pushKV("amount", ValueFromAmount(txo.nValue));
+ unspent.pushKV("coinbase", coin.IsCoinBase());
unspent.pushKV("height", (int32_t)coin.nHeight);
unspents.push_back(unspent);
@@ -2179,13 +2240,253 @@ static RPCHelpMan scantxoutset()
result.pushKV("unspents", unspents);
result.pushKV("total_amount", ValueFromAmount(total_in));
} else {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str()));
}
return result;
},
};
}
+/** RAII object to prevent concurrency issue when scanning blockfilters */
+static std::atomic<int> g_scanfilter_progress;
+static std::atomic<int> g_scanfilter_progress_height;
+static std::atomic<bool> g_scanfilter_in_progress;
+static std::atomic<bool> g_scanfilter_should_abort_scan;
+class BlockFiltersScanReserver
+{
+private:
+ bool m_could_reserve{false};
+public:
+ explicit BlockFiltersScanReserver() = default;
+
+ bool reserve() {
+ CHECK_NONFATAL(!m_could_reserve);
+ if (g_scanfilter_in_progress.exchange(true)) {
+ return false;
+ }
+ m_could_reserve = true;
+ return true;
+ }
+
+ ~BlockFiltersScanReserver() {
+ if (m_could_reserve) {
+ g_scanfilter_in_progress = false;
+ }
+ }
+};
+
+static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
+{
+ const CBlock block{GetBlockChecked(blockman, &blockindex)};
+ const CBlockUndo block_undo{GetUndoChecked(blockman, &blockindex)};
+
+ // Check if any of the outputs match the scriptPubKey
+ for (const auto& tx : block.vtx) {
+ if (std::any_of(tx->vout.cbegin(), tx->vout.cend(), [&](const auto& txout) {
+ return needles.count(std::vector<unsigned char>(txout.scriptPubKey.begin(), txout.scriptPubKey.end())) != 0;
+ })) {
+ return true;
+ }
+ }
+ // Check if any of the inputs match the scriptPubKey
+ for (const auto& txundo : block_undo.vtxundo) {
+ if (std::any_of(txundo.vprevout.cbegin(), txundo.vprevout.cend(), [&](const auto& coin) {
+ return needles.count(std::vector<unsigned char>(coin.out.scriptPubKey.begin(), coin.out.scriptPubKey.end())) != 0;
+ })) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static RPCHelpMan scanblocks()
+{
+ return RPCHelpMan{"scanblocks",
+ "\nReturn relevant blockhashes for given descriptors (requires blockfilterindex).\n"
+ "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
+ {
+ scan_action_arg_desc,
+ scan_objects_arg_desc,
+ RPCArg{"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "Height to start to scan from"},
+ RPCArg{"stop_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"chain tip"}, "Height to stop to scan"},
+ RPCArg{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
+ RPCArg{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {
+ {"filter_false_positives", RPCArg::Type::BOOL, RPCArg::Default{false}, "Filter false positives (slower and may fail on pruned nodes). Otherwise they may occur at a rate of 1/M"},
+ },
+ RPCArgOptions{.oneline_description="\"options\""}},
+ },
+ {
+ scan_result_status_none,
+ RPCResult{"When action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
+ {RPCResult::Type::NUM, "from_height", "The height we started the scan from"},
+ {RPCResult::Type::NUM, "to_height", "The height we ended the scan at"},
+ {RPCResult::Type::ARR, "relevant_blocks", "Blocks that may have matched a scanobject.", {
+ {RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"},
+ }},
+ }},
+ RPCResult{"when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "", {
+ {RPCResult::Type::NUM, "progress", "Approximate percent complete"},
+ {RPCResult::Type::NUM, "current_height", "Height of the block currently being scanned"},
+ },
+ },
+ scan_result_abort,
+ },
+ RPCExamples{
+ HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 300000") +
+ HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 100 150 basic") +
+ HelpExampleCli("scanblocks", "status") +
+ HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 300000") +
+ HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 100, 150, \"basic\"") +
+ HelpExampleRpc("scanblocks", "\"status\"")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ UniValue ret(UniValue::VOBJ);
+ if (request.params[0].get_str() == "status") {
+ BlockFiltersScanReserver reserver;
+ if (reserver.reserve()) {
+ // no scan in progress
+ return NullUniValue;
+ }
+ ret.pushKV("progress", g_scanfilter_progress.load());
+ ret.pushKV("current_height", g_scanfilter_progress_height.load());
+ return ret;
+ } else if (request.params[0].get_str() == "abort") {
+ BlockFiltersScanReserver reserver;
+ if (reserver.reserve()) {
+ // reserve was possible which means no scan was running
+ return false;
+ }
+ // set the abort flag
+ g_scanfilter_should_abort_scan = true;
+ return true;
+ }
+ else if (request.params[0].get_str() == "start") {
+ BlockFiltersScanReserver reserver;
+ if (!reserver.reserve()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
+ }
+ const std::string filtertype_name{request.params[4].isNull() ? "basic" : request.params[4].get_str()};
+
+ BlockFilterType filtertype;
+ if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
+ }
+
+ UniValue options{request.params[5].isNull() ? UniValue::VOBJ : request.params[5]};
+ bool filter_false_positives{options.exists("filter_false_positives") ? options["filter_false_positives"].get_bool() : false};
+
+ BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
+ if (!index) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
+ }
+
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ ChainstateManager& chainman = EnsureChainman(node);
+
+ // set the start-height
+ const CBlockIndex* block = nullptr;
+ const CBlockIndex* stop_block = nullptr;
+ {
+ LOCK(cs_main);
+ CChain& active_chain = chainman.ActiveChain();
+ block = active_chain.Genesis();
+ stop_block = active_chain.Tip();
+ if (!request.params[2].isNull()) {
+ block = active_chain[request.params[2].getInt<int>()];
+ if (!block) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height");
+ }
+ }
+ if (!request.params[3].isNull()) {
+ stop_block = active_chain[request.params[3].getInt<int>()];
+ if (!stop_block || stop_block->nHeight < block->nHeight) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height");
+ }
+ }
+ }
+ CHECK_NONFATAL(block);
+
+ // loop through the scan objects, add scripts to the needle_set
+ GCSFilter::ElementSet needle_set;
+ for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
+ FlatSigningProvider provider;
+ std::vector<CScript> scripts = EvalDescriptorStringOrObject(scanobject, provider);
+ for (const CScript& script : scripts) {
+ needle_set.emplace(script.begin(), script.end());
+ }
+ }
+ UniValue blocks(UniValue::VARR);
+ const int amount_per_chunk = 10000;
+ const CBlockIndex* start_index = block; // for remembering the start of a blockfilter range
+ std::vector<BlockFilter> filters;
+ const CBlockIndex* start_block = block; // for progress reporting
+ const int total_blocks_to_process = stop_block->nHeight - start_block->nHeight;
+
+ g_scanfilter_should_abort_scan = false;
+ g_scanfilter_progress = 0;
+ g_scanfilter_progress_height = start_block->nHeight;
+
+ while (block) {
+ node.rpc_interruption_point(); // allow a clean shutdown
+ if (g_scanfilter_should_abort_scan) {
+ LogPrintf("scanblocks RPC aborted at height %d.\n", block->nHeight);
+ break;
+ }
+ const CBlockIndex* next = nullptr;
+ {
+ LOCK(cs_main);
+ CChain& active_chain = chainman.ActiveChain();
+ next = active_chain.Next(block);
+ if (block == stop_block) next = nullptr;
+ }
+ if (start_index->nHeight + amount_per_chunk == block->nHeight || next == nullptr) {
+ LogPrint(BCLog::RPC, "Fetching blockfilters from height %d to height %d.\n", start_index->nHeight, block->nHeight);
+ if (index->LookupFilterRange(start_index->nHeight, block, filters)) {
+ for (const BlockFilter& filter : filters) {
+ // compare the elements-set with each filter
+ if (filter.GetFilter().MatchAny(needle_set)) {
+ if (filter_false_positives) {
+ // Double check the filter matches by scanning the block
+ const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
+
+ if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
+ continue;
+ }
+ }
+
+ blocks.push_back(filter.GetBlockHash().GetHex());
+ LogPrint(BCLog::RPC, "scanblocks: found match in %s\n", filter.GetBlockHash().GetHex());
+ }
+ }
+ }
+ start_index = block;
+
+ // update progress
+ int blocks_processed = block->nHeight - start_block->nHeight;
+ if (total_blocks_to_process > 0) { // avoid division by zero
+ g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
+ } else {
+ g_scanfilter_progress = 100;
+ }
+ g_scanfilter_progress_height = block->nHeight;
+ }
+ block = next;
+ }
+ ret.pushKV("from_height", start_block->nHeight);
+ ret.pushKV("to_height", g_scanfilter_progress_height.load());
+ ret.pushKV("relevant_blocks", blocks);
+ }
+ else {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str()));
+ }
+ return ret;
+},
+ };
+}
+
static RPCHelpMan getblockfilter()
{
return RPCHelpMan{"getblockfilter",
@@ -2421,6 +2722,7 @@ void RegisterBlockchainRPCCommands(CRPCTable& t)
{"blockchain", &verifychain},
{"blockchain", &preciousblock},
{"blockchain", &scantxoutset},
+ {"blockchain", &scanblocks},
{"blockchain", &getblockfilter},
{"hidden", &invalidateblock},
{"hidden", &reconsiderblock},
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 6cdb5fa48b..9ccb87b78a 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,8 +16,6 @@
#include <stdint.h>
#include <vector>
-extern RecursiveMutex cs_main;
-
class CBlock;
class CBlockIndex;
class Chainstate;
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 612dbbdacf..9449b9d197 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -1,13 +1,16 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <rpc/client.h>
+#include <tinyformat.h>
#include <util/system.h>
#include <set>
#include <stdint.h>
+#include <string>
+#include <string_view>
class CRPCConvertParam
{
@@ -83,6 +86,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendmany", 8, "fee_rate"},
{ "sendmany", 9, "verbose" },
{ "deriveaddresses", 1, "range" },
+ { "scanblocks", 1, "scanobjects" },
+ { "scanblocks", 2, "start_height" },
+ { "scanblocks", 3, "stop_height" },
+ { "scanblocks", 5, "options" },
{ "scantxoutset", 1, "scanobjects" },
{ "addmultisigaddress", 0, "nrequired" },
{ "addmultisigaddress", 1, "keys" },
@@ -99,6 +106,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getchaintxstats", 0, "nblocks" },
{ "gettransaction", 1, "include_watchonly" },
{ "gettransaction", 2, "verbose" },
+ { "getrawtransaction", 1, "verbosity" },
{ "getrawtransaction", 1, "verbose" },
{ "createrawtransaction", 0, "inputs" },
{ "createrawtransaction", 1, "outputs" },
@@ -109,6 +117,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "signrawtransactionwithkey", 2, "prevtxs" },
{ "signrawtransactionwithwallet", 1, "prevtxs" },
{ "sendrawtransaction", 1, "maxfeerate" },
+ { "sendrawtransaction", 2, "maxburnamount" },
{ "testmempoolaccept", 0, "rawtxs" },
{ "testmempoolaccept", 1, "maxfeerate" },
{ "submitpackage", 0, "package" },
@@ -222,11 +231,16 @@ private:
public:
CRPCConvertTable();
- bool convert(const std::string& method, int idx) {
- return (members.count(std::make_pair(method, idx)) > 0);
+ /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
+ UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx)
+ {
+ return members.count({method, param_idx}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value;
}
- bool convert(const std::string& method, const std::string& name) {
- return (membersByName.count(std::make_pair(method, name)) > 0);
+
+ /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
+ UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name)
+ {
+ return membersByName.count({method, param_name}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value;
}
};
@@ -243,13 +257,11 @@ static CRPCConvertTable rpcCvtTable;
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
* as well as objects and arrays.
*/
-UniValue ParseNonRFCJSONValue(const std::string& strVal)
+UniValue ParseNonRFCJSONValue(std::string_view raw)
{
- UniValue jVal;
- if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
- !jVal.isArray() || jVal.size()!=1)
- throw std::runtime_error(std::string("Error parsing JSON: ") + strVal);
- return jVal[0];
+ UniValue parsed;
+ if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
+ return parsed;
}
UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
@@ -257,15 +269,8 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
UniValue params(UniValue::VARR);
for (unsigned int idx = 0; idx < strParams.size(); idx++) {
- const std::string& strVal = strParams[idx];
-
- if (!rpcCvtTable.convert(strMethod, idx)) {
- // insert string value directly
- params.push_back(strVal);
- } else {
- // parse string as JSON, insert bool/number/object/etc. value
- params.push_back(ParseNonRFCJSONValue(strVal));
- }
+ std::string_view value{strParams[idx]};
+ params.push_back(rpcCvtTable.ArgToUniValue(value, strMethod, idx));
}
return params;
@@ -274,23 +279,29 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams)
{
UniValue params(UniValue::VOBJ);
+ UniValue positional_args{UniValue::VARR};
- for (const std::string &s: strParams) {
+ for (std::string_view s: strParams) {
size_t pos = s.find('=');
if (pos == std::string::npos) {
- throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)"));
+ positional_args.push_back(rpcCvtTable.ArgToUniValue(s, strMethod, positional_args.size()));
+ continue;
}
- std::string name = s.substr(0, pos);
- std::string value = s.substr(pos+1);
+ std::string name{s.substr(0, pos)};
+ std::string_view value{s.substr(pos+1)};
- if (!rpcCvtTable.convert(strMethod, name)) {
- // insert string value directly
- params.pushKV(name, value);
- } else {
- // parse string as JSON, insert bool/number/object/etc. value
- params.pushKV(name, ParseNonRFCJSONValue(value));
- }
+ // Intentionally overwrite earlier named values with later ones as a
+ // convenience for scripts and command line users that want to merge
+ // options.
+ params.pushKV(name, rpcCvtTable.ArgToUniValue(value, strMethod, name));
+ }
+
+ if (!positional_args.empty()) {
+ // Use __pushKV instead of pushKV to avoid overwriting an explicit
+ // "args" value with an implicit one. Let the RPC server handle the
+ // request as given.
+ params.__pushKV("args", positional_args);
}
return params;
diff --git a/src/rpc/client.h b/src/rpc/client.h
index b9fee5bbb3..3c5c4fc4d6 100644
--- a/src/rpc/client.h
+++ b/src/rpc/client.h
@@ -6,6 +6,9 @@
#ifndef BITCOIN_RPC_CLIENT_H
#define BITCOIN_RPC_CLIENT_H
+#include <string>
+#include <string_view>
+
#include <univalue.h>
/** Convert positional arguments to command-specific RPC representation */
@@ -17,6 +20,6 @@ UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector<s
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
* as well as objects and arrays.
*/
-UniValue ParseNonRFCJSONValue(const std::string& strVal);
+UniValue ParseNonRFCJSONValue(std::string_view raw);
#endif // BITCOIN_RPC_CLIENT_H
diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp
index 4de7fc4205..f5a6913572 100644
--- a/src/rpc/external_signer.cpp
+++ b/src/rpc/external_signer.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp
index e50bf00473..62396d4c58 100644
--- a/src/rpc/fees.cpp
+++ b/src/rpc/fees.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -63,8 +63,6 @@ static RPCHelpMan estimatesmartfee()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
-
CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
const NodeContext& node = EnsureAnyNodeContext(request.context);
const CTxMemPool& mempool = EnsureMemPool(node);
@@ -155,8 +153,6 @@ static RPCHelpMan estimaterawfee()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
-
CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index e390a7c15c..3a69e2d8a2 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -10,6 +10,7 @@
#include <chainparams.h>
#include <core_io.h>
#include <fs.h>
+#include <kernel/mempool_entry.h>
#include <node/mempool_persist_args.h>
#include <policy/rbf.h>
#include <policy/settings.h>
@@ -17,11 +18,14 @@
#include <rpc/server.h>
#include <rpc/server_util.h>
#include <rpc/util.h>
+#include <script/standard.h>
#include <txmempool.h>
#include <univalue.h>
#include <util/moneystr.h>
#include <util/time.h>
+#include <utility>
+
using kernel::DumpMempool;
using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
@@ -41,7 +45,11 @@ static RPCHelpMan sendrawtransaction()
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
{"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
"Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
- "/kvB.\nSet to 0 to accept any fee rate.\n"},
+ "/kvB.\nSet to 0 to accept any fee rate."},
+ {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(0)},
+ "Reject transactions with provably unspendable outputs (e.g. 'datacarrier' outputs that use the OP_RETURN opcode) greater than the specified value, expressed in " + CURRENCY_UNIT + ".\n"
+ "If burning funds through unspendable outputs is desired, increase this value.\n"
+ "This check is based on heuristics and does not guarantee spendability of outputs.\n"},
},
RPCResult{
RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
@@ -58,15 +66,19 @@ static RPCHelpMan sendrawtransaction()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {
- UniValue::VSTR,
- UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
- });
+ const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
CMutableTransaction mtx;
if (!DecodeHexTx(mtx, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
}
+
+ for (const auto& out : mtx.vout) {
+ if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
+ throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
+ }
+ }
+
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
@@ -123,6 +135,10 @@ static RPCHelpMan testmempoolaccept()
{RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",
{
{RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
+ {RPCResult::Type::STR_AMOUNT, "effective-feerate", /*optional=*/false, "the effective feerate in " + CURRENCY_UNIT + " per KvB. May differ from the base feerate if, for example, there are modified fees from prioritisetransaction or a package feerate was used."},
+ {RPCResult::Type::ARR, "effective-includes", /*optional=*/false, "transactions whose fees and vsizes are included in effective-feerate.",
+ {RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
+ }},
}},
{RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"},
}},
@@ -140,10 +156,6 @@ static RPCHelpMan testmempoolaccept()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {
- UniValue::VARR,
- UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
- });
const UniValue raw_transactions = request.params[0].get_array();
if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
throw JSONRPCError(RPC_INVALID_PARAMETER,
@@ -214,6 +226,12 @@ static RPCHelpMan testmempoolaccept()
result_inner.pushKV("vsize", virtual_size);
UniValue fees(UniValue::VOBJ);
fees.pushKV("base", ValueFromAmount(fee));
+ fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
+ UniValue effective_includes_res(UniValue::VARR);
+ for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
+ effective_includes_res.push_back(wtxid.ToString());
+ }
+ fees.pushKV("effective-includes", effective_includes_res);
result_inner.pushKV("fees", fees);
}
} else {
@@ -448,20 +466,17 @@ static RPCHelpMan getmempoolancestors()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
}
- CTxMemPool::setEntries setAncestors;
- uint64_t noLimit = std::numeric_limits<uint64_t>::max();
- std::string dummy;
- mempool.CalculateMemPoolAncestors(*it, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
+ auto ancestors{mempool.AssumeCalculateMemPoolAncestors(__func__, *it, CTxMemPool::Limits::NoLimits(), /*fSearchForParents=*/false)};
if (!fVerbose) {
UniValue o(UniValue::VARR);
- for (CTxMemPool::txiter ancestorIt : setAncestors) {
+ for (CTxMemPool::txiter ancestorIt : ancestors) {
o.push_back(ancestorIt->GetTx().GetHash().ToString());
}
return o;
} else {
UniValue o(UniValue::VOBJ);
- for (CTxMemPool::txiter ancestorIt : setAncestors) {
+ for (CTxMemPool::txiter ancestorIt : ancestors) {
const CTxMemPoolEntry &e = *ancestorIt;
const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
@@ -768,10 +783,13 @@ static RPCHelpMan submitpackage()
{RPCResult::Type::NUM, "vsize", "Virtual transaction size as defined in BIP 141."},
{RPCResult::Type::OBJ, "fees", "Transaction fees", {
{RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
+ {RPCResult::Type::STR_AMOUNT, "effective-feerate", /*optional=*/true, "if the transaction was not already in the mempool, the effective feerate in " + CURRENCY_UNIT + " per KvB. For example, the package feerate and/or feerate with modified fees from prioritisetransaction."},
+ {RPCResult::Type::ARR, "effective-includes", /*optional=*/true, "if effective-feerate is provided, the wtxids of the transactions whose fees and vsizes are included in effective-feerate.",
+ {{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
+ }},
}},
}}
}},
- {RPCResult::Type::STR_AMOUNT, "package-feerate", /*optional=*/true, "package feerate used for feerate checks in " + CURRENCY_UNIT + " per KvB. Excludes transactions which were deduplicated or accepted individually."},
{RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
{
{RPCResult::Type::STR_HEX, "", "The transaction id"},
@@ -787,9 +805,6 @@ static RPCHelpMan submitpackage()
if (!Params().IsMockableChain()) {
throw std::runtime_error("submitpackage is for regression testing (-regtest mode) only");
}
- RPCTypeCheck(request.params, {
- UniValue::VARR,
- });
const UniValue raw_transactions = request.params[0].get_array();
if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
throw JSONRPCError(RPC_INVALID_PARAMETER,
@@ -838,15 +853,16 @@ static RPCHelpMan submitpackage()
NONFATAL_UNREACHABLE();
}
}
+ size_t num_broadcast{0};
for (const auto& tx : txns) {
- size_t num_submitted{0};
std::string err_string;
- const auto err = BroadcastTransaction(node, tx, err_string, 0, true, true);
+ const auto err = BroadcastTransaction(node, tx, err_string, /*max_tx_fee=*/0, /*relay=*/true, /*wait_callback=*/true);
if (err != TransactionError::OK) {
throw JSONRPCTransactionError(err,
strprintf("transaction broadcast failed: %s (all transactions were submitted, %d transactions were broadcast successfully)",
- err_string, num_submitted));
+ err_string, num_broadcast));
}
+ num_broadcast++;
}
UniValue rpc_result{UniValue::VOBJ};
UniValue tx_result_map{UniValue::VOBJ};
@@ -856,6 +872,7 @@ static RPCHelpMan submitpackage()
CHECK_NONFATAL(it != package_result.m_tx_results.end());
UniValue result_inner{UniValue::VOBJ};
result_inner.pushKV("txid", tx->GetHash().GetHex());
+ const auto& tx_result = it->second;
if (it->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS) {
result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
}
@@ -864,6 +881,17 @@ static RPCHelpMan submitpackage()
result_inner.pushKV("vsize", int64_t{it->second.m_vsize.value()});
UniValue fees(UniValue::VOBJ);
fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value()));
+ if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
+ // Effective feerate is not provided for MEMPOOL_ENTRY transactions even
+ // though modified fees is known, because it is unknown whether package
+ // feerate was used when it was originally submitted.
+ fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
+ UniValue effective_includes_res(UniValue::VARR);
+ for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
+ effective_includes_res.push_back(wtxid.ToString());
+ }
+ fees.pushKV("effective-includes", effective_includes_res);
+ }
result_inner.pushKV("fees", fees);
if (it->second.m_replaced_transactions.has_value()) {
for (const auto& ptx : it->second.m_replaced_transactions.value()) {
@@ -874,9 +902,6 @@ static RPCHelpMan submitpackage()
tx_result_map.pushKV(tx->GetWitnessHash().GetHex(), result_inner);
}
rpc_result.pushKV("tx-results", tx_result_map);
- if (package_result.m_package_feerate.has_value()) {
- rpc_result.pushKV("package-feerate", ValueFromAmount(package_result.m_package_feerate.value().GetFeePerK()));
- }
UniValue replaced_list(UniValue::VARR);
for (const uint256& hash : replaced_txids) replaced_list.push_back(hash.ToString());
rpc_result.pushKV("replaced-transactions", replaced_list);
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index c4bd03fa9f..8753f845a5 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -441,7 +441,7 @@ static RPCHelpMan prioritisetransaction()
"Accepts the transaction into mined blocks at a higher (or lower) priority\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id."},
- {"dummy", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "API-Compatibility for previous API. Must be zero or null.\n"
+ {"dummy", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "API-Compatibility for previous API. Must be zero or null.\n"
" DEPRECATED. For forward compatibility use named arguments and omit this parameter."},
{"fee_delta", RPCArg::Type::NUM, RPCArg::Optional::NO, "The fee value (in satoshis) to add (or subtract, if negative).\n"
" Note, that this value is not a fee rate. It is a value to modify absolute fee of the TX.\n"
@@ -513,8 +513,8 @@ static RPCHelpMan getblocktemplate()
{
{"template_request", RPCArg::Type::OBJ, RPCArg::Default{UniValue::VOBJ}, "Format of the template",
{
- {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
- {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
+ {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
+ {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED, "A list of strings",
{
{"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
}},
@@ -730,10 +730,10 @@ static RPCHelpMan getblocktemplate()
// Update block
static CBlockIndex* pindexPrev;
- static int64_t nStart;
+ static int64_t time_start;
static std::unique_ptr<CBlockTemplate> pblocktemplate;
if (pindexPrev != active_chain.Tip() ||
- (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
+ (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
pindexPrev = nullptr;
@@ -741,7 +741,7 @@ static RPCHelpMan getblocktemplate()
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrevNew = active_chain.Tip();
- nStart = GetTime();
+ time_start = GetTime();
// Create new block
CScript scriptDummy = CScript() << OP_TRUE;
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index d701a180ab..7ffa777ef4 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -114,7 +114,7 @@ static RPCHelpMan getpeerinfo()
{
{RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"}
}},
- {RPCResult::Type::BOOL, "relaytxes", /*optional=*/true, "Whether peer has asked us to relay transactions to it"},
+ {RPCResult::Type::BOOL, "relaytxes", "Whether we relay transactions to this peer"},
{RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"},
{RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"},
{RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"},
@@ -123,30 +123,30 @@ static RPCHelpMan getpeerinfo()
{RPCResult::Type::NUM, "bytesrecv", "The total bytes received"},
{RPCResult::Type::NUM_TIME, "conntime", "The " + UNIX_EPOCH_TIME + " of the connection"},
{RPCResult::Type::NUM, "timeoffset", "The time offset in seconds"},
- {RPCResult::Type::NUM, "pingtime", /*optional=*/true, "ping time (if available)"},
- {RPCResult::Type::NUM, "minping", /*optional=*/true, "minimum observed ping time (if any at all)"},
- {RPCResult::Type::NUM, "pingwait", /*optional=*/true, "ping wait (if non-zero)"},
+ {RPCResult::Type::NUM, "pingtime", /*optional=*/true, "The last ping time in milliseconds (ms), if any"},
+ {RPCResult::Type::NUM, "minping", /*optional=*/true, "The minimum observed ping time in milliseconds (ms), if any"},
+ {RPCResult::Type::NUM, "pingwait", /*optional=*/true, "The duration in milliseconds (ms) of an outstanding ping (if non-zero)"},
{RPCResult::Type::NUM, "version", "The peer version, such as 70001"},
{RPCResult::Type::STR, "subver", "The string version"},
{RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"},
{RPCResult::Type::BOOL, "bip152_hb_to", "Whether we selected peer as (compact blocks) high-bandwidth peer"},
{RPCResult::Type::BOOL, "bip152_hb_from", "Whether peer selected us as (compact blocks) high-bandwidth peer"},
- {RPCResult::Type::NUM, "startingheight", /*optional=*/true, "The starting height (block) of the peer"},
- {RPCResult::Type::NUM, "presynced_headers", /*optional=*/true, "The current height of header pre-synchronization with this peer, or -1 if no low-work sync is in progress"},
- {RPCResult::Type::NUM, "synced_headers", /*optional=*/true, "The last header we have in common with this peer"},
- {RPCResult::Type::NUM, "synced_blocks", /*optional=*/true, "The last block we have in common with this peer"},
- {RPCResult::Type::ARR, "inflight", /*optional=*/true, "",
+ {RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"},
+ {RPCResult::Type::NUM, "presynced_headers", "The current height of header pre-synchronization with this peer, or -1 if no low-work sync is in progress"},
+ {RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"},
+ {RPCResult::Type::NUM, "synced_blocks", "The last block we have in common with this peer"},
+ {RPCResult::Type::ARR, "inflight", "",
{
{RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"},
}},
- {RPCResult::Type::BOOL, "addr_relay_enabled", /*optional=*/true, "Whether we participate in address relay with this peer"},
- {RPCResult::Type::NUM, "addr_processed", /*optional=*/true, "The total number of addresses processed, excluding those dropped due to rate limiting"},
- {RPCResult::Type::NUM, "addr_rate_limited", /*optional=*/true, "The total number of addresses dropped due to rate limiting"},
+ {RPCResult::Type::BOOL, "addr_relay_enabled", "Whether we participate in address relay with this peer"},
+ {RPCResult::Type::NUM, "addr_processed", "The total number of addresses processed, excluding those dropped due to rate limiting"},
+ {RPCResult::Type::NUM, "addr_rate_limited", "The total number of addresses dropped due to rate limiting"},
{RPCResult::Type::ARR, "permissions", "Any special permissions that have been granted to this peer",
{
{RPCResult::Type::STR, "permission_type", Join(NET_PERMISSIONS_DOC, ",\n") + ".\n"},
}},
- {RPCResult::Type::NUM, "minfeefilter", /*optional=*/true, "The minimum fee rate for transactions this peer accepts"},
+ {RPCResult::Type::NUM, "minfeefilter", "The minimum fee rate for transactions this peer accepts"},
{RPCResult::Type::OBJ_DYN, "bytessent_per_msg", "",
{
{RPCResult::Type::NUM, "msg", "The total bytes sent aggregated by message type\n"
@@ -185,10 +185,18 @@ static RPCHelpMan getpeerinfo()
UniValue obj(UniValue::VOBJ);
CNodeStateStats statestats;
bool fStateStats = peerman.GetNodeStateStats(stats.nodeid, statestats);
+ // GetNodeStateStats() requires the existence of a CNodeState and a Peer object
+ // to succeed for this peer. These are created at connection initialisation and
+ // exist for the duration of the connection - except if there is a race where the
+ // peer got disconnected in between the GetNodeStats() and the GetNodeStateStats()
+ // calls. In this case, the peer doesn't need to be reported here.
+ if (!fStateStats) {
+ continue;
+ }
obj.pushKV("id", stats.nodeid);
obj.pushKV("addr", stats.m_addr_name);
if (stats.addrBind.IsValid()) {
- obj.pushKV("addrbind", stats.addrBind.ToString());
+ obj.pushKV("addrbind", stats.addrBind.ToStringAddrPort());
}
if (!(stats.addrLocal.empty())) {
obj.pushKV("addrlocal", stats.addrLocal);
@@ -197,9 +205,10 @@ static RPCHelpMan getpeerinfo()
if (stats.m_mapped_as != 0) {
obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
}
- ServiceFlags services{fStateStats ? statestats.their_services : ServiceFlags::NODE_NONE};
+ ServiceFlags services{statestats.their_services};
obj.pushKV("services", strprintf("%016x", services));
obj.pushKV("servicesnames", GetServicesNames(services));
+ obj.pushKV("relaytxes", statestats.m_relay_txs);
obj.pushKV("lastsend", count_seconds(stats.m_last_send));
obj.pushKV("lastrecv", count_seconds(stats.m_last_recv));
obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time));
@@ -214,7 +223,7 @@ static RPCHelpMan getpeerinfo()
if (stats.m_min_ping_time < std::chrono::microseconds::max()) {
obj.pushKV("minping", Ticks<SecondsDouble>(stats.m_min_ping_time));
}
- if (fStateStats && statestats.m_ping_wait > 0s) {
+ if (statestats.m_ping_wait > 0s) {
obj.pushKV("pingwait", Ticks<SecondsDouble>(statestats.m_ping_wait));
}
obj.pushKV("version", stats.nVersion);
@@ -225,27 +234,24 @@ static RPCHelpMan getpeerinfo()
obj.pushKV("inbound", stats.fInbound);
obj.pushKV("bip152_hb_to", stats.m_bip152_highbandwidth_to);
obj.pushKV("bip152_hb_from", stats.m_bip152_highbandwidth_from);
- if (fStateStats) {
- obj.pushKV("startingheight", statestats.m_starting_height);
- obj.pushKV("presynced_headers", statestats.presync_height);
- obj.pushKV("synced_headers", statestats.nSyncHeight);
- obj.pushKV("synced_blocks", statestats.nCommonHeight);
- UniValue heights(UniValue::VARR);
- for (const int height : statestats.vHeightInFlight) {
- heights.push_back(height);
- }
- obj.pushKV("inflight", heights);
- obj.pushKV("relaytxes", statestats.m_relay_txs);
- obj.pushKV("minfeefilter", ValueFromAmount(statestats.m_fee_filter_received));
- obj.pushKV("addr_relay_enabled", statestats.m_addr_relay_enabled);
- obj.pushKV("addr_processed", statestats.m_addr_processed);
- obj.pushKV("addr_rate_limited", statestats.m_addr_rate_limited);
+ obj.pushKV("startingheight", statestats.m_starting_height);
+ obj.pushKV("presynced_headers", statestats.presync_height);
+ obj.pushKV("synced_headers", statestats.nSyncHeight);
+ obj.pushKV("synced_blocks", statestats.nCommonHeight);
+ UniValue heights(UniValue::VARR);
+ for (const int height : statestats.vHeightInFlight) {
+ heights.push_back(height);
}
+ obj.pushKV("inflight", heights);
+ obj.pushKV("addr_relay_enabled", statestats.m_addr_relay_enabled);
+ obj.pushKV("addr_processed", statestats.m_addr_processed);
+ obj.pushKV("addr_rate_limited", statestats.m_addr_rate_limited);
UniValue permissions(UniValue::VARR);
for (const auto& permission : NetPermissions::ToStrings(stats.m_permission_flags)) {
permissions.push_back(permission);
}
obj.pushKV("permissions", permissions);
+ obj.pushKV("minfeefilter", ValueFromAmount(statestats.m_fee_filter_received));
UniValue sendPerMsgType(UniValue::VOBJ);
for (const auto& i : stats.mapSendBytesPerMsgType) {
@@ -352,7 +358,6 @@ static RPCHelpMan addconnection()
throw std::runtime_error("addconnection is for regression testing (-regtest mode) only.");
}
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR});
const std::string address = request.params[0].get_str();
const std::string conn_type_in{TrimString(request.params[1].get_str())};
ConnectionType conn_type{};
@@ -491,7 +496,7 @@ static RPCHelpMan getaddednodeinfo()
UniValue addresses(UniValue::VARR);
if (info.fConnected) {
UniValue address(UniValue::VOBJ);
- address.pushKV("address", info.resolvedAddress.ToString());
+ address.pushKV("address", info.resolvedAddress.ToStringAddrPort());
address.pushKV("connected", info.fInbound ? "inbound" : "outbound");
addresses.push_back(address);
}
@@ -566,7 +571,7 @@ static UniValue GetNetworksInfo()
obj.pushKV("name", GetNetworkName(network));
obj.pushKV("limited", !IsReachable(network));
obj.pushKV("reachable", IsReachable(network));
- obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string());
+ obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringAddrPort() : std::string());
obj.pushKV("proxy_randomize_credentials", proxy.randomize_credentials);
networks.push_back(obj);
}
@@ -659,7 +664,7 @@ static RPCHelpMan getnetworkinfo()
for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost)
{
UniValue rec(UniValue::VOBJ);
- rec.pushKV("address", item.first.ToString());
+ rec.pushKV("address", item.first.ToStringAddr());
rec.pushKV("port", item.second.nPort);
rec.pushKV("score", item.second.nScore);
localAddresses.push_back(rec);
@@ -697,9 +702,7 @@ static RPCHelpMan setban()
throw std::runtime_error(help.ToString());
}
NodeContext& node = EnsureAnyNodeContext(request.context);
- if (!node.banman) {
- throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
- }
+ BanMan& banman = EnsureBanman(node);
CSubNet subNet;
CNetAddr netAddr;
@@ -721,7 +724,7 @@ static RPCHelpMan setban()
if (strCommand == "add")
{
- if (isSubnet ? node.banman->IsBanned(subNet) : node.banman->IsBanned(netAddr)) {
+ if (isSubnet ? banman.IsBanned(subNet) : banman.IsBanned(netAddr)) {
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
}
@@ -729,17 +732,19 @@ static RPCHelpMan setban()
if (!request.params[2].isNull())
banTime = request.params[2].getInt<int64_t>();
- bool absolute = false;
- if (request.params[3].isTrue())
- absolute = true;
+ const bool absolute{request.params[3].isNull() ? false : request.params[3].get_bool()};
+
+ if (absolute && banTime < GetTime()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: Absolute timestamp is in the past");
+ }
if (isSubnet) {
- node.banman->Ban(subNet, banTime, absolute);
+ banman.Ban(subNet, banTime, absolute);
if (node.connman) {
node.connman->DisconnectNode(subNet);
}
} else {
- node.banman->Ban(netAddr, banTime, absolute);
+ banman.Ban(netAddr, banTime, absolute);
if (node.connman) {
node.connman->DisconnectNode(netAddr);
}
@@ -747,7 +752,7 @@ static RPCHelpMan setban()
}
else if(strCommand == "remove")
{
- if (!( isSubnet ? node.banman->Unban(subNet) : node.banman->Unban(netAddr) )) {
+ if (!( isSubnet ? banman.Unban(subNet) : banman.Unban(netAddr) )) {
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously manually banned.");
}
}
@@ -778,13 +783,10 @@ static RPCHelpMan listbanned()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureAnyNodeContext(request.context);
- if(!node.banman) {
- throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
- }
+ BanMan& banman = EnsureAnyBanman(request.context);
banmap_t banMap;
- node.banman->GetBanned(banMap);
+ banman.GetBanned(banMap);
const int64_t current_time{GetTime()};
UniValue bannedAddresses(UniValue::VARR);
@@ -818,12 +820,9 @@ static RPCHelpMan clearbanned()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- NodeContext& node = EnsureAnyNodeContext(request.context);
- if (!node.banman) {
- throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
- }
+ BanMan& banman = EnsureAnyBanman(request.context);
- node.banman->ClearBanned();
+ banman.ClearBanned();
return UniValue::VNULL;
},
@@ -902,7 +901,7 @@ static RPCHelpMan getnodeaddresses()
UniValue obj(UniValue::VOBJ);
obj.pushKV("time", int64_t{TicksSinceEpoch<std::chrono::seconds>(addr.nTime)});
obj.pushKV("services", (uint64_t)addr.nServices);
- obj.pushKV("address", addr.ToStringIP());
+ obj.pushKV("address", addr.ToStringAddr());
obj.pushKV("port", addr.GetPort());
obj.pushKV("network", GetNetworkName(addr.GetNetClass()));
ret.push_back(obj);
@@ -940,7 +939,7 @@ static RPCHelpMan addpeeraddress()
const std::string& addr_string{request.params[0].get_str()};
const auto port{request.params[1].getInt<uint16_t>()};
- const bool tried{request.params[2].isTrue()};
+ const bool tried{request.params[2].isNull() ? false : request.params[2].get_bool()};
UniValue obj(UniValue::VOBJ);
CNetAddr net_addr;
diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp
index 605ebc15a7..5918bc6e38 100644
--- a/src/rpc/node.cpp
+++ b/src/rpc/node.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,6 +12,7 @@
#include <interfaces/echo.h>
#include <interfaces/init.h>
#include <interfaces/ipc.h>
+#include <kernel/cs_main.h>
#include <node/context.h>
#include <rpc/server.h>
#include <rpc/server_util.h>
@@ -52,7 +53,6 @@ static RPCHelpMan setmocktime()
// ensure all call sites of GetTime() are accessing this safely.
LOCK(cs_main);
- RPCTypeCheck(request.params, {UniValue::VNUM});
const int64_t time{request.params[0].getInt<int64_t>()};
if (time < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime cannot be negative: %s.", time));
@@ -106,8 +106,6 @@ static RPCHelpMan mockscheduler()
throw std::runtime_error("mockscheduler is for regression testing (-regtest mode) only");
}
- // check params are valid values
- RPCTypeCheck(request.params, {UniValue::VNUM});
int64_t delta_seconds = request.params[0].getInt<int64_t>();
if (delta_seconds <= 0 || delta_seconds > 3600) {
throw std::runtime_error("delta_time must be between 1 and 3600 seconds (1 hr)");
@@ -242,11 +240,11 @@ static RPCHelpMan logging()
" - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n"
,
{
- {"include", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The categories to add to debug logging",
+ {"include", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The categories to add to debug logging",
{
{"include_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"},
}},
- {"exclude", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The categories to remove from debug logging",
+ {"exclude", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The categories to remove from debug logging",
{
{"exclude_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"},
}},
@@ -295,18 +293,18 @@ static RPCHelpMan echo(const std::string& name)
"\nIt will return an internal bug report when arg9='trigger_internal_bug' is passed.\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.",
- {
- {"arg0", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- {"arg1", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- {"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- {"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- {"arg4", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- {"arg5", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- {"arg6", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- {"arg7", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- {"arg8", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- {"arg9", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
- },
+ {
+ {"arg0", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ {"arg1", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ {"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ {"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ {"arg4", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ {"arg5", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ {"arg6", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ {"arg7", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ {"arg8", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ {"arg9", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
+ },
RPCResult{RPCResult::Type::ANY, "", "Returns whatever was passed in"},
RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
@@ -378,7 +376,7 @@ static RPCHelpMan getindexinfo()
return RPCHelpMan{"getindexinfo",
"\nReturns the status of one or all available indices currently running in the node.\n",
{
- {"index_name", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Filter results for an index with a specific name."},
+ {"index_name", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Filter results for an index with a specific name."},
},
RPCResult{
RPCResult::Type::OBJ_DYN, "", "", {
diff --git a/src/rpc/output_script.cpp b/src/rpc/output_script.cpp
index 744f809814..bb04f58424 100644
--- a/src/rpc/output_script.cpp
+++ b/src/rpc/output_script.cpp
@@ -195,8 +195,6 @@ static RPCHelpMan getdescriptorinfo()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR});
-
FlatSigningProvider provider;
std::string error;
auto desc = Parse(request.params[0].get_str(), provider, error);
@@ -222,16 +220,17 @@ static RPCHelpMan deriveaddresses()
return 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"
+ " 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"
+ " tr(<pubkey>,multi_a(<n>,<pubkey>,<pubkey>,...)) P2TR-multisig outputs for the given threshold and pubkeys\n"
"\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
"or more path elements separated by \"/\", 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, RPCArg::Optional::NO, "The descriptor."},
- {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED_NAMED_ARG, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
+ {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
},
RPCResult{
RPCResult::Type::ARR, "", "",
@@ -246,7 +245,6 @@ static RPCHelpMan deriveaddresses()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType()}); // Range argument is checked later
const std::string desc_str = request.params[0].get_str();
int64_t range_begin = 0;
@@ -273,7 +271,7 @@ static RPCHelpMan deriveaddresses()
UniValue addresses(UniValue::VARR);
- for (int i = range_begin; i <= range_end; ++i) {
+ for (int64_t i = range_begin; i <= range_end; ++i) {
FlatSigningProvider provider;
std::vector<CScript> scripts;
if (!desc->Expand(i, key_provider, scripts, provider)) {
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index f365de7d0c..21d49fda9d 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -32,6 +32,7 @@
#include <script/signingprovider.h>
#include <script/standard.h>
#include <uint256.h>
+#include <undo.h>
#include <util/bip32.h>
#include <util/check.h>
#include <util/strencodings.h>
@@ -50,15 +51,20 @@ using node::FindCoins;
using node::GetTransaction;
using node::NodeContext;
using node::PSBTAnalysis;
+using node::ReadBlockFromDisk;
+using node::UndoReadFromDisk;
-static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, Chainstate& active_chainstate)
+static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry,
+ Chainstate& active_chainstate, const CTxUndo* txundo = nullptr,
+ TxVerbosity verbosity = TxVerbosity::SHOW_DETAILS)
{
+ CHECK_NONFATAL(verbosity >= TxVerbosity::SHOW_DETAILS);
// Call into TxToUniv() in bitcoin-common to decode the transaction hex.
//
// Blockchain contextual information (confirmations and blocktime) is not
// available to code in bitcoin-common, so we query them here and push the
// data into the returned UniValue.
- TxToUniv(tx, /*block_hash=*/uint256(), entry, /*include_hex=*/true, RPCSerializationFlags());
+ TxToUniv(tx, /*block_hash=*/uint256(), entry, /*include_hex=*/true, RPCSerializationFlags(), txundo, verbosity);
if (!hashBlock.IsNull()) {
LOCK(cs_main);
@@ -77,6 +83,17 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue&
}
}
+static std::vector<RPCResult> ScriptPubKeyDoc() {
+ return
+ {
+ {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
+ {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
+ {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
+ };
+}
+
static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
{
return {
@@ -112,14 +129,7 @@ static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
{
{RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
{RPCResult::Type::NUM, "n", "index"},
- {RPCResult::Type::OBJ, "scriptPubKey", "",
- {
- {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
- {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
- {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
- {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
- {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
- }},
+ {RPCResult::Type::OBJ, "scriptPubKey", "", ScriptPubKeyDoc()},
}},
}},
};
@@ -155,7 +165,7 @@ static std::vector<RPCArg> CreateTxDoc()
},
},
},
- },
+ RPCArgOptions{.skip_type_check = true}},
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
{"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "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."},
@@ -166,26 +176,27 @@ static RPCHelpMan getrawtransaction()
{
return RPCHelpMan{
"getrawtransaction",
- "Return the raw transaction data.\n"
- "\nBy default, this call only returns a transaction if it is in the mempool. If -txindex is enabled\n"
+ "By default, this call only returns a transaction if it is in the mempool. If -txindex is enabled\n"
"and no blockhash argument is passed, it will return the transaction if it is in the mempool or any block.\n"
"If a blockhash argument is passed, it will return the transaction if\n"
- "the specified block is available and the transaction is in that block.\n"
- "\nHint: Use gettransaction for wallet transactions.\n"
+ "the specified block is available and the transaction is in that block.\n\n"
+ "Hint: Use gettransaction for wallet transactions.\n\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'.",
+ "If verbosity is 0 or omitted, returns the serialized transaction as a hex-encoded string.\n"
+ "If verbosity is 1, returns a JSON Object with information about the transaction.\n"
+ "If verbosity is 2, returns a JSON Object with information about the transaction, including fee and prevout information.",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
- {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If false, return a string, otherwise return a json object"},
- {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "The block in which to look for the transaction"},
+ {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{0}, "0 for hex-encoded data, 1 for a JSON object, and 2 for JSON object with fee and prevout",
+ RPCArgOptions{.skip_type_check = true}},
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The block in which to look for the transaction"},
},
{
- RPCResult{"if verbose is not set or set to false",
- RPCResult::Type::STR, "data", "The serialized, hex-encoded data for 'txid'"
+ RPCResult{"if verbosity is not set or set to 0",
+ RPCResult::Type::STR, "data", "The serialized transaction as a hex-encoded string for 'txid'"
},
- RPCResult{"if verbose is set to true",
+ RPCResult{"if verbosity is set to 1",
RPCResult::Type::OBJ, "", "",
Cat<std::vector<RPCResult>>(
{
@@ -198,20 +209,40 @@ static RPCHelpMan getrawtransaction()
},
DecodeTxDoc(/*txid_field_doc=*/"The transaction id (same as provided)")),
},
+ RPCResult{"for verbosity = 2",
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
+ {RPCResult::Type::NUM, "fee", /*optional=*/true, "transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
+ {RPCResult::Type::ARR, "vin", "",
+ {
+ {RPCResult::Type::OBJ, "", "utxo being spent",
+ {
+ {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
+ {RPCResult::Type::OBJ, "prevout", /*optional=*/true, "The previous output, omitted if block undo data is not available",
+ {
+ {RPCResult::Type::BOOL, "generated", "Coinbase or not"},
+ {RPCResult::Type::NUM, "height", "The height of the prevout"},
+ {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
+ {RPCResult::Type::OBJ, "scriptPubKey", "", ScriptPubKeyDoc()},
+ }},
+ }},
+ }},
+ }},
},
RPCExamples{
HelpExampleCli("getrawtransaction", "\"mytxid\"")
- + HelpExampleCli("getrawtransaction", "\"mytxid\" true")
- + HelpExampleRpc("getrawtransaction", "\"mytxid\", true")
- + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"")
- + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" 1")
+ + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" 0 \"myblockhash\"")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" 1 \"myblockhash\"")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" 2 \"myblockhash\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
ChainstateManager& chainman = EnsureChainman(node);
- bool in_active_chain = true;
uint256 hash = ParseHashV(request.params[0], "parameter 1");
const CBlockIndex* blockindex = nullptr;
@@ -220,10 +251,14 @@ static RPCHelpMan getrawtransaction()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved");
}
- // Accept either a bool (true) or a num (>=1) to indicate verbose output.
- bool fVerbose = false;
+ // Accept either a bool (true) or a num (>=0) to indicate verbosity.
+ int verbosity{0};
if (!request.params[1].isNull()) {
- fVerbose = request.params[1].isNum() ? (request.params[1].getInt<int>() != 0) : request.params[1].get_bool();
+ if (request.params[1].isBool()) {
+ verbosity = request.params[1].get_bool();
+ } else {
+ verbosity = request.params[1].getInt<int>();
+ }
}
if (!request.params[2].isNull()) {
@@ -234,7 +269,6 @@ static RPCHelpMan getrawtransaction()
if (!blockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
}
- in_active_chain = chainman.ActiveChain().Contains(blockindex);
}
bool f_txindex_ready = false;
@@ -262,13 +296,43 @@ static RPCHelpMan getrawtransaction()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errmsg + ". Use gettransaction for wallet transactions.");
}
- if (!fVerbose) {
+ if (verbosity <= 0) {
return EncodeHexTx(*tx, RPCSerializationFlags());
}
UniValue result(UniValue::VOBJ);
- if (blockindex) result.pushKV("in_active_chain", in_active_chain);
- TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
+ if (blockindex) {
+ LOCK(cs_main);
+ result.pushKV("in_active_chain", chainman.ActiveChain().Contains(blockindex));
+ }
+ // If request is verbosity >= 1 but no blockhash was given, then look up the blockindex
+ if (request.params[2].isNull()) {
+ LOCK(cs_main);
+ blockindex = chainman.m_blockman.LookupBlockIndex(hash_block);
+ }
+ if (verbosity == 1) {
+ TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
+ return result;
+ }
+
+ CBlockUndo blockUndo;
+ CBlock block;
+ const bool is_block_pruned{WITH_LOCK(cs_main, return chainman.m_blockman.IsBlockPruned(blockindex))};
+
+ if (tx->IsCoinBase() ||
+ !blockindex || is_block_pruned ||
+ !(UndoReadFromDisk(blockUndo, blockindex) && ReadBlockFromDisk(block, blockindex, Params().GetConsensus()))) {
+ TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
+ return result;
+ }
+
+ CTxUndo* undoTX {nullptr};
+ auto it = std::find_if(block.vtx.begin(), block.vtx.end(), [tx](CTransactionRef t){ return *t == *tx; });
+ if (it != block.vtx.end()) {
+ // -1 as blockundo does not have coinbase tx
+ undoTX = &blockUndo.vtxundo.at(it - block.vtx.begin() - 1);
+ }
+ TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate(), undoTX, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
return result;
},
};
@@ -294,17 +358,9 @@ static RPCHelpMan createrawtransaction()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {
- UniValue::VARR,
- UniValueType(), // ARR or OBJ, checked later
- UniValue::VNUM,
- UniValue::VBOOL
- }, true
- );
-
std::optional<bool> rbf;
if (!request.params[3].isNull()) {
- rbf = request.params[3].isTrue();
+ rbf = request.params[3].get_bool();
}
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
@@ -337,8 +393,6 @@ static RPCHelpMan decoderawtransaction()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
-
CMutableTransaction mtx;
bool try_witness = request.params[1].isNull() ? true : request.params[1].get_bool();
@@ -391,8 +445,6 @@ static RPCHelpMan decodescript()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR});
-
UniValue r(UniValue::VOBJ);
CScript script;
if (request.params[0].get_str().size() > 0){
@@ -470,15 +522,17 @@ static RPCHelpMan decodescript()
if (can_wrap_P2WSH) {
UniValue sr(UniValue::VOBJ);
CScript segwitScr;
+ FlatSigningProvider provider;
if (which_type == TxoutType::PUBKEY) {
segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0])));
} else if (which_type == TxoutType::PUBKEYHASH) {
segwitScr = GetScriptForDestination(WitnessV0KeyHash(uint160{solutions_data[0]}));
} else {
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
+ provider.scripts[CScriptID(script)] = script;
segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script));
}
- ScriptToUniv(segwitScr, /*out=*/sr, /*include_hex=*/true, /*include_address=*/true);
+ ScriptToUniv(segwitScr, /*out=*/sr, /*include_hex=*/true, /*include_address=*/true, /*provider=*/&provider);
sr.pushKV("p2sh-segwit", EncodeDestination(ScriptHash(segwitScr)));
r.pushKV("segwit", sr);
}
@@ -590,7 +644,7 @@ static RPCHelpMan signrawtransactionwithkey()
{"privatekey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "private key in base58-encoding"},
},
},
- {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The previous dependent transaction outputs",
+ {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The previous dependent transaction outputs",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
@@ -642,8 +696,6 @@ static RPCHelpMan signrawtransactionwithkey()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true);
-
CMutableTransaction mtx;
if (!DecodeHexTx(mtx, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
@@ -921,8 +973,6 @@ static RPCHelpMan decodepsbt()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR});
-
// Unserialize the transactions
PartiallySignedTransaction psbtx;
std::string error;
@@ -1241,13 +1291,9 @@ static RPCHelpMan decodepsbt()
}
// Taproot tree
- if (output.m_tap_tree.has_value()) {
+ if (!output.m_tap_tree.empty()) {
UniValue tree(UniValue::VARR);
- const auto& tuples = output.m_tap_tree->GetTreeTuples();
- for (const auto& tuple : tuples) {
- uint8_t depth = std::get<0>(tuple);
- uint8_t leaf_ver = std::get<1>(tuple);
- CScript script = std::get<2>(tuple);
+ for (const auto& [depth, leaf_ver, script] : output.m_tap_tree) {
UniValue elem(UniValue::VOBJ);
elem.pushKV("depth", (int)depth);
elem.pushKV("leaf_ver", (int)leaf_ver);
@@ -1339,8 +1385,6 @@ static RPCHelpMan combinepsbt()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VARR}, true);
-
// Unserialize the transactions
std::vector<PartiallySignedTransaction> psbtxs;
UniValue txs = request.params[0].get_array();
@@ -1394,8 +1438,6 @@ static RPCHelpMan finalizepsbt()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true);
-
// Unserialize the transactions
PartiallySignedTransaction psbtx;
std::string error;
@@ -1443,17 +1485,9 @@ static RPCHelpMan createpsbt()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {
- UniValue::VARR,
- UniValueType(), // ARR or OBJ, checked later
- UniValue::VNUM,
- UniValue::VBOOL,
- }, true
- );
-
std::optional<bool> rbf;
if (!request.params[3].isNull()) {
- rbf = request.params[3].isTrue();
+ rbf = request.params[3].get_bool();
}
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
@@ -1504,8 +1538,6 @@ static RPCHelpMan converttopsbt()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true);
-
// parse hex string from parameter
CMutableTransaction tx;
bool permitsigdata = request.params[1].isNull() ? false : request.params[1].get_bool();
@@ -1551,7 +1583,7 @@ static RPCHelpMan utxoupdatepsbt()
"\nUpdates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set or the mempool.\n",
{
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
- {"descriptors", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "An array of either strings or objects", {
+ {"descriptors", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of either strings or objects", {
{"", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with an output descriptor and extra information", {
{"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
@@ -1567,8 +1599,6 @@ static RPCHelpMan utxoupdatepsbt()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}, true);
-
// Unserialize the transactions
PartiallySignedTransaction psbtx;
std::string error;
@@ -1658,8 +1688,6 @@ static RPCHelpMan joinpsbts()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VARR}, true);
-
// Unserialize the transactions
std::vector<PartiallySignedTransaction> psbtxs;
UniValue txs = request.params[0].get_array();
@@ -1786,8 +1814,6 @@ static RPCHelpMan analyzepsbt()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {UniValue::VSTR});
-
// Unserialize the transaction
PartiallySignedTransaction psbtx;
std::string error;
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index b078ee8b29..3ba930f84f 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -21,12 +21,8 @@
#include <util/strencodings.h>
#include <util/translation.h>
-CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf)
+void AddInputs(CMutableTransaction& rawTx, const UniValue& inputs_in, std::optional<bool> rbf)
{
- if (outputs_in.isNull()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
- }
-
UniValue inputs;
if (inputs_in.isNull()) {
inputs = UniValue::VARR;
@@ -34,18 +30,6 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
inputs = inputs_in.get_array();
}
- const bool outputs_is_obj = outputs_in.isObject();
- UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
-
- CMutableTransaction rawTx;
-
- if (!locktime.isNull()) {
- int64_t nLockTime = locktime.getInt<int64_t>();
- if (nLockTime < 0 || nLockTime > LOCKTIME_MAX)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
- rawTx.nLockTime = nLockTime;
- }
-
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
const UniValue& o = input.get_obj();
@@ -84,6 +68,16 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
rawTx.vin.push_back(in);
}
+}
+
+void AddOutputs(CMutableTransaction& rawTx, const UniValue& outputs_in)
+{
+ if (outputs_in.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
+ }
+
+ const bool outputs_is_obj = outputs_in.isObject();
+ UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
if (!outputs_is_obj) {
// Translate array of key-value pairs into dict
@@ -132,6 +126,21 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
rawTx.vout.push_back(out);
}
}
+}
+
+CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf)
+{
+ CMutableTransaction rawTx;
+
+ if (!locktime.isNull()) {
+ int64_t nLockTime = locktime.getInt<int64_t>();
+ if (nLockTime < 0 || nLockTime > LOCKTIME_MAX)
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
+ rawTx.nLockTime = nLockTime;
+ }
+
+ AddInputs(rawTx, inputs_in, rbf);
+ AddOutputs(rawTx, outputs_in);
if (rbf.has_value() && rbf.value() && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h
index 9b5c9f08d4..a863432b7a 100644
--- a/src/rpc/rawtransaction_util.h
+++ b/src/rpc/rawtransaction_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -38,6 +38,13 @@ void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const
*/
void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins);
+
+/** Normalize univalue-represented inputs and add them to the transaction */
+void AddInputs(CMutableTransaction& rawTx, const UniValue& inputs_in, bool rbf);
+
+/** Normalize univalue-represented outputs and add them to the transaction */
+void AddOutputs(CMutableTransaction& rawTx, const UniValue& outputs_in);
+
/** Create a transaction from univalue parameters */
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf);
diff --git a/src/rpc/register.h b/src/rpc/register.h
index 301f410da3..c88f49ecf0 100644
--- a/src/rpc/register.h
+++ b/src/rpc/register.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index 8595fa78bb..b6ef1909c9 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -75,7 +75,7 @@ static fs::path GetAuthCookieFile(bool temp=false)
if (temp) {
arg += ".tmp";
}
- return AbsPathForConfigVal(arg);
+ return AbsPathForConfigVal(gArgs, arg);
}
bool GenerateAuthCookie(std::string *cookie_out)
@@ -86,7 +86,7 @@ bool GenerateAuthCookie(std::string *cookie_out)
std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd);
/** the umask determines what permissions are used to create this file -
- * these are set to 077 in init.cpp unless overridden with -sysperms.
+ * these are set to 0077 in util/system.cpp.
*/
std::ofstream file;
fs::path filepath_tmp = GetAuthCookieFile(true);
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 1d7bd2eb94..44d7e2676b 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -103,7 +103,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
{
UniValue unused_result;
if (setDone.insert(pcmd->unique_id).second)
- pcmd->actor(jreq, unused_result, true /* last_handler */);
+ pcmd->actor(jreq, unused_result, /*last_handler=*/true);
}
catch (const std::exception& e)
{
@@ -168,7 +168,7 @@ static RPCHelpMan stop()
// to the client (intended for testing)
"\nRequest a graceful shutdown of " PACKAGE_NAME ".",
{
- {"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "how long to wait in ms", RPCArgOptions{.hidden=true}},
+ {"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "how long to wait in ms", RPCArgOptions{.hidden=true}},
},
RPCResult{RPCResult::Type::STR, "", "A string with the content '" + RESULT + "'"},
RPCExamples{""},
@@ -399,10 +399,21 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
const std::vector<UniValue>& values = in.params.getValues();
std::unordered_map<std::string, const UniValue*> argsIn;
for (size_t i=0; i<keys.size(); ++i) {
- argsIn[keys[i]] = &values[i];
+ auto [_, inserted] = argsIn.emplace(keys[i], &values[i]);
+ if (!inserted) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + keys[i] + " specified multiple times");
+ }
}
- // Process expected parameters.
+ // Process expected parameters. If any parameters were left unspecified in
+ // the request before a parameter that was specified, null values need to be
+ // inserted at the unspecifed parameter positions, and the "hole" variable
+ // below tracks the number of null values that need to be inserted.
+ // The "initial_hole_size" variable stores the size of the initial hole,
+ // i.e. how many initial positional arguments were left unspecified. This is
+ // used after the for-loop to add initial positional arguments from the
+ // "args" parameter, if present.
int hole = 0;
+ int initial_hole_size = 0;
for (const std::string &argNamePattern: argNames) {
std::vector<std::string> vargNames = SplitString(argNamePattern, '|');
auto fr = argsIn.end();
@@ -424,6 +435,24 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
argsIn.erase(fr);
} else {
hole += 1;
+ if (out.params.empty()) initial_hole_size = hole;
+ }
+ }
+ // If leftover "args" param was found, use it as a source of positional
+ // arguments and add named arguments after. This is a convenience for
+ // clients that want to pass a combination of named and positional
+ // arguments as described in doc/JSON-RPC-interface.md#parameter-passing
+ auto positional_args{argsIn.extract("args")};
+ if (positional_args && positional_args.mapped()->isArray()) {
+ const bool has_named_arguments{initial_hole_size < (int)argNames.size()};
+ if (initial_hole_size < (int)positional_args.mapped()->size() && has_named_arguments) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + argNames[initial_hole_size] + " specified twice both as positional and named argument");
+ }
+ // Assign positional_args to out.params and append named_args after.
+ UniValue named_args{std::move(out.params)};
+ out.params = *positional_args.mapped();
+ for (size_t i{out.params.size()}; i < named_args.size(); ++i) {
+ out.params.push_back(named_args[i]);
}
}
// If there are still arguments in the argsIn map, this is an error.
diff --git a/src/rpc/server_util.cpp b/src/rpc/server_util.cpp
index 6a1b41f066..7a708ec813 100644
--- a/src/rpc/server_util.cpp
+++ b/src/rpc/server_util.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -39,6 +39,20 @@ CTxMemPool& EnsureAnyMemPool(const std::any& context)
return EnsureMemPool(EnsureAnyNodeContext(context));
}
+
+BanMan& EnsureBanman(const NodeContext& node)
+{
+ if (!node.banman) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
+ }
+ return *node.banman;
+}
+
+BanMan& EnsureAnyBanman(const std::any& context)
+{
+ return EnsureBanman(EnsureAnyNodeContext(context));
+}
+
ArgsManager& EnsureArgsman(const NodeContext& node)
{
if (!node.args) {
diff --git a/src/rpc/server_util.h b/src/rpc/server_util.h
index 2cc710a803..9af9572431 100644
--- a/src/rpc/server_util.h
+++ b/src/rpc/server_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,6 +13,7 @@ class CConnman;
class CTxMemPool;
class ChainstateManager;
class PeerManager;
+class BanMan;
namespace node {
struct NodeContext;
} // namespace node
@@ -20,6 +21,8 @@ struct NodeContext;
node::NodeContext& EnsureAnyNodeContext(const std::any& context);
CTxMemPool& EnsureMemPool(const node::NodeContext& node);
CTxMemPool& EnsureAnyMemPool(const std::any& context);
+BanMan& EnsureBanman(const node::NodeContext& node);
+BanMan& EnsureAnyBanman(const std::any& context);
ArgsManager& EnsureArgsman(const node::NodeContext& node);
ArgsManager& EnsureAnyArgsman(const std::any& context);
ChainstateManager& EnsureChainman(const node::NodeContext& node);
diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp
index cd8b49bfe1..24b5d04115 100644
--- a/src/rpc/txoutproof.cpp
+++ b/src/rpc/txoutproof.cpp
@@ -34,7 +34,7 @@ static RPCHelpMan gettxoutproof()
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"},
},
},
- {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "If specified, looks for txid in the block with this hash"},
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "If specified, looks for txid in the block with this hash"},
},
RPCResult{
RPCResult::Type::STR, "data", "A string that is a serialized, hex-encoded data for the proof."
@@ -84,13 +84,13 @@ static RPCHelpMan gettxoutproof()
g_txindex->BlockUntilSyncedToCurrentChain();
}
- LOCK(cs_main);
-
if (pblockindex == nullptr) {
const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, /*mempool=*/nullptr, *setTxids.begin(), chainman.GetConsensus(), hashBlock);
if (!tx || hashBlock.IsNull()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
}
+
+ LOCK(cs_main);
pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock);
if (!pblockindex) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
@@ -112,7 +112,7 @@ static RPCHelpMan gettxoutproof()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block");
}
- CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
+ DataStream ssMB{};
CMerkleBlock mb(block, setTxids);
ssMB << mb;
std::string strHex = HexStr(ssMB);
@@ -138,7 +138,7 @@ static RPCHelpMan verifytxoutproof()
RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
+ DataStream ssMB{ParseHexV(request.params[0], "proof")};
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 3e98e89791..a1020c3b2b 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -1,7 +1,8 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 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 <clientversion.h>
#include <consensus/amount.h>
#include <key_io.h>
#include <outputtype.h>
@@ -30,31 +31,6 @@ std::string GetAllOutputTypes()
return Join(ret, ", ");
}
-void RPCTypeCheck(const UniValue& params,
- const std::list<UniValueType>& typesExpected,
- bool fAllowNull)
-{
- unsigned int i = 0;
- for (const UniValueType& t : typesExpected) {
- if (params.size() <= i)
- break;
-
- const UniValue& v = params[i];
- if (!(fAllowNull && v.isNull())) {
- RPCTypeCheckArgument(v, t);
- }
- i++;
- }
-}
-
-void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
-{
- if (!typeExpected.typeAny && value.type() != typeExpected.type) {
- throw JSONRPCError(RPC_TYPE_ERROR,
- strprintf("JSON value of type %s is not of expected type %s", uvTypeName(value.type()), uvTypeName(typeExpected.type)));
- }
-}
-
void RPCTypeCheckObj(const UniValue& o,
const std::map<std::string, UniValueType>& typesExpected,
bool fAllowNull,
@@ -65,11 +41,8 @@ void RPCTypeCheckObj(const UniValue& o,
if (!fAllowNull && v.isNull())
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
- if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
- std::string err = strprintf("Expected type %s for %s, got %s",
- uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
- throw JSONRPCError(RPC_TYPE_ERROR, err);
- }
+ if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull())))
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("JSON value of type %s for field %s is not of expected type %s", uvTypeName(v.type()), t.first, uvTypeName(t.second.type)));
}
if (fStrict)
@@ -408,6 +381,7 @@ struct Sections {
const auto indent = std::string(current_indent, ' ');
const auto indent_next = std::string(current_indent + 2, ' ');
const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name
+ const bool is_top_level_arg{outer_type == OuterType::NONE}; // True on the first recursion
switch (arg.m_type) {
case RPCArg::Type::STR_HEX:
@@ -416,7 +390,7 @@ struct Sections {
case RPCArg::Type::AMOUNT:
case RPCArg::Type::RANGE:
case RPCArg::Type::BOOL: {
- if (outer_type == OuterType::NONE) return; // Nothing more to do for non-recursive types on first recursion
+ if (is_top_level_arg) return; // Nothing more to do for non-recursive types on first recursion
auto left = indent;
if (arg.m_opts.type_str.size() != 0 && push_name) {
left += "\"" + arg.GetName() + "\": " + arg.m_opts.type_str.at(0);
@@ -424,12 +398,12 @@ struct Sections {
left += push_name ? arg.ToStringObj(/*oneline=*/false) : arg.ToString(/*oneline=*/false);
}
left += ",";
- PushSection({left, arg.ToDescriptionString()});
+ PushSection({left, arg.ToDescriptionString(/*is_named_arg=*/push_name)});
break;
}
case RPCArg::Type::OBJ:
case RPCArg::Type::OBJ_USER_KEYS: {
- const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
+ const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name);
PushSection({indent + (push_name ? "\"" + arg.GetName() + "\": " : "") + "{", right});
for (const auto& arg_inner : arg.m_inner) {
Push(arg_inner, current_indent + 2, OuterType::OBJ);
@@ -437,20 +411,20 @@ struct Sections {
if (arg.m_type != RPCArg::Type::OBJ) {
PushSection({indent_next + "...", ""});
}
- PushSection({indent + "}" + (outer_type != OuterType::NONE ? "," : ""), ""});
+ PushSection({indent + "}" + (is_top_level_arg ? "" : ","), ""});
break;
}
case RPCArg::Type::ARR: {
auto left = indent;
left += push_name ? "\"" + arg.GetName() + "\": " : "";
left += "[";
- const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
+ const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name);
PushSection({left, right});
for (const auto& arg_inner : arg.m_inner) {
Push(arg_inner, current_indent + 2, OuterType::ARR);
}
PushSection({indent_next + "...", ""});
- PushSection({indent + "]" + (outer_type != OuterType::NONE ? "," : ""), ""});
+ PushSection({indent + "]" + (is_top_level_arg ? "" : ","), ""});
break;
}
} // no default case, so the compiler can warn about missing cases
@@ -582,9 +556,39 @@ UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request) const
if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs(request.params.size())) {
throw std::runtime_error(ToString());
}
- const UniValue ret = m_fun(*this, request);
+ UniValue arg_mismatch{UniValue::VOBJ};
+ for (size_t i{0}; i < m_args.size(); ++i) {
+ const auto& arg{m_args.at(i)};
+ UniValue match{arg.MatchesType(request.params[i])};
+ if (!match.isTrue()) {
+ arg_mismatch.pushKV(strprintf("Position %s (%s)", i + 1, arg.m_names), std::move(match));
+ }
+ }
+ if (!arg_mismatch.empty()) {
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Wrong type passed:\n%s", arg_mismatch.write(4)));
+ }
+ UniValue ret = m_fun(*this, request);
if (gArgs.GetBoolArg("-rpcdoccheck", DEFAULT_RPC_DOC_CHECK)) {
- CHECK_NONFATAL(std::any_of(m_results.m_results.begin(), m_results.m_results.end(), [&ret](const RPCResult& res) { return res.MatchesType(ret); }));
+ UniValue mismatch{UniValue::VARR};
+ for (const auto& res : m_results.m_results) {
+ UniValue match{res.MatchesType(ret)};
+ if (match.isTrue()) {
+ mismatch.setNull();
+ break;
+ }
+ mismatch.push_back(match);
+ }
+ if (!mismatch.isNull()) {
+ std::string explain{
+ mismatch.empty() ? "no possible results defined" :
+ mismatch.size() == 1 ? mismatch[0].write(4) :
+ mismatch.write(4)};
+ throw std::runtime_error{
+ strprintf("Internal bug detected: RPC call \"%s\" returned incorrect type:\n%s\n%s %s\nPlease report this issue here: %s\n",
+ m_name, explain,
+ PACKAGE_NAME, FormatFullVersion(),
+ PACKAGE_BUGREPORT)};
+ }
}
return ret;
}
@@ -644,7 +648,7 @@ std::string RPCHelpMan::ToString() const
if (i == 0) ret += "\nArguments:\n";
// Push named argument name and description
- sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString());
+ sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString(/*is_named_arg=*/true));
sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size());
// Recursively push nested args
@@ -680,6 +684,52 @@ UniValue RPCHelpMan::GetArgMap() const
return arr;
}
+static std::optional<UniValue::VType> ExpectedType(RPCArg::Type type)
+{
+ using Type = RPCArg::Type;
+ switch (type) {
+ case Type::STR_HEX:
+ case Type::STR: {
+ return UniValue::VSTR;
+ }
+ case Type::NUM: {
+ return UniValue::VNUM;
+ }
+ case Type::AMOUNT: {
+ // VNUM or VSTR, checked inside AmountFromValue()
+ return std::nullopt;
+ }
+ case Type::RANGE: {
+ // VNUM or VARR, checked inside ParseRange()
+ return std::nullopt;
+ }
+ case Type::BOOL: {
+ return UniValue::VBOOL;
+ }
+ case Type::OBJ:
+ case Type::OBJ_USER_KEYS: {
+ return UniValue::VOBJ;
+ }
+ case Type::ARR: {
+ return UniValue::VARR;
+ }
+ } // no default case, so the compiler can warn about missing cases
+ NONFATAL_UNREACHABLE();
+}
+
+UniValue RPCArg::MatchesType(const UniValue& request) const
+{
+ if (m_opts.skip_type_check) return true;
+ if (IsOptional() && request.isNull()) return true;
+ const auto exp_type{ExpectedType(m_type)};
+ if (!exp_type) return true; // nothing to check
+
+ if (*exp_type != request.getType()) {
+ return strprintf("JSON value of type %s is not of expected type %s", uvTypeName(request.getType()), uvTypeName(*exp_type));
+ }
+ return true;
+}
+
std::string RPCArg::GetFirstName() const
{
return m_names.substr(0, m_names.find("|"));
@@ -700,7 +750,7 @@ bool RPCArg::IsOptional() const
}
}
-std::string RPCArg::ToDescriptionString() const
+std::string RPCArg::ToDescriptionString(bool is_named_arg) const
{
std::string ret;
ret += "(";
@@ -747,13 +797,10 @@ std::string RPCArg::ToDescriptionString() const
} else {
switch (std::get<RPCArg::Optional>(m_fallback)) {
case RPCArg::Optional::OMITTED: {
+ if (is_named_arg) ret += ", optional"; // Default value is "null" in dicts. Otherwise,
// nothing to do. Element is treated as if not present and has no default value
break;
}
- case RPCArg::Optional::OMITTED_NAMED_ARG: {
- ret += ", optional"; // Default value is "null"
- break;
- }
case RPCArg::Optional::NO: {
ret += ", required";
break;
@@ -863,53 +910,77 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
NONFATAL_UNREACHABLE();
}
-bool RPCResult::MatchesType(const UniValue& result) const
+static std::optional<UniValue::VType> ExpectedType(RPCResult::Type type)
{
- if (m_skip_type_check) {
- return true;
- }
- switch (m_type) {
+ using Type = RPCResult::Type;
+ switch (type) {
case Type::ELISION:
case Type::ANY: {
- return true;
+ return std::nullopt;
}
case Type::NONE: {
- return UniValue::VNULL == result.getType();
+ return UniValue::VNULL;
}
case Type::STR:
case Type::STR_HEX: {
- return UniValue::VSTR == result.getType();
+ return UniValue::VSTR;
}
case Type::NUM:
case Type::STR_AMOUNT:
case Type::NUM_TIME: {
- return UniValue::VNUM == result.getType();
+ return UniValue::VNUM;
}
case Type::BOOL: {
- return UniValue::VBOOL == result.getType();
+ return UniValue::VBOOL;
}
case Type::ARR_FIXED:
case Type::ARR: {
- if (UniValue::VARR != result.getType()) return false;
+ return UniValue::VARR;
+ }
+ case Type::OBJ_DYN:
+ case Type::OBJ: {
+ return UniValue::VOBJ;
+ }
+ } // no default case, so the compiler can warn about missing cases
+ NONFATAL_UNREACHABLE();
+}
+
+UniValue RPCResult::MatchesType(const UniValue& result) const
+{
+ if (m_skip_type_check) {
+ return true;
+ }
+
+ const auto exp_type = ExpectedType(m_type);
+ if (!exp_type) return true; // can be any type, so nothing to check
+
+ if (*exp_type != result.getType()) {
+ return strprintf("returned type is %s, but declared as %s in doc", uvTypeName(result.getType()), uvTypeName(*exp_type));
+ }
+
+ if (UniValue::VARR == result.getType()) {
+ UniValue errors(UniValue::VOBJ);
for (size_t i{0}; i < result.get_array().size(); ++i) {
// If there are more results than documented, re-use the last doc_inner.
const RPCResult& doc_inner{m_inner.at(std::min(m_inner.size() - 1, i))};
- if (!doc_inner.MatchesType(result.get_array()[i])) return false;
+ UniValue match{doc_inner.MatchesType(result.get_array()[i])};
+ if (!match.isTrue()) errors.pushKV(strprintf("%d", i), match);
}
- return true; // empty result array is valid
+ if (errors.empty()) return true; // empty result array is valid
+ return errors;
}
- case Type::OBJ_DYN:
- case Type::OBJ: {
- if (UniValue::VOBJ != result.getType()) return false;
+
+ if (UniValue::VOBJ == result.getType()) {
if (!m_inner.empty() && m_inner.at(0).m_type == Type::ELISION) return true;
+ UniValue errors(UniValue::VOBJ);
if (m_type == Type::OBJ_DYN) {
const RPCResult& doc_inner{m_inner.at(0)}; // Assume all types are the same, randomly pick the first
for (size_t i{0}; i < result.get_obj().size(); ++i) {
- if (!doc_inner.MatchesType(result.get_obj()[i])) {
- return false;
- }
+ UniValue match{doc_inner.MatchesType(result.get_obj()[i])};
+ if (!match.isTrue()) errors.pushKV(result.getKeys()[i], match);
}
- return true; // empty result obj is valid
+ if (errors.empty()) return true; // empty result obj is valid
+ return errors;
}
std::set<std::string> doc_keys;
for (const auto& doc_entry : m_inner) {
@@ -919,7 +990,7 @@ bool RPCResult::MatchesType(const UniValue& result) const
result.getObjMap(result_obj);
for (const auto& result_entry : result_obj) {
if (doc_keys.find(result_entry.first) == doc_keys.end()) {
- return false; // missing documentation
+ errors.pushKV(result_entry.first, "key returned that was not in doc");
}
}
@@ -927,18 +998,18 @@ bool RPCResult::MatchesType(const UniValue& result) const
const auto result_it{result_obj.find(doc_entry.m_key_name)};
if (result_it == result_obj.end()) {
if (!doc_entry.m_optional) {
- return false; // result is missing a required key
+ errors.pushKV(doc_entry.m_key_name, "key missing, despite not being optional in doc");
}
continue;
}
- if (!doc_entry.MatchesType(result_it->second)) {
- return false; // wrong type
- }
+ UniValue match{doc_entry.MatchesType(result_it->second)};
+ if (!match.isTrue()) errors.pushKV(doc_entry.m_key_name, match);
}
- return true;
+ if (errors.empty()) return true;
+ return errors;
}
- } // no default case, so the compiler can warn about missing cases
- NONFATAL_UNREACHABLE();
+
+ return true;
}
void RPCResult::CheckInnerDoc() const
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 9aa5df00b1..e3783c8f76 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -62,18 +62,6 @@ struct UniValueType {
UniValue::VType type;
};
-/**
- * Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
- * the right number of arguments are passed, just that any passed are the correct type.
- */
-void RPCTypeCheck(const UniValue& params,
- const std::list<UniValueType>& typesExpected, bool fAllowNull=false);
-
-/**
- * Type-check one argument; throws JSONRPCError if wrong type given.
- */
-void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected);
-
/*
Check for expected keys/value types in an Object.
*/
@@ -138,6 +126,7 @@ enum class OuterType {
};
struct RPCArgOptions {
+ bool skip_type_check{false};
std::string oneline_description{}; //!< Should be empty unless it is supposed to override the auto-generated summary line
std::vector<std::string> type_str{}; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_opts.type_str.at(0) will override the type of the value in a key-value pair, m_opts.type_str.at(1) will override the type in the argument description.
bool hidden{false}; //!< For testing only
@@ -160,21 +149,20 @@ struct RPCArg {
/** Required arg */
NO,
/**
- * Optional arg that is a named argument and has a default value of
- * `null`. When possible, the default value should be specified.
- */
- OMITTED_NAMED_ARG,
- /**
- * Optional argument with default value omitted because they are
- * implicitly clear. That is, elements in an array or object may not
- * exist by default.
+ * Optional argument for which the default value is omitted from
+ * help text for one of two reasons:
+ * - It's a named argument and has a default value of `null`.
+ * - Its default value is implicitly clear. That is, elements in an
+ * array may not exist by default.
* When possible, the default value should be specified.
*/
OMITTED,
};
+ /** Hint for default value */
using DefaultHint = std::string;
+ /** Default constant value */
using Default = UniValue;
- using Fallback = std::variant<Optional, /* hint for default value */ DefaultHint, /* default constant value */ Default>;
+ using Fallback = std::variant<Optional, DefaultHint, Default>;
const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments)
const Type m_type;
@@ -184,10 +172,10 @@ struct RPCArg {
const RPCArgOptions m_opts;
RPCArg(
- const std::string name,
- const Type type,
- const Fallback fallback,
- const std::string description,
+ std::string name,
+ Type type,
+ Fallback fallback,
+ std::string description,
RPCArgOptions opts = {})
: m_names{std::move(name)},
m_type{std::move(type)},
@@ -199,11 +187,11 @@ struct RPCArg {
}
RPCArg(
- const std::string name,
- const Type type,
- const Fallback fallback,
- const std::string description,
- const std::vector<RPCArg> inner,
+ std::string name,
+ Type type,
+ Fallback fallback,
+ std::string description,
+ std::vector<RPCArg> inner,
RPCArgOptions opts = {})
: m_names{std::move(name)},
m_type{std::move(type)},
@@ -217,6 +205,12 @@ struct RPCArg {
bool IsOptional() const;
+ /**
+ * Check whether the request JSON type matches.
+ * Returns true if type matches, or object describing error(s) if not.
+ */
+ UniValue MatchesType(const UniValue& request) const;
+
/** Return the first of all aliases */
std::string GetFirstName() const;
@@ -237,7 +231,7 @@ struct RPCArg {
* Return the description string, including the argument type and whether
* the argument is required.
*/
- std::string ToDescriptionString() const;
+ std::string ToDescriptionString(bool is_named_arg) const;
};
struct RPCResult {
@@ -266,12 +260,12 @@ struct RPCResult {
const std::string m_cond;
RPCResult(
- const std::string cond,
- const Type type,
- const std::string m_key_name,
- const bool optional,
- const std::string description,
- const std::vector<RPCResult> inner = {})
+ std::string cond,
+ Type type,
+ std::string m_key_name,
+ bool optional,
+ std::string description,
+ std::vector<RPCResult> inner = {})
: m_type{std::move(type)},
m_key_name{std::move(m_key_name)},
m_inner{std::move(inner)},
@@ -285,19 +279,19 @@ struct RPCResult {
}
RPCResult(
- const std::string cond,
- const Type type,
- const std::string m_key_name,
- const std::string description,
- const std::vector<RPCResult> inner = {})
- : RPCResult{cond, type, m_key_name, false, description, inner} {}
+ std::string cond,
+ Type type,
+ std::string m_key_name,
+ std::string description,
+ std::vector<RPCResult> inner = {})
+ : RPCResult{std::move(cond), type, std::move(m_key_name), /*optional=*/false, std::move(description), std::move(inner)} {}
RPCResult(
- const Type type,
- const std::string m_key_name,
- const bool optional,
- const std::string description,
- const std::vector<RPCResult> inner = {},
+ Type type,
+ std::string m_key_name,
+ bool optional,
+ std::string description,
+ std::vector<RPCResult> inner = {},
bool skip_type_check = false)
: m_type{std::move(type)},
m_key_name{std::move(m_key_name)},
@@ -311,12 +305,12 @@ struct RPCResult {
}
RPCResult(
- const Type type,
- const std::string m_key_name,
- const std::string description,
- const std::vector<RPCResult> inner = {},
+ Type type,
+ std::string m_key_name,
+ std::string description,
+ std::vector<RPCResult> inner = {},
bool skip_type_check = false)
- : RPCResult{type, m_key_name, false, description, inner, skip_type_check} {}
+ : RPCResult{type, std::move(m_key_name), /*optional=*/false, std::move(description), std::move(inner), skip_type_check} {}
/** Append the sections of the result. */
void ToSections(Sections& sections, OuterType outer_type = OuterType::NONE, const int current_indent = 0) const;
@@ -324,8 +318,10 @@ struct RPCResult {
std::string ToStringObj() const;
/** Return the description string, including the result type. */
std::string ToDescriptionString() const;
- /** Check whether the result JSON type matches. */
- bool MatchesType(const UniValue& result) const;
+ /** Check whether the result JSON type matches.
+ * Returns true if type matches, or object describing error(s) if not.
+ */
+ UniValue MatchesType(const UniValue& result) const;
private:
void CheckInnerDoc() const;
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 3df1d48b3c..1c9aedc10b 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/scheduler.h b/src/scheduler.h
index 749e5442b0..9212582b97 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index f7f9dfc262..4fab481b39 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -62,12 +62,6 @@ inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror)
return 0;
}
-struct ECCryptoClosure
-{
- ECCVerifyHandle handle;
-};
-
-ECCryptoClosure instance_of_eccryptoclosure;
} // namespace
/** Check that all specified flags are part of the libconsensus interface. */
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index 8fea42e4b9..f2f2ff8686 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 864eb8864f..857fee1818 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -4,11 +4,13 @@
#include <script/descriptor.h>
+#include <hash.h>
#include <key_io.h>
#include <pubkey.h>
#include <script/miniscript.h>
#include <script/script.h>
#include <script/standard.h>
+#include <uint256.h>
#include <span.h>
#include <util/bip32.h>
@@ -1012,7 +1014,7 @@ public:
return false;
}
- bool IsSolvable() const override { return false; } // For now, mark these descriptors as non-solvable (as we don't have signing logic for them).
+ bool IsSolvable() const override { return true; }
bool IsSingleType() const final { return true; }
};
@@ -1618,8 +1620,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
}
}
if (txntype == TxoutType::WITNESS_V0_SCRIPTHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH)) {
- CScriptID scriptid;
- CRIPEMD160().Write(data[0].data(), data[0].size()).Finalize(scriptid.begin());
+ CScriptID scriptid{RIPEMD160(data[0])};
CScript subscript;
if (provider.GetCScript(scriptid, subscript)) {
auto sub = InferScript(subscript, ParseScriptContext::P2WSH, provider);
@@ -1643,7 +1644,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
for (const auto& [depth, script, leaf_ver] : *tree) {
std::unique_ptr<DescriptorImpl> subdesc;
if (leaf_ver == TAPROOT_LEAF_TAPSCRIPT) {
- subdesc = InferScript(script, ParseScriptContext::P2TR, provider);
+ subdesc = InferScript(CScript(script.begin(), script.end()), ParseScriptContext::P2TR, provider);
}
if (!subdesc) {
ok = false;
@@ -1832,17 +1833,17 @@ DescriptorCache DescriptorCache::MergeAndDiff(const DescriptorCache& other)
return diff;
}
-const ExtPubKeyMap DescriptorCache::GetCachedParentExtPubKeys() const
+ExtPubKeyMap DescriptorCache::GetCachedParentExtPubKeys() const
{
return m_parent_xpubs;
}
-const std::unordered_map<uint32_t, ExtPubKeyMap> DescriptorCache::GetCachedDerivedExtPubKeys() const
+std::unordered_map<uint32_t, ExtPubKeyMap> DescriptorCache::GetCachedDerivedExtPubKeys() const
{
return m_derived_xpubs;
}
-const ExtPubKeyMap DescriptorCache::GetCachedLastHardenedExtPubKeys() const
+ExtPubKeyMap DescriptorCache::GetCachedLastHardenedExtPubKeys() const
{
return m_last_hardened_xpubs;
}
diff --git a/src/script/descriptor.h b/src/script/descriptor.h
index 16ee2f6d97..39b1a37f9a 100644
--- a/src/script/descriptor.h
+++ b/src/script/descriptor.h
@@ -35,7 +35,7 @@ public:
/** Retrieve a cached parent xpub
*
* @param[in] key_exp_pos Position of the key expression within the descriptor
- * @param[in] xpub The CExtPubKey to get from cache
+ * @param[out] xpub The CExtPubKey to get from cache
*/
bool GetCachedParentExtPubKey(uint32_t key_exp_pos, CExtPubKey& xpub) const;
/** Cache an xpub derived at an index
@@ -49,7 +49,7 @@ public:
*
* @param[in] key_exp_pos Position of the key expression within the descriptor
* @param[in] der_index Derivation index of the xpub
- * @param[in] xpub The CExtPubKey to get from cache
+ * @param[out] xpub The CExtPubKey to get from cache
*/
bool GetCachedDerivedExtPubKey(uint32_t key_exp_pos, uint32_t der_index, CExtPubKey& xpub) const;
/** Cache a last hardened xpub
@@ -61,16 +61,16 @@ public:
/** Retrieve a cached last hardened xpub
*
* @param[in] key_exp_pos Position of the key expression within the descriptor
- * @param[in] xpub The CExtPubKey to get from cache
+ * @param[out] xpub The CExtPubKey to get from cache
*/
bool GetCachedLastHardenedExtPubKey(uint32_t key_exp_pos, CExtPubKey& xpub) const;
/** Retrieve all cached parent xpubs */
- const ExtPubKeyMap GetCachedParentExtPubKeys() const;
+ ExtPubKeyMap GetCachedParentExtPubKeys() const;
/** Retrieve all cached derived xpubs */
- const std::unordered_map<uint32_t, ExtPubKeyMap> GetCachedDerivedExtPubKeys() const;
+ std::unordered_map<uint32_t, ExtPubKeyMap> GetCachedDerivedExtPubKeys() const;
/** Retrieve all cached last hardened xpubs */
- const ExtPubKeyMap GetCachedLastHardenedExtPubKeys() const;
+ ExtPubKeyMap GetCachedLastHardenedExtPubKeys() const;
/** Combine another DescriptorCache into this one.
* Returns a cache containing the items from the other cache unknown to current cache
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 38bb11aad4..5f4a1aceb2 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -1303,7 +1303,7 @@ public:
// Serialize the nSequence
if (nInput != nIn && (fHashSingle || fHashNone))
// let the others update at will
- ::Serialize(s, (int)0);
+ ::Serialize(s, int{0});
else
::Serialize(s, txTo.vin[nInput].nSequence);
}
@@ -1439,7 +1439,7 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
hashOutputs = SHA256Uint256(m_outputs_single_hash);
m_bip143_segwit_ready = true;
}
- if (uses_bip341_taproot) {
+ if (uses_bip341_taproot && m_spent_outputs_ready) {
m_spent_amounts_single_hash = GetSpentAmountsSHA256(m_spent_outputs);
m_spent_scripts_single_hash = GetSpentScriptsSHA256(m_spent_outputs);
m_bip341_taproot_ready = true;
@@ -1825,9 +1825,20 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
return true;
}
-uint256 ComputeTapleafHash(uint8_t leaf_version, const CScript& script)
+uint256 ComputeTapleafHash(uint8_t leaf_version, Span<const unsigned char> script)
{
- return (HashWriter{HASHER_TAPLEAF} << leaf_version << script).GetSHA256();
+ return (HashWriter{HASHER_TAPLEAF} << leaf_version << CompactSizeWriter(script.size()) << script).GetSHA256();
+}
+
+uint256 ComputeTapbranchHash(Span<const unsigned char> a, Span<const unsigned char> b)
+{
+ HashWriter ss_branch{HASHER_TAPBRANCH};
+ if (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())) {
+ ss_branch << a << b;
+ } else {
+ ss_branch << b << a;
+ }
+ return ss_branch.GetSHA256();
}
uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint256& tapleaf_hash)
@@ -1839,14 +1850,8 @@ uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint25
const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
uint256 k = tapleaf_hash;
for (int i = 0; i < path_len; ++i) {
- HashWriter ss_branch{HASHER_TAPBRANCH};
Span node{Span{control}.subspan(TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE)};
- if (std::lexicographical_compare(k.begin(), k.end(), node.begin(), node.end())) {
- ss_branch << k << node;
- } else {
- ss_branch << node << k;
- }
- k = ss_branch.GetSHA256();
+ k = ComputeTapbranchHash(k, node);
}
return k;
}
@@ -1917,18 +1922,18 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
} else {
// Script path spending (stack size is >1 after removing optional annex)
const valtype& control = SpanPopBack(stack);
- const valtype& script_bytes = SpanPopBack(stack);
- exec_script = CScript(script_bytes.begin(), script_bytes.end());
+ const valtype& script = SpanPopBack(stack);
if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > TAPROOT_CONTROL_MAX_SIZE || ((control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) {
return set_error(serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE);
}
- execdata.m_tapleaf_hash = ComputeTapleafHash(control[0] & TAPROOT_LEAF_MASK, exec_script);
+ execdata.m_tapleaf_hash = ComputeTapleafHash(control[0] & TAPROOT_LEAF_MASK, script);
if (!VerifyTaprootCommitment(control, program, execdata.m_tapleaf_hash)) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
}
execdata.m_tapleaf_hash_init = true;
if ((control[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
// Tapscript (leaf version 0xc0)
+ exec_script = CScript(script.begin(), script.end());
execdata.m_validation_weight_left = ::GetSerializeSize(witness.stack, PROTOCOL_VERSION) + VALIDATION_WEIGHT_OFFSET;
execdata.m_validation_weight_left_init = true;
return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::TAPSCRIPT, checker, execdata, serror);
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index ba910cc945..ac1013302d 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -333,7 +333,10 @@ public:
};
/** Compute the BIP341 tapleaf hash from leaf version & script. */
-uint256 ComputeTapleafHash(uint8_t leaf_version, const CScript& script);
+uint256 ComputeTapleafHash(uint8_t leaf_version, Span<const unsigned char> script);
+/** Compute the BIP341 tapbranch hash from two branches.
+ * Spans must be 32 bytes each. */
+uint256 ComputeTapbranchHash(Span<const unsigned char> a, Span<const unsigned char> b);
/** Compute the BIP341 taproot script tree Merkle root from control block and leaf hash.
* Requires control block to have valid length (33 + k*32, with k in {0,1,..,128}). */
uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint256& tapleaf_hash);
diff --git a/src/script/miniscript.cpp b/src/script/miniscript.cpp
index cb4d4cb783..3937638cf8 100644
--- a/src/script/miniscript.cpp
+++ b/src/script/miniscript.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -172,8 +172,8 @@ Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector<Ty
(y & "B"_mst).If(x << "Bdu"_mst) | // B=B_y*B_x*d_x*u_x
(x & "o"_mst).If(y << "z"_mst) | // o=o_x*z_y
(x & y & "m"_mst).If(x << "e"_mst && (x | y) << "s"_mst) | // m=m_x*m_y*e_x*(s_x+s_y)
- (x & y & "zes"_mst) | // z=z_x*z_y, e=e_x*e_y, s=s_x*s_y
- (y & "ufd"_mst) | // u=u_y, f=f_y, d=d_y
+ (x & y & "zs"_mst) | // z=z_x*z_y, s=s_x*s_y
+ (y & "ufde"_mst) | // u=u_y, f=f_y, d=d_y, e=e_y
"x"_mst | // x
((x | y) & "ghij"_mst) | // g=g_x+g_y, h=h_x+h_y, i=i_x+i_y, j=j_x+j_y
(x & y & "k"_mst); // k=k_x*k_y
@@ -201,7 +201,7 @@ Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector<Ty
(y & z & "u"_mst) | // u=u_y*u_z
(z & "f"_mst).If((x << "s"_mst) || (y << "f"_mst)) | // f=(s_x+f_y)*f_z
(z & "d"_mst) | // d=d_z
- (x & z & "e"_mst).If(x << "s"_mst || y << "f"_mst) | // e=e_x*e_z*(s_x+f_y)
+ (z & "e"_mst).If(x << "s"_mst || y << "f"_mst) | // e=e_z*(s_x+f_y)
(x & y & z & "m"_mst).If(x << "e"_mst && (x | y | z) << "s"_mst) | // m=m_x*m_y*m_z*e_x*(s_x+s_y+s_z)
(z & (x | y) & "s"_mst) | // s=s_z*(s_x+s_y)
"x"_mst | // x
@@ -279,6 +279,76 @@ size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_
assert(false);
}
+InputStack& InputStack::SetAvailable(Availability avail) {
+ available = avail;
+ if (avail == Availability::NO) {
+ stack.clear();
+ size = std::numeric_limits<size_t>::max();
+ has_sig = false;
+ malleable = false;
+ non_canon = false;
+ }
+ return *this;
+}
+
+InputStack& InputStack::SetWithSig() {
+ has_sig = true;
+ return *this;
+}
+
+InputStack& InputStack::SetNonCanon() {
+ non_canon = true;
+ return *this;
+}
+
+InputStack& InputStack::SetMalleable(bool x) {
+ malleable = x;
+ return *this;
+}
+
+InputStack operator+(InputStack a, InputStack b) {
+ a.stack = Cat(std::move(a.stack), std::move(b.stack));
+ if (a.available != Availability::NO && b.available != Availability::NO) a.size += b.size;
+ a.has_sig |= b.has_sig;
+ a.malleable |= b.malleable;
+ a.non_canon |= b.non_canon;
+ if (a.available == Availability::NO || b.available == Availability::NO) {
+ a.SetAvailable(Availability::NO);
+ } else if (a.available == Availability::MAYBE || b.available == Availability::MAYBE) {
+ a.SetAvailable(Availability::MAYBE);
+ }
+ return a;
+}
+
+InputStack operator|(InputStack a, InputStack b) {
+ // If only one is invalid, pick the other one. If both are invalid, pick an arbitrary one.
+ if (a.available == Availability::NO) return b;
+ if (b.available == Availability::NO) return a;
+ // If only one of the solutions has a signature, we must pick the other one.
+ if (!a.has_sig && b.has_sig) return a;
+ if (!b.has_sig && a.has_sig) return b;
+ if (!a.has_sig && !b.has_sig) {
+ // If neither solution requires a signature, the result is inevitably malleable.
+ a.malleable = true;
+ b.malleable = true;
+ } else {
+ // If both options require a signature, prefer the non-malleable one.
+ if (b.malleable && !a.malleable) return a;
+ if (a.malleable && !b.malleable) return b;
+ }
+ // Between two malleable or two non-malleable solutions, pick the smaller one between
+ // YESes, and the bigger ones between MAYBEs. Prefer YES over MAYBE.
+ if (a.available == Availability::YES && b.available == Availability::YES) {
+ return std::move(a.size <= b.size ? a : b);
+ } else if (a.available == Availability::MAYBE && b.available == Availability::MAYBE) {
+ return std::move(a.size >= b.size ? a : b);
+ } else if (a.available == Availability::YES) {
+ return a;
+ } else {
+ return b;
+ }
+}
+
std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script)
{
std::vector<Opcode> out;
diff --git a/src/script/miniscript.h b/src/script/miniscript.h
index 6faf2624fd..bb42bf3c92 100644
--- a/src/script/miniscript.h
+++ b/src/script/miniscript.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -223,6 +223,11 @@ enum class Fragment {
// WRAP_U(X) is represented as OR_I(X,0)
};
+enum class Availability {
+ NO,
+ YES,
+ MAYBE,
+};
namespace internal {
@@ -235,6 +240,62 @@ size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_
//! A helper sanitizer/checker for the output of CalcType.
Type SanitizeType(Type x);
+//! An object representing a sequence of witness stack elements.
+struct InputStack {
+ /** Whether this stack is valid for its intended purpose (satisfaction or dissatisfaction of a Node).
+ * The MAYBE value is used for size estimation, when keys/preimages may actually be unavailable,
+ * but may be available at signing time. This makes the InputStack structure and signing logic,
+ * filled with dummy signatures/preimages usable for witness size estimation.
+ */
+ Availability available = Availability::YES;
+ //! Whether this stack contains a digital signature.
+ bool has_sig = false;
+ //! Whether this stack is malleable (can be turned into an equally valid other stack by a third party).
+ bool malleable = false;
+ //! Whether this stack is non-canonical (using a construction known to be unnecessary for satisfaction).
+ //! Note that this flag does not affect the satisfaction algorithm; it is only used for sanity checking.
+ bool non_canon = false;
+ //! Serialized witness size.
+ size_t size = 0;
+ //! Data elements.
+ std::vector<std::vector<unsigned char>> stack;
+ //! Construct an empty stack (valid).
+ InputStack() {}
+ //! Construct a valid single-element stack (with an element up to 75 bytes).
+ InputStack(std::vector<unsigned char> in) : size(in.size() + 1), stack(Vector(std::move(in))) {}
+ //! Change availability
+ InputStack& SetAvailable(Availability avail);
+ //! Mark this input stack as having a signature.
+ InputStack& SetWithSig();
+ //! Mark this input stack as non-canonical (known to not be necessary in non-malleable satisfactions).
+ InputStack& SetNonCanon();
+ //! Mark this input stack as malleable.
+ InputStack& SetMalleable(bool x = true);
+ //! Concatenate two input stacks.
+ friend InputStack operator+(InputStack a, InputStack b);
+ //! Choose between two potential input stacks.
+ friend InputStack operator|(InputStack a, InputStack b);
+};
+
+/** A stack consisting of a single zero-length element (interpreted as 0 by the script interpreter in numeric context). */
+static const auto ZERO = InputStack(std::vector<unsigned char>());
+/** A stack consisting of a single malleable 32-byte 0x0000...0000 element (for dissatisfying hash challenges). */
+static const auto ZERO32 = InputStack(std::vector<unsigned char>(32, 0)).SetMalleable();
+/** A stack consisting of a single 0x01 element (interpreted as 1 by the script interpreted in numeric context). */
+static const auto ONE = InputStack(Vector((unsigned char)1));
+/** The empty stack. */
+static const auto EMPTY = InputStack();
+/** A stack representing the lack of any (dis)satisfactions. */
+static const auto INVALID = InputStack().SetAvailable(Availability::NO);
+
+//! A pair of a satisfaction and a dissatisfaction InputStack.
+struct InputResult {
+ InputStack nsat, sat;
+
+ template<typename A, typename B>
+ InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
+};
+
//! Class whose objects represent the maximum of a list of integers.
template<typename I>
struct MaxInt {
@@ -785,6 +846,226 @@ private:
assert(false);
}
+ template<typename Ctx>
+ internal::InputResult ProduceInput(const Ctx& ctx) const {
+ using namespace internal;
+
+ // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
+ // given those of its subnodes.
+ auto helper = [&ctx](const Node& node, Span<InputResult> subres) -> InputResult {
+ switch (node.fragment) {
+ case Fragment::PK_K: {
+ std::vector<unsigned char> sig;
+ Availability avail = ctx.Sign(node.keys[0], sig);
+ return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
+ }
+ case Fragment::PK_H: {
+ std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
+ Availability avail = ctx.Sign(node.keys[0], sig);
+ return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
+ }
+ case Fragment::MULTI: {
+ // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
+ // In the loop below, these stacks are built up using a dynamic programming approach.
+ // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
+ std::vector<InputStack> sats = Vector(ZERO);
+ for (size_t i = 0; i < node.keys.size(); ++i) {
+ std::vector<unsigned char> sig;
+ Availability avail = ctx.Sign(node.keys[i], sig);
+ // Compute signature stack for just the i'th key.
+ auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
+ // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
+ // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
+ // current (i'th) key. The very last element needs all signatures filled.
+ std::vector<InputStack> next_sats;
+ next_sats.push_back(sats[0]);
+ for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
+ next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
+ // Switch over.
+ sats = std::move(next_sats);
+ }
+ // The dissatisfaction consists of k+1 stack elements all equal to 0.
+ InputStack nsat = ZERO;
+ for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
+ assert(node.k <= sats.size());
+ return {std::move(nsat), std::move(sats[node.k])};
+ }
+ case Fragment::THRESH: {
+ // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
+ // In the loop below, these stacks are built up using a dynamic programming approach.
+ // sats[0] starts off empty.
+ std::vector<InputStack> sats = Vector(EMPTY);
+ for (size_t i = 0; i < subres.size(); ++i) {
+ // Introduce an alias for the i'th last satisfaction/dissatisfaction.
+ auto& res = subres[subres.size() - i - 1];
+ // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
+ // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
+ // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
+ std::vector<InputStack> next_sats;
+ next_sats.push_back(sats[0] + res.nsat);
+ for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
+ next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
+ // Switch over.
+ sats = std::move(next_sats);
+ }
+ // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
+ // is computed by gathering all sats[i].nsat for i != k.
+ InputStack nsat = INVALID;
+ for (size_t i = 0; i < sats.size(); ++i) {
+ // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
+ // the rest are non-canonical (a no-signature dissatisfaction - the i=0
+ // form - is always available) and malleable (due to overcompleteness).
+ // Marking the solutions malleable here is not strictly necessary, as they
+ // should already never be picked in non-malleable solutions due to the
+ // availability of the i=0 form.
+ if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
+ // Include all dissatisfactions (even these non-canonical ones) in nsat.
+ if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
+ }
+ assert(node.k <= sats.size());
+ return {std::move(nsat), std::move(sats[node.k])};
+ }
+ case Fragment::OLDER: {
+ return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
+ }
+ case Fragment::AFTER: {
+ return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
+ }
+ case Fragment::SHA256: {
+ std::vector<unsigned char> preimage;
+ Availability avail = ctx.SatSHA256(node.data, preimage);
+ return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
+ }
+ case Fragment::RIPEMD160: {
+ std::vector<unsigned char> preimage;
+ Availability avail = ctx.SatRIPEMD160(node.data, preimage);
+ return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
+ }
+ case Fragment::HASH256: {
+ std::vector<unsigned char> preimage;
+ Availability avail = ctx.SatHASH256(node.data, preimage);
+ return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
+ }
+ case Fragment::HASH160: {
+ std::vector<unsigned char> preimage;
+ Availability avail = ctx.SatHASH160(node.data, preimage);
+ return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
+ }
+ case Fragment::AND_V: {
+ auto& x = subres[0], &y = subres[1];
+ // As the dissatisfaction here only consist of a single option, it doesn't
+ // actually need to be listed (it's not required for reasoning about malleability of
+ // other options), and is never required (no valid miniscript relies on the ability
+ // to satisfy the type V left subexpression). It's still listed here for
+ // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
+ // care about malleability might in some cases prefer it still.
+ return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
+ }
+ case Fragment::AND_B: {
+ auto& x = subres[0], &y = subres[1];
+ // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
+ // as malleable. While they are definitely malleable, they are also non-canonical due
+ // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
+ // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
+ // weren't marked as malleable.
+ return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
+ }
+ case Fragment::OR_B: {
+ auto& x = subres[0], &z = subres[1];
+ // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
+ return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
+ }
+ case Fragment::OR_C: {
+ auto& x = subres[0], &z = subres[1];
+ return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
+ }
+ case Fragment::OR_D: {
+ auto& x = subres[0], &z = subres[1];
+ return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
+ }
+ case Fragment::OR_I: {
+ auto& x = subres[0], &z = subres[1];
+ return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
+ }
+ case Fragment::ANDOR: {
+ auto& x = subres[0], &y = subres[1], &z = subres[2];
+ return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
+ }
+ case Fragment::WRAP_A:
+ case Fragment::WRAP_S:
+ case Fragment::WRAP_C:
+ case Fragment::WRAP_N:
+ return std::move(subres[0]);
+ case Fragment::WRAP_D: {
+ auto &x = subres[0];
+ return {ZERO, x.sat + ONE};
+ }
+ case Fragment::WRAP_J: {
+ auto &x = subres[0];
+ // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
+ // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
+ // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
+ // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
+ // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
+ return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
+ }
+ case Fragment::WRAP_V: {
+ auto &x = subres[0];
+ return {INVALID, std::move(x.sat)};
+ }
+ case Fragment::JUST_0: return {EMPTY, INVALID};
+ case Fragment::JUST_1: return {INVALID, EMPTY};
+ }
+ assert(false);
+ return {INVALID, INVALID};
+ };
+
+ auto tester = [&helper](const Node& node, Span<InputResult> subres) -> InputResult {
+ auto ret = helper(node, subres);
+
+ // Do a consistency check between the satisfaction code and the type checker
+ // (the actual satisfaction code in ProduceInputHelper does not use GetType)
+
+ // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
+ if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) assert(ret.nsat.stack.size() == 0);
+ if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) assert(ret.sat.stack.size() == 0);
+
+ // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
+ if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) assert(ret.nsat.stack.size() == 1);
+ if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) assert(ret.sat.stack.size() == 1);
+
+ // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
+ // the top element cannot be 0.
+ if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) assert(ret.sat.stack.size() >= 1);
+ if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) assert(ret.nsat.stack.size() >= 1);
+ if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) assert(!ret.sat.stack.back().empty());
+
+ // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
+ // it must be canonical.
+ if (node.GetType() << "d"_mst) assert(ret.nsat.available != Availability::NO);
+ if (node.GetType() << "d"_mst) assert(!ret.nsat.has_sig);
+ if (node.GetType() << "d"_mst && !ret.nsat.malleable) assert(!ret.nsat.non_canon);
+
+ // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
+ if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) assert(ret.nsat.has_sig);
+ if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) assert(ret.sat.has_sig);
+
+ // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
+ if (node.GetType() << "me"_mst) assert(ret.nsat.available != Availability::NO);
+ if (node.GetType() << "me"_mst) assert(!ret.nsat.malleable);
+
+ // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
+ if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) assert(!ret.sat.malleable);
+
+ // If a non-malleable satisfaction exists, it must be canonical.
+ if (ret.sat.available != Availability::NO && !ret.sat.malleable) assert(!ret.sat.non_canon);
+
+ return ret;
+ };
+
+ return TreeEval<InputResult>(tester);
+ }
+
public:
/** Update duplicate key information in this Node.
*
@@ -855,6 +1136,9 @@ public:
//! Return the maximum number of ops needed to satisfy this script non-malleably.
uint32_t GetOps() const { return ops.count + ops.sat.value; }
+ //! Return the number of ops in the script (not counting the dynamic ones that depend on execution).
+ uint32_t GetStaticOps() const { return ops.count; }
+
//! Check the ops limit of this script against the consensus limit.
bool CheckOpsLimit() const { return GetOps() <= MAX_OPS_PER_SCRIPT; }
@@ -877,6 +1161,47 @@ public:
});
}
+ //! Determine whether a Miniscript node is satisfiable. fn(node) will be invoked for all
+ //! key, time, and hashing nodes, and should return their satisfiability.
+ template<typename F>
+ bool IsSatisfiable(F fn) const
+ {
+ // TreeEval() doesn't support bool as NodeType, so use int instead.
+ return TreeEval<int>([&fn](const Node& node, Span<int> subs) -> bool {
+ switch (node.fragment) {
+ case Fragment::JUST_0:
+ return false;
+ case Fragment::JUST_1:
+ return true;
+ case Fragment::PK_K:
+ case Fragment::PK_H:
+ case Fragment::MULTI:
+ case Fragment::AFTER:
+ case Fragment::OLDER:
+ case Fragment::HASH256:
+ case Fragment::HASH160:
+ case Fragment::SHA256:
+ case Fragment::RIPEMD160:
+ return bool{fn(node)};
+ case Fragment::ANDOR:
+ return (subs[0] && subs[1]) || subs[2];
+ case Fragment::AND_V:
+ case Fragment::AND_B:
+ return subs[0] && subs[1];
+ case Fragment::OR_B:
+ case Fragment::OR_C:
+ case Fragment::OR_D:
+ case Fragment::OR_I:
+ return subs[0] || subs[1];
+ case Fragment::THRESH:
+ return std::count(subs.begin(), subs.end(), true) >= node.k;
+ default: // wrappers
+ assert(subs.size() == 1);
+ return subs[0];
+ }
+ });
+ }
+
//! Check whether this node is valid at all.
bool IsValid() const { return !(GetType() == ""_mst) && ScriptSize() <= MAX_STANDARD_P2WSH_SCRIPT_SIZE; }
@@ -904,6 +1229,18 @@ public:
//! Check whether this node is safe as a script on its own.
bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
+ //! Produce a witness for this script, if possible and given the information available in the context.
+ //! The non-malleable satisfaction is guaranteed to be valid if it exists, and ValidSatisfaction()
+ //! is true. If IsSane() holds, this satisfaction is guaranteed to succeed in case the node's
+ //! conditions are satisfied (private keys and hash preimages available, locktimes satsified).
+ template<typename Ctx>
+ Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
+ auto ret = ProduceInput(ctx);
+ if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
+ stack = std::move(ret.sat.stack);
+ return ret.sat.available;
+ }
+
//! Equality testing.
bool operator==(const Node<Key>& arg) const { return Compare(*this, arg) == 0; }
@@ -1378,7 +1715,7 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx)
assert(constructed.size() == 1);
assert(constructed[0]->ScriptSize() == script_size);
if (in.size() > 0) return {};
- const NodeRef<Key> tl_node = std::move(constructed.front());
+ NodeRef<Key> tl_node = std::move(constructed.front());
tl_node->DuplicateKeyCheck(ctx);
return tl_node;
}
@@ -1813,7 +2150,7 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx)
}
}
if (constructed.size() != 1) return {};
- const NodeRef<Key> tl_node = std::move(constructed.front());
+ NodeRef<Key> tl_node = std::move(constructed.front());
tl_node->DuplicateKeyCheck(ctx);
// Note that due to how ComputeType works (only assign the type to the node if the
// subs' types are valid) this would fail if any node of tree is badly typed.
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 88b4bc2f44..79d19b9085 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/script.h b/src/script/script.h
index 1e5f694d52..374ae1642e 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index e507ec7528..fef3601887 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 290955090d..d33d60d5bc 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 5da0d076d8..85589fe86b 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,6 +10,7 @@
#include <policy/policy.h>
#include <primitives/transaction.h>
#include <script/keyorigin.h>
+#include <script/miniscript.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <uint256.h>
@@ -146,6 +147,16 @@ static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdat
static bool CreateTaprootScriptSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const XOnlyPubKey& pubkey, const uint256& leaf_hash, SigVersion sigversion)
{
+ KeyOriginInfo info;
+ if (provider.GetKeyOriginByXOnly(pubkey, info)) {
+ auto it = sigdata.taproot_misc_pubkeys.find(pubkey);
+ if (it == sigdata.taproot_misc_pubkeys.end()) {
+ sigdata.taproot_misc_pubkeys.emplace(pubkey, std::make_pair(std::set<uint256>({leaf_hash}), info));
+ } else {
+ it->second.first.insert(leaf_hash);
+ }
+ }
+
auto lookup_key = std::make_pair(pubkey, leaf_hash);
auto it = sigdata.taproot_script_sigs.find(lookup_key);
if (it != sigdata.taproot_script_sigs.end()) {
@@ -159,28 +170,18 @@ static bool CreateTaprootScriptSig(const BaseSignatureCreator& creator, Signatur
return false;
}
-static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatureCreator& creator, SignatureData& sigdata, int leaf_version, const CScript& script, std::vector<valtype>& result)
+static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatureCreator& creator, SignatureData& sigdata, int leaf_version, Span<const unsigned char> script_bytes, std::vector<valtype>& result)
{
// Only BIP342 tapscript signing is supported for now.
if (leaf_version != TAPROOT_LEAF_TAPSCRIPT) return false;
SigVersion sigversion = SigVersion::TAPSCRIPT;
- uint256 leaf_hash = (HashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
+ uint256 leaf_hash = ComputeTapleafHash(leaf_version, script_bytes);
+ CScript script = CScript(script_bytes.begin(), script_bytes.end());
// <xonly pubkey> OP_CHECKSIG
if (script.size() == 34 && script[33] == OP_CHECKSIG && script[0] == 0x20) {
XOnlyPubKey pubkey{Span{script}.subspan(1, 32)};
-
- KeyOriginInfo info;
- if (provider.GetKeyOriginByXOnly(pubkey, info)) {
- auto it = sigdata.taproot_misc_pubkeys.find(pubkey);
- if (it == sigdata.taproot_misc_pubkeys.end()) {
- sigdata.taproot_misc_pubkeys.emplace(pubkey, std::make_pair(std::set<uint256>({leaf_hash}), info));
- } else {
- it->second.first.insert(leaf_hash);
- }
- }
-
std::vector<unsigned char> sig;
if (CreateTaprootScriptSig(creator, sigdata, provider, sig, pubkey, leaf_hash, sigversion)) {
result = Vector(std::move(sig));
@@ -286,7 +287,6 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
std::vector<valtype>& ret, TxoutType& whichTypeRet, SigVersion sigversion, SignatureData& sigdata)
{
CScript scriptRet;
- uint160 h160;
ret.clear();
std::vector<unsigned char> sig;
@@ -315,8 +315,8 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
ret.push_back(ToByteVector(pubkey));
return true;
}
- case TxoutType::SCRIPTHASH:
- h160 = uint160(vSolutions[0]);
+ case TxoutType::SCRIPTHASH: {
+ uint160 h160{vSolutions[0]};
if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) {
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
return true;
@@ -324,7 +324,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
// Could not find redeemScript, add to missing
sigdata.missing_redeem_script = h160;
return false;
-
+ }
case TxoutType::MULTISIG: {
size_t required = vSolutions.front()[0];
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
@@ -350,8 +350,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
return true;
case TxoutType::WITNESS_V0_SCRIPTHASH:
- CRIPEMD160().Write(vSolutions[0].data(), vSolutions[0].size()).Finalize(h160.begin());
- if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) {
+ if (GetCScript(provider, sigdata, CScriptID{RIPEMD160(vSolutions[0])}, scriptRet)) {
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
return true;
}
@@ -382,6 +381,92 @@ static CScript PushAll(const std::vector<valtype>& values)
return result;
}
+template<typename M, typename K, typename V>
+miniscript::Availability MsLookupHelper(const M& map, const K& key, V& value)
+{
+ auto it = map.find(key);
+ if (it != map.end()) {
+ value = it->second;
+ return miniscript::Availability::YES;
+ }
+ return miniscript::Availability::NO;
+}
+
+/**
+ * Context for solving a Miniscript.
+ * If enough material (access to keys, hash preimages, ..) is given, produces a valid satisfaction.
+ */
+struct Satisfier {
+ typedef CPubKey Key;
+
+ const SigningProvider& m_provider;
+ SignatureData& m_sig_data;
+ const BaseSignatureCreator& m_creator;
+ const CScript& m_witness_script;
+
+ explicit Satisfier(const SigningProvider& provider LIFETIMEBOUND, SignatureData& sig_data LIFETIMEBOUND,
+ const BaseSignatureCreator& creator LIFETIMEBOUND,
+ const CScript& witscript LIFETIMEBOUND) : m_provider(provider),
+ m_sig_data(sig_data),
+ m_creator(creator),
+ m_witness_script(witscript) {}
+
+ static bool KeyCompare(const Key& a, const Key& b) {
+ return a < b;
+ }
+
+ //! Conversion from a raw public key.
+ template <typename I>
+ std::optional<Key> FromPKBytes(I first, I last) const
+ {
+ Key pubkey{first, last};
+ if (pubkey.IsValid()) return pubkey;
+ return {};
+ }
+
+ //! Conversion from a raw public key hash.
+ template<typename I>
+ std::optional<Key> FromPKHBytes(I first, I last) const {
+ assert(last - first == 20);
+ Key pubkey;
+ CKeyID key_id;
+ std::copy(first, last, key_id.begin());
+ if (GetPubKey(m_provider, m_sig_data, key_id, pubkey)) return pubkey;
+ m_sig_data.missing_pubkeys.push_back(key_id);
+ return {};
+ }
+
+ //! Conversion to raw public key.
+ std::vector<unsigned char> ToPKBytes(const CPubKey& key) const { return {key.begin(), key.end()}; }
+
+ //! Satisfy a signature check.
+ miniscript::Availability Sign(const CPubKey& key, std::vector<unsigned char>& sig) const {
+ if (CreateSig(m_creator, m_sig_data, m_provider, sig, key, m_witness_script, SigVersion::WITNESS_V0)) {
+ return miniscript::Availability::YES;
+ }
+ return miniscript::Availability::NO;
+ }
+
+ //! Time lock satisfactions.
+ bool CheckAfter(uint32_t value) const { return m_creator.Checker().CheckLockTime(CScriptNum(value)); }
+ bool CheckOlder(uint32_t value) const { return m_creator.Checker().CheckSequence(CScriptNum(value)); }
+
+
+ //! Hash preimage satisfactions.
+ miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
+ return MsLookupHelper(m_sig_data.sha256_preimages, hash, preimage);
+ }
+ miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
+ return MsLookupHelper(m_sig_data.ripemd160_preimages, hash, preimage);
+ }
+ miniscript::Availability SatHASH256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
+ return MsLookupHelper(m_sig_data.hash256_preimages, hash, preimage);
+ }
+ miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
+ return MsLookupHelper(m_sig_data.hash160_preimages, hash, preimage);
+ }
+};
+
bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata)
{
if (sigdata.complete) return true;
@@ -417,9 +502,21 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
{
CScript witnessscript(result[0].begin(), result[0].end());
sigdata.witness_script = witnessscript;
- TxoutType subType;
+
+ TxoutType subType{TxoutType::NONSTANDARD};
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TxoutType::SCRIPTHASH && subType != TxoutType::WITNESS_V0_SCRIPTHASH && subType != TxoutType::WITNESS_V0_KEYHASH;
+
+ // If we couldn't find a solution with the legacy satisfier, try satisfying the script using Miniscript.
+ // Note we need to check if the result stack is empty before, because it might be used even if the Script
+ // isn't fully solved. For instance the CHECKMULTISIG satisfaction in SignStep() pushes partial signatures
+ // and the extractor relies on this behaviour to combine witnesses.
+ if (!solved && result.empty()) {
+ Satisfier ms_satisfier{provider, sigdata, creator, witnessscript};
+ const auto ms = miniscript::FromScript(witnessscript, ms_satisfier);
+ solved = ms && ms->Satisfy(ms_satisfier, result) == miniscript::Availability::YES;
+ }
result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
+
sigdata.scriptWitness.stack = result;
sigdata.witness = true;
result.clear();
@@ -565,26 +662,25 @@ void SignatureData::MergeSignatureData(SignatureData sigdata)
signatures.insert(std::make_move_iterator(sigdata.signatures.begin()), std::make_move_iterator(sigdata.signatures.end()));
}
-bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
+bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, SignatureData& sig_data)
{
assert(nIn < txTo.vin.size());
MutableTransactionSignatureCreator creator(txTo, nIn, amount, nHashType);
- SignatureData sigdata;
- bool ret = ProduceSignature(provider, creator, fromPubKey, sigdata);
- UpdateInput(txTo.vin.at(nIn), sigdata);
+ bool ret = ProduceSignature(provider, creator, fromPubKey, sig_data);
+ UpdateInput(txTo.vin.at(nIn), sig_data);
return ret;
}
-bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
+bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, SignatureData& sig_data)
{
assert(nIn < txTo.vin.size());
const CTxIn& txin = txTo.vin[nIn];
assert(txin.prevout.n < txFrom.vout.size());
const CTxOut& txout = txFrom.vout[txin.prevout.n];
- return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
+ return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, sig_data);
}
namespace {
@@ -593,8 +689,10 @@ class DummySignatureChecker final : public BaseSignatureChecker
{
public:
DummySignatureChecker() = default;
- bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; }
- bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const override { return true; }
+ bool CheckECDSASignature(const std::vector<unsigned char>& sig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return sig.size() != 0; }
+ bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const override { return sig.size() != 0; }
+ bool CheckLockTime(const CScriptNum& nLockTime) const override { return true; }
+ bool CheckSequence(const CScriptNum& nSequence) const override { return true; }
};
}
diff --git a/src/script/sign.h b/src/script/sign.h
index 813dfe04e3..f46bc55992 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,6 +13,7 @@
#include <script/interpreter.h>
#include <script/keyorigin.h>
#include <script/standard.h>
+#include <uint256.h>
class CKey;
class CKeyID;
@@ -82,6 +83,10 @@ struct SignatureData {
std::vector<CKeyID> missing_sigs; ///< KeyIDs of pubkeys for signatures which could not be found
uint160 missing_redeem_script; ///< ScriptID of the missing redeemScript (if any)
uint256 missing_witness_script; ///< SHA256 of the missing witnessScript (if any)
+ std::map<std::vector<uint8_t>, std::vector<uint8_t>> sha256_preimages; ///< Mapping from a SHA256 hash to its preimage provided to solve a Script
+ std::map<std::vector<uint8_t>, std::vector<uint8_t>> hash256_preimages; ///< Mapping from a HASH256 hash to its preimage provided to solve a Script
+ std::map<std::vector<uint8_t>, std::vector<uint8_t>> ripemd160_preimages; ///< Mapping from a RIPEMD160 hash to its preimage provided to solve a Script
+ std::map<std::vector<uint8_t>, std::vector<uint8_t>> hash160_preimages; ///< Mapping from a HASH160 hash to its preimage provided to solve a Script
SignatureData() {}
explicit SignatureData(const CScript& script) : scriptSig(script) {}
@@ -91,9 +96,24 @@ struct SignatureData {
/** Produce a script signature using a generic signature creator. */
bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata);
-/** Produce a script signature for a transaction. */
-bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
-bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
+/**
+ * Produce a satisfying script (scriptSig or witness).
+ *
+ * @param provider Utility containing the information necessary to solve a script.
+ * @param fromPubKey The script to produce a satisfaction for.
+ * @param txTo The spending transaction.
+ * @param nIn The index of the input in `txTo` referring the output being spent.
+ * @param amount The value of the output being spent.
+ * @param nHashType Signature hash type.
+ * @param sig_data Additional data provided to solve a script. Filled with the resulting satisfying
+ * script and whether the satisfaction is complete.
+ *
+ * @return True if the produced script is entirely satisfying `fromPubKey`.
+ **/
+bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo,
+ unsigned int nIn, const CAmount& amount, int nHashType, SignatureData& sig_data);
+bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo,
+ unsigned int nIn, int nHashType, SignatureData& sig_data);
/** Extract signature data from a transaction input, and insert it. */
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp
index a82a8b252a..ef055573b9 100644
--- a/src/script/signingprovider.cpp
+++ b/src/script/signingprovider.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,7 +7,7 @@
#include <script/signingprovider.h>
#include <script/standard.h>
-#include <util/system.h>
+#include <logging.h>
const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h
index 2d4234ea0b..a5bbcff6a0 100644
--- a/src/script/signingprovider.h
+++ b/src/script/signingprovider.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 6101738061..7c4a05b6e6 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -370,12 +370,7 @@ bool IsValidDestination(const CTxDestination& dest) {
leaf.merkle_branch.push_back(a.hash);
ret.leaves.emplace_back(std::move(leaf));
}
- /* Lexicographically sort a and b's hash, and compute parent hash. */
- if (a.hash < b.hash) {
- ret.hash = (HashWriter{HASHER_TAPBRANCH} << a.hash << b.hash).GetSHA256();
- } else {
- ret.hash = (HashWriter{HASHER_TAPBRANCH} << b.hash << a.hash).GetSHA256();
- }
+ ret.hash = ComputeTapbranchHash(a.hash, b.hash);
return ret;
}
@@ -443,14 +438,14 @@ void TaprootBuilder::Insert(TaprootBuilder::NodeInfo&& node, int depth)
return branch.size() == 0 || (branch.size() == 1 && branch[0]);
}
-TaprootBuilder& TaprootBuilder::Add(int depth, const CScript& script, int leaf_version, bool track)
+TaprootBuilder& TaprootBuilder::Add(int depth, Span<const unsigned char> script, int leaf_version, bool track)
{
assert((leaf_version & ~TAPROOT_LEAF_MASK) == 0);
if (!IsValid()) return *this;
/* Construct NodeInfo object with leaf hash and (if track is true) also leaf information. */
NodeInfo node;
- node.hash = (HashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
- if (track) node.leaves.emplace_back(LeafInfo{script, leaf_version, {}});
+ node.hash = ComputeTapleafHash(leaf_version, script);
+ if (track) node.leaves.emplace_back(LeafInfo{std::vector<unsigned char>(script.begin(), script.end()), leaf_version, {}});
/* Insert into the branch. */
Insert(std::move(node), depth);
return *this;
@@ -506,13 +501,13 @@ TaprootSpendData TaprootBuilder::GetSpendData() const
return spd;
}
-std::optional<std::vector<std::tuple<int, CScript, int>>> InferTaprootTree(const TaprootSpendData& spenddata, const XOnlyPubKey& output)
+std::optional<std::vector<std::tuple<int, std::vector<unsigned char>, int>>> InferTaprootTree(const TaprootSpendData& spenddata, const XOnlyPubKey& output)
{
// Verify that the output matches the assumed Merkle root and internal key.
auto tweak = spenddata.internal_key.CreateTapTweak(spenddata.merkle_root.IsNull() ? nullptr : &spenddata.merkle_root);
if (!tweak || tweak->first != output) return std::nullopt;
// If the Merkle root is 0, the tree is empty, and we're done.
- std::vector<std::tuple<int, CScript, int>> ret;
+ std::vector<std::tuple<int, std::vector<unsigned char>, int>> ret;
if (spenddata.merkle_root.IsNull()) return ret;
/** Data structure to represent the nodes of the tree we're going to build. */
@@ -523,7 +518,7 @@ std::optional<std::vector<std::tuple<int, CScript, int>>> InferTaprootTree(const
std::unique_ptr<TreeNode> sub[2];
/** If this is known to be a leaf node, a pointer to the (script, leaf_ver) pair.
* nullptr otherwise. */
- const std::pair<CScript, int>* leaf = nullptr;
+ const std::pair<std::vector<unsigned char>, int>* leaf = nullptr;
/** Whether or not this node has been explored (is known to be a leaf, or known to have children). */
bool explored = false;
/** Whether or not this node is an inner node (unknown until explored = true). */
@@ -607,7 +602,7 @@ std::optional<std::vector<std::tuple<int, CScript, int>>> InferTaprootTree(const
node.done = true;
stack.pop_back();
} else if (node.sub[0]->done && !node.sub[1]->done && !node.sub[1]->explored && !node.sub[1]->hash.IsNull() &&
- (HashWriter{HASHER_TAPBRANCH} << node.sub[1]->hash << node.sub[1]->hash).GetSHA256() == node.hash) {
+ ComputeTapbranchHash(node.sub[1]->hash, node.sub[1]->hash) == node.hash) {
// Whenever there are nodes with two identical subtrees under it, we run into a problem:
// the control blocks for the leaves underneath those will be identical as well, and thus
// they will all be matched to the same path in the tree. The result is that at the location
@@ -641,10 +636,10 @@ std::optional<std::vector<std::tuple<int, CScript, int>>> InferTaprootTree(const
return ret;
}
-std::vector<std::tuple<uint8_t, uint8_t, CScript>> TaprootBuilder::GetTreeTuples() const
+std::vector<std::tuple<uint8_t, uint8_t, std::vector<unsigned char>>> TaprootBuilder::GetTreeTuples() const
{
assert(IsComplete());
- std::vector<std::tuple<uint8_t, uint8_t, CScript>> tuples;
+ std::vector<std::tuple<uint8_t, uint8_t, std::vector<unsigned char>>> tuples;
if (m_branch.size()) {
const auto& leaves = m_branch[0]->leaves;
for (const auto& leaf : leaves) {
diff --git a/src/script/standard.h b/src/script/standard.h
index 1e6769782a..18cf5c8c88 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -217,7 +217,7 @@ struct TaprootSpendData
* inference can reconstruct the full tree. Within each set, the control
* blocks are sorted by size, so that the signing logic can easily
* prefer the cheapest one. */
- std::map<std::pair<CScript, int>, std::set<std::vector<unsigned char>, ShortestVectorFirstComparator>> scripts;
+ std::map<std::pair<std::vector<unsigned char>, int>, std::set<std::vector<unsigned char>, ShortestVectorFirstComparator>> scripts;
/** Merge other TaprootSpendData (for the same scriptPubKey) into this. */
void Merge(TaprootSpendData other);
};
@@ -229,7 +229,7 @@ private:
/** Information about a tracked leaf in the Merkle tree. */
struct LeafInfo
{
- CScript script; //!< The script.
+ std::vector<unsigned char> script; //!< The script.
int leaf_version; //!< The leaf version for that script.
std::vector<uint256> merkle_branch; //!< The hashing partners above this leaf.
};
@@ -296,7 +296,7 @@ public:
/** Add a new script at a certain depth in the tree. Add() operations must be called
* in depth-first traversal order of binary tree. If track is true, it will be included in
* the GetSpendData() output. */
- TaprootBuilder& Add(int depth, const CScript& script, int leaf_version, bool track = true);
+ TaprootBuilder& Add(int depth, Span<const unsigned char> script, int leaf_version, bool track = true);
/** Like Add(), but for a Merkle node with a given hash to the tree. */
TaprootBuilder& AddOmitted(int depth, const uint256& hash);
/** Finalize the construction. Can only be called when IsComplete() is true.
@@ -314,7 +314,9 @@ public:
/** Compute spending data (after Finalize()). */
TaprootSpendData GetSpendData() const;
/** Returns a vector of tuples representing the depth, leaf version, and script */
- std::vector<std::tuple<uint8_t, uint8_t, CScript>> GetTreeTuples() const;
+ std::vector<std::tuple<uint8_t, uint8_t, std::vector<unsigned char>>> GetTreeTuples() const;
+ /** Returns true if there are any tapscripts */
+ bool HasScripts() const { return !m_branch.empty(); }
};
/** Given a TaprootSpendData and the output key, reconstruct its script tree.
@@ -323,6 +325,6 @@ public:
* std::nullopt is returned. Otherwise, a vector of (depth, script, leaf_ver) tuples is
* returned, corresponding to a depth-first traversal of the script tree.
*/
-std::optional<std::vector<std::tuple<int, CScript, int>>> InferTaprootTree(const TaprootSpendData& spenddata, const XOnlyPubKey& output);
+std::optional<std::vector<std::tuple<int, std::vector<unsigned char>, int>>> InferTaprootTree(const TaprootSpendData& spenddata, const XOnlyPubKey& output);
#endif // BITCOIN_SCRIPT_STANDARD_H
diff --git a/src/secp256k1/.cirrus.yml b/src/secp256k1/.cirrus.yml
index a2e7f36d1f..0b904a4e38 100644
--- a/src/secp256k1/.cirrus.yml
+++ b/src/secp256k1/.cirrus.yml
@@ -1,6 +1,9 @@
env:
+ ### cirrus config
+ CIRRUS_CLONE_DEPTH: 1
### compiler options
HOST:
+ WRAPPER_CMD:
# Specific warnings can be disabled with -Wno-error=foo.
# -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
WERROR_CFLAGS: -Werror -pedantic-errors
@@ -22,21 +25,27 @@ env:
SECP256K1_TEST_ITERS:
BENCH: yes
SECP256K1_BENCH_ITERS: 2
- CTIMETEST: yes
+ CTIMETESTS: yes
# Compile and run the tests
EXAMPLES: yes
+# https://cirrus-ci.org/pricing/#compute-credits
+credits_snippet: &CREDITS
+ # Don't use any credits for now.
+ use_compute_credits: false
+
cat_logs_snippet: &CAT_LOGS
always:
cat_tests_log_script:
- cat tests.log || true
+ cat_noverify_tests_log_script:
+ - cat noverify_tests.log || true
cat_exhaustive_tests_log_script:
- cat exhaustive_tests.log || true
- cat_valgrind_ctime_test_log_script:
- - cat valgrind_ctime_test.log || true
+ cat_ctime_tests_log_script:
+ - cat ctime_tests.log || true
cat_bench_log_script:
- cat bench.log || true
- on_failure:
cat_config_log_script:
- cat config.log || true
cat_test_env_script:
@@ -47,10 +56,8 @@ cat_logs_snippet: &CAT_LOGS
merge_base_script_snippet: &MERGE_BASE
merge_base_script:
- if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
- - git fetch $CIRRUS_REPO_CLONE_URL $CIRRUS_BASE_BRANCH
- - git config --global user.email "ci@ci.ci"
- - git config --global user.name "ci"
- - git merge FETCH_HEAD # Merge base to detect silent merge conflicts
+ - git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge"
+ - git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts
linux_container_snippet: &LINUX_CONTAINER
container:
@@ -69,13 +76,15 @@ task:
- env: {WIDEMUL: int64, RECOVERY: yes}
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128}
+ - env: {WIDEMUL: int128_struct}
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ASM: x86_64}
- env: { RECOVERY: yes, SCHNORRSIG: yes}
- - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
+ - env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, CPPFLAGS: -DVERIFY}
+ - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no}
- env: {CPPFLAGS: -DDETERMINISTIC}
- - env: {CFLAGS: -O0, CTIMETEST: no}
+ - env: {CFLAGS: -O0, CTIMETESTS: no}
- env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
- env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 }
matrix:
@@ -107,65 +116,32 @@ task:
<< : *CAT_LOGS
task:
- name: "x86_64: macOS Catalina"
+ name: "arm64: macOS Ventura"
macos_instance:
- image: catalina-base
+ image: ghcr.io/cirruslabs/macos-ventura-base:latest
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
- # Cirrus gives us a fixed number of 12 virtual CPUs. Not that we even have that many jobs at the moment...
- MAKEFLAGS: -j13
+ # Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment...
+ MAKEFLAGS: -j5
matrix:
<< : *ENV_MATRIX
+ env:
+ ASM: no
+ WITH_VALGRIND: no
+ CTIMETESTS: no
matrix:
- env:
- CC: gcc-9
+ CC: gcc
- env:
CC: clang
- # Update Command Line Tools
- # Uncomment this if the Command Line Tools on the CirrusCI macOS image are too old to brew valgrind.
- # See https://apple.stackexchange.com/a/195963 for the implementation.
- ## update_clt_script:
- ## - system_profiler SPSoftwareDataType
- ## - touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
- ## - |-
- ## PROD=$(softwareupdate -l | grep "*.*Command Line" | tail -n 1 | awk -F"*" '{print $2}' | sed -e 's/^ *//' | sed 's/Label: //g' | tr -d '\n')
- ## # For debugging
- ## - softwareupdate -l && echo "PROD: $PROD"
- ## - softwareupdate -i "$PROD" --verbose
- ## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
- ##
- brew_valgrind_pre_script:
- # Retry a few times because this tends to fail randomly.
- - for i in {1..5}; do brew update && break || sleep 15; done
- - brew config
- - brew tap LouisBrunner/valgrind
- # Fetch valgrind source but don't build it yet.
- - brew fetch --HEAD LouisBrunner/valgrind/valgrind
- brew_valgrind_cache:
- # This is $(brew --cellar valgrind) but command substition does not work here.
- folder: /usr/local/Cellar/valgrind
- # Rebuild cache if ...
- fingerprint_script:
- # ... macOS version changes:
- - sw_vers
- # ... brew changes:
- - brew config
- # ... valgrind changes:
- - git -C "$(brew --cache)/valgrind--git" rev-parse HEAD
- populate_script:
- # If there's no hit in the cache, build and install valgrind.
- - brew install --HEAD LouisBrunner/valgrind/valgrind
- brew_valgrind_post_script:
- # If we have restored valgrind from the cache, tell brew to create symlink to the PATH.
- # If we haven't restored from cached (and just run brew install), this is a no-op.
- - brew link valgrind
brew_script:
- - brew install automake libtool gcc@9
+ - brew install automake libtool gcc
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
+ << : *CREDITS
task:
name: "s390x (big-endian): Linux (Debian stable, QEMU)"
@@ -178,7 +154,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
- CTIMETEST: no
+ CTIMETESTS: no
<< : *MERGE_BASE
test_script:
# https://sourceware.org/bugzilla/show_bug.cgi?id=27008
@@ -197,7 +173,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
- CTIMETEST: no
+ CTIMETESTS: no
matrix:
- env: {}
- env: {EXPERIMENTAL: yes, ASM: arm}
@@ -217,7 +193,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
- CTIMETEST: no
+ CTIMETESTS: no
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@@ -234,24 +210,70 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
- CTIMETEST: no
+ CTIMETESTS: no
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
- name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
<< : *LINUX_CONTAINER
env:
- WRAPPER_CMD: wine64-stable
- SECP256K1_TEST_ITERS: 16
- HOST: x86_64-w64-mingw32
+ WRAPPER_CMD: wine
+ WITH_VALGRIND: no
+ ECDH: yes
+ RECOVERY: yes
+ SCHNORRSIG: yes
+ CTIMETESTS: no
+ matrix:
+ - name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
+ env:
+ HOST: x86_64-w64-mingw32
+ - name: "i686 (mingw32-w64): Windows (Debian stable, Wine)"
+ env:
+ HOST: i686-w64-mingw32
+ << : *MERGE_BASE
+ test_script:
+ - ./ci/cirrus.sh
+ << : *CAT_LOGS
+
+task:
+ << : *LINUX_CONTAINER
+ env:
+ WRAPPER_CMD: wine
+ WERROR_CFLAGS: -WX
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
+ EXPERIMENTAL: yes
SCHNORRSIG: yes
- CTIMETEST: no
+ CTIMETESTS: no
+ # Use a MinGW-w64 host to tell ./configure we're building for Windows.
+ # This will detect some MinGW-w64 tools but then make will need only
+ # the MSVC tools CC, AR and NM as specified below.
+ HOST: x86_64-w64-mingw32
+ CC: /opt/msvc/bin/x64/cl
+ AR: /opt/msvc/bin/x64/lib
+ NM: /opt/msvc/bin/x64/dumpbin -symbols -headers
+ # Set non-essential options that affect the CLI messages here.
+ # (They depend on the user's taste, so we don't want to set them automatically in configure.ac.)
+ CFLAGS: -nologo -diagnostics:caret
+ LDFLAGS: -Xlinker -Xlinker -Xlinker -nologo
+ matrix:
+ - name: "x86_64 (MSVC): Windows (Debian stable, Wine)"
+ - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)"
+ env:
+ WIDEMUL: int128_struct
+ - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct with __(u)mulh)"
+ env:
+ WIDEMUL: int128_struct
+ CPPFLAGS: -DSECP256K1_MSVC_MULH_TEST_OVERRIDE
+ - name: "i686 (MSVC): Windows (Debian stable, Wine)"
+ env:
+ HOST: i686-w64-mingw32
+ CC: /opt/msvc/bin/x86/cl
+ AR: /opt/msvc/bin/x86/lib
+ NM: /opt/msvc/bin/x86/dumpbin -symbols -headers
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@@ -264,7 +286,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
- CTIMETEST: no
+ CTIMETESTS: no
matrix:
- name: "Valgrind (memcheck)"
container:
@@ -301,14 +323,40 @@ task:
- ./ci/cirrus.sh
<< : *CAT_LOGS
+# Memory sanitizers
task:
- name: "C++ -fpermissive"
<< : *LINUX_CONTAINER
+ name: "MSan"
env:
- # ./configure correctly errors out when given CC=g++.
- # We hack around this by passing CC=g++ only to make.
- CC: gcc
- MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g
+ ECDH: yes
+ RECOVERY: yes
+ SCHNORRSIG: yes
+ CTIMETESTS: yes
+ CC: clang
+ SECP256K1_TEST_ITERS: 32
+ ASM: no
+ WITH_VALGRIND: no
+ container:
+ memory: 2G
+ matrix:
+ - env:
+ CFLAGS: "-fsanitize=memory -g"
+ - env:
+ ECMULTGENPRECISION: 2
+ ECMULTWINDOW: 2
+ CFLAGS: "-fsanitize=memory -g -O3"
+ << : *MERGE_BASE
+ test_script:
+ - ./ci/cirrus.sh
+ << : *CAT_LOGS
+
+task:
+ name: "C++ -fpermissive (entire project)"
+ << : *LINUX_CONTAINER
+ env:
+ CC: g++
+ CFLAGS: -fpermissive -g
+ CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE
WERROR_CFLAGS:
ECDH: yes
RECOVERY: yes
@@ -319,8 +367,43 @@ task:
<< : *CAT_LOGS
task:
+ name: "C++ (public headers)"
+ << : *LINUX_CONTAINER
+ test_script:
+ - g++ -Werror include/*.h
+ - clang -Werror -x c++-header include/*.h
+ - /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h
+
+task:
name: "sage prover"
<< : *LINUX_CONTAINER
test_script:
- cd sage
- sage prove_group_implementations.sage
+
+task:
+ name: "x86_64: Windows (VS 2022)"
+ windows_container:
+ image: cirrusci/windowsservercore:visualstudio2022
+ cpu: 4
+ memory: 3840MB
+ env:
+ PATH: '%CIRRUS_WORKING_DIR%\build\src\RelWithDebInfo;%PATH%'
+ x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'
+ # Ignore MSBuild warning MSB8029.
+ # See: https://learn.microsoft.com/en-us/visualstudio/msbuild/errors/msb8029?view=vs-2022
+ IgnoreWarnIntDirInTempDetected: 'true'
+ merge_script:
+ - PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; }
+ configure_script:
+ - '%x64_NATIVE_TOOLS%'
+ - cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
+ build_script:
+ - '%x64_NATIVE_TOOLS%'
+ - cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5
+ check_script:
+ - '%x64_NATIVE_TOOLS%'
+ - ctest --test-dir build -j 5
+ - build\src\RelWithDebInfo\bench_ecmult.exe
+ - build\src\RelWithDebInfo\bench_internal.exe
+ - build\src\RelWithDebInfo\bench.exe
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index d88627d72e..bc7e499de7 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -1,11 +1,12 @@
bench
bench_ecmult
bench_internal
+noverify_tests
tests
exhaustive_tests
precompute_ecmult_gen
precompute_ecmult
-valgrind_ctime_test
+ctime_tests
ecdh_example
ecdsa_example
schnorr_example
@@ -13,9 +14,9 @@ schnorr_example
*.so
*.a
*.csv
-!.gitignore
*.log
*.trs
+*.sage.py
Makefile
configure
@@ -34,8 +35,6 @@ libtool
*.lo
*.o
*~
-*.log
-*.trs
coverage/
coverage.html
@@ -44,8 +43,6 @@ coverage.*.html
*.gcno
*.gcov
-src/libsecp256k1-config.h
-src/libsecp256k1-config.h.in
build-aux/ar-lib
build-aux/config.guess
build-aux/config.sub
@@ -60,5 +57,7 @@ build-aux/m4/ltversion.m4
build-aux/missing
build-aux/compile
build-aux/test-driver
-src/stamp-h1
libsecp256k1.pc
+
+# Default CMake build directory.
+/build
diff --git a/src/secp256k1/CHANGELOG.md b/src/secp256k1/CHANGELOG.md
new file mode 100644
index 0000000000..7f43843641
--- /dev/null
+++ b/src/secp256k1/CHANGELOG.md
@@ -0,0 +1,61 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [0.3.0] - 2023-03-08
+
+#### Added
+ - Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported.
+ - Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory.
+ - Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target.
+
+#### Fixed
+ - Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning.
+
+#### Changed
+ - Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.)
+ - Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization.
+
+#### Removed
+ - Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags).
+
+#### ABI Compatibility
+
+Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions.
+
+## [0.2.0] - 2022-12-12
+
+#### Added
+ - Added usage examples for common use cases in a new `examples/` directory.
+ - Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`.
+ - Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms.
+
+#### Changed
+ - Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`.
+ - The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API.
+
+#### Deprecated
+ - Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead.
+ - Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`.
+ - Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`.
+
+#### ABI Compatibility
+
+Since this is the first release, we do not compare application binary interfaces.
+However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version.
+
+## [0.1.0] - 2013-03-05 to 2021-12-25
+
+This version was in fact never released.
+The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
+Therefore, this version number does not uniquely identify a set of source files.
+
+[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...HEAD
+[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0
+[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0
+[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93
diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt
new file mode 100644
index 0000000000..5c8aad6fcc
--- /dev/null
+++ b/src/secp256k1/CMakeLists.txt
@@ -0,0 +1,302 @@
+cmake_minimum_required(VERSION 3.1)
+
+if(CMAKE_VERSION VERSION_GREATER 3.14)
+ # MSVC runtime library flags are selected by the CMAKE_MSVC_RUNTIME_LIBRARY abstraction.
+ cmake_policy(SET CMP0091 NEW)
+ # MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.
+ cmake_policy(SET CMP0092 NEW)
+endif()
+
+# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
+# the API. All changes in experimental modules are treated as
+# backwards-compatible and therefore at most increase the minor version.
+project(libsecp256k1 VERSION 0.3.0 LANGUAGES C)
+
+# The library version is based on libtool versioning of the ABI. The set of
+# rules for updating the version can be found here:
+# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+# All changes in experimental modules are treated as if they don't affect the
+# interface and therefore only increase the revision.
+set(${PROJECT_NAME}_LIB_VERSION_CURRENT 2)
+set(${PROJECT_NAME}_LIB_VERSION_REVISION 0)
+set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
+
+set(CMAKE_C_STANDARD 90)
+set(CMAKE_C_EXTENSIONS OFF)
+
+list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+
+# We do not use CMake's BUILD_SHARED_LIBS option.
+option(SECP256K1_BUILD_SHARED "Build shared library." ON)
+option(SECP256K1_BUILD_STATIC "Build static library." ON)
+if(NOT SECP256K1_BUILD_SHARED AND NOT SECP256K1_BUILD_STATIC)
+ message(FATAL_ERROR "At least one of SECP256K1_BUILD_SHARED and SECP256K1_BUILD_STATIC must be enabled.")
+endif()
+
+option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
+if(SECP256K1_ENABLE_MODULE_ECDH)
+ add_definitions(-DENABLE_MODULE_ECDH=1)
+endif()
+
+option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
+if(SECP256K1_ENABLE_MODULE_RECOVERY)
+ add_definitions(-DENABLE_MODULE_RECOVERY=1)
+endif()
+
+option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
+option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
+if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
+ set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
+ add_definitions(-DENABLE_MODULE_SCHNORRSIG=1)
+endif()
+if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
+ add_definitions(-DENABLE_MODULE_EXTRAKEYS=1)
+endif()
+
+option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
+if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
+ add_definitions(-DUSE_EXTERNAL_DEFAULT_CALLBACKS=1)
+endif()
+
+set(SECP256K1_ECMULT_WINDOW_SIZE "AUTO" CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. \"AUTO\" is a reasonable setting for desktop machines (currently 15). [default=AUTO]")
+set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS "AUTO" 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)
+include(CheckStringOptionValue)
+check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE)
+if(SECP256K1_ECMULT_WINDOW_SIZE STREQUAL "AUTO")
+ set(SECP256K1_ECMULT_WINDOW_SIZE 15)
+endif()
+add_definitions(-DECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE})
+
+set(SECP256K1_ECMULT_GEN_PREC_BITS "AUTO" CACHE STRING "Precision bits to tune the precomputed table size for signing, specified as integer 2, 4 or 8. \"AUTO\" is a reasonable setting for desktop machines (currently 4). [default=AUTO]")
+set_property(CACHE SECP256K1_ECMULT_GEN_PREC_BITS PROPERTY STRINGS "AUTO" 2 4 8)
+check_string_option_value(SECP256K1_ECMULT_GEN_PREC_BITS)
+if(SECP256K1_ECMULT_GEN_PREC_BITS STREQUAL "AUTO")
+ set(SECP256K1_ECMULT_GEN_PREC_BITS 4)
+endif()
+add_definitions(-DECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS})
+
+set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]")
+set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64")
+check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
+if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
+ string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value)
+ add_definitions(-DUSE_FORCE_WIDEMUL_${widemul_upper_value}=1)
+endif()
+mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
+
+set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm\" (experimental). [default=AUTO]")
+set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm")
+check_string_option_value(SECP256K1_ASM)
+if(SECP256K1_ASM STREQUAL "arm")
+ enable_language(ASM)
+ add_definitions(-DUSE_EXTERNAL_ASM=1)
+elseif(SECP256K1_ASM)
+ include(Check64bitAssembly)
+ check_64bit_assembly()
+ if(HAS_64BIT_ASM)
+ set(SECP256K1_ASM "x86_64")
+ add_definitions(-DUSE_ASM_X86_64=1)
+ elseif(SECP256K1_ASM STREQUAL "AUTO")
+ set(SECP256K1_ASM "OFF")
+ else()
+ message(FATAL_ERROR "x86_64 assembly optimization requested but not available.")
+ endif()
+endif()
+
+option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
+if(NOT SECP256K1_EXPERIMENTAL)
+ if(SECP256K1_ASM STREQUAL "arm")
+ message(FATAL_ERROR "ARM assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
+ endif()
+endif()
+
+set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]")
+set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON")
+check_string_option_value(SECP256K1_VALGRIND)
+if(SECP256K1_VALGRIND)
+ find_package(Valgrind MODULE)
+ if(Valgrind_FOUND)
+ set(SECP256K1_VALGRIND ON)
+ include_directories(${Valgrind_INCLUDE_DIR})
+ add_definitions(-DVALGRIND)
+ elseif(SECP256K1_VALGRIND STREQUAL "AUTO")
+ set(SECP256K1_VALGRIND OFF)
+ else()
+ message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.")
+ endif()
+endif()
+
+option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON)
+option(SECP256K1_BUILD_TESTS "Build tests." ON)
+option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON)
+option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND})
+option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF)
+
+# Redefine configuration flags.
+# We leave assertions on, because they are only used in the examples, and we want them always on there.
+if(MSVC)
+ string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+ string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
+ string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
+else()
+ string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+ string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
+ string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
+ # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.)
+ string(REGEX REPLACE "-O3[ \t\r\n]*" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
+endif()
+
+# Define custom "Coverage" build type.
+set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage -Wno-unused-parameter" CACHE STRING
+ "Flags used by the C compiler during \"Coverage\" builds."
+ FORCE
+)
+set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
+ "Flags used for linking binaries during \"Coverage\" builds."
+ FORCE
+)
+set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
+ "Flags used by the shared libraries linker during \"Coverage\" builds."
+ FORCE
+)
+mark_as_advanced(
+ CMAKE_C_FLAGS_COVERAGE
+ CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+)
+
+if(CMAKE_CONFIGURATION_TYPES)
+ set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage")
+endif()
+
+get_property(cached_cmake_build_type CACHE CMAKE_BUILD_TYPE PROPERTY TYPE)
+if(cached_cmake_build_type)
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
+ STRINGS "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage"
+ )
+endif()
+
+set(default_build_type "RelWithDebInfo")
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+ message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
+ set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
+endif()
+
+include(TryAddCompileOption)
+if(MSVC)
+ try_add_compile_option(/W2)
+ try_add_compile_option(/wd4146)
+else()
+ try_add_compile_option(-pedantic)
+ try_add_compile_option(-Wall)
+ try_add_compile_option(-Wcast-align)
+ try_add_compile_option(-Wcast-align=strict)
+ try_add_compile_option(-Wconditional-uninitialized)
+ try_add_compile_option(-Wextra)
+ try_add_compile_option(-Wnested-externs)
+ try_add_compile_option(-Wno-long-long)
+ try_add_compile_option(-Wno-overlength-strings)
+ try_add_compile_option(-Wno-unused-function)
+ try_add_compile_option(-Wreserved-identifier)
+ try_add_compile_option(-Wshadow)
+ try_add_compile_option(-Wstrict-prototypes)
+ try_add_compile_option(-Wundef)
+endif()
+
+if(CMAKE_VERSION VERSION_GREATER 3.2)
+ # Honor visibility properties for all target types.
+ # See: https://cmake.org/cmake/help/latest/policy/CMP0063.html
+ cmake_policy(SET CMP0063 NEW)
+endif()
+set(CMAKE_C_VISIBILITY_PRESET hidden)
+
+# Ask CTest to create a "check" target (e.g., make check) as alias for the "test" target.
+# CTEST_TEST_TARGET_ALIAS is not documented but supposed to be user-facing.
+# See: https://gitlab.kitware.com/cmake/cmake/-/commit/816c9d1aa1f2b42d40c81a991b68c96eb12b6d2
+set(CTEST_TEST_TARGET_ALIAS check)
+include(CTest)
+# We do not use CTest's BUILD_TESTING because a single toggle for all tests is too coarse for our needs.
+mark_as_advanced(BUILD_TESTING)
+if(SECP256K1_BUILD_BENCHMARK OR SECP256K1_BUILD_TESTS OR SECP256K1_BUILD_EXHAUSTIVE_TESTS OR SECP256K1_BUILD_CTIME_TESTS OR SECP256K1_BUILD_EXAMPLES)
+ enable_testing()
+endif()
+
+add_subdirectory(src)
+if(SECP256K1_BUILD_EXAMPLES)
+ add_subdirectory(examples)
+endif()
+
+message("\n")
+message("secp256k1 configure summary")
+message("===========================")
+message("Build artifacts:")
+message(" shared library ...................... ${SECP256K1_BUILD_SHARED}")
+message(" static library ...................... ${SECP256K1_BUILD_STATIC}")
+message("Optional modules:")
+message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}")
+message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
+message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
+message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
+message("Parameters:")
+message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
+message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
+message("Optional features:")
+message(" assembly optimization ............... ${SECP256K1_ASM}")
+message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}")
+if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
+ message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}")
+endif()
+message("Optional binaries:")
+message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}")
+message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}")
+set(tests_status "${SECP256K1_BUILD_TESTS}")
+if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
+ set(tests_status OFF)
+endif()
+message(" tests ............................... ${tests_status}")
+message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}")
+message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}")
+message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}")
+message("")
+if(CMAKE_CROSSCOMPILING)
+ set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
+else()
+ set(cross_status "FALSE")
+endif()
+message("Cross compiling ....................... ${cross_status}")
+message("Valgrind .............................. ${SECP256K1_VALGRIND}")
+get_directory_property(definitions COMPILE_DEFINITIONS)
+string(REPLACE ";" " " definitions "${definitions}")
+message("Preprocessor defined macros ........... ${definitions}")
+message("C compiler ............................ ${CMAKE_C_COMPILER}")
+message("CFLAGS ................................ ${CMAKE_C_FLAGS}")
+get_directory_property(compile_options COMPILE_OPTIONS)
+string(REPLACE ";" " " compile_options "${compile_options}")
+message("Compile options ....................... " ${compile_options})
+if(DEFINED CMAKE_BUILD_TYPE)
+ message("Build type:")
+ message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}")
+ string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
+ message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}")
+ message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}")
+ message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}")
+else()
+ message("Available configurations .............. ${CMAKE_CONFIGURATION_TYPES}")
+ message("RelWithDebInfo configuration:")
+ message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+ message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
+ message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
+ message("Debug configuration:")
+ message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}")
+ message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
+ message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
+endif()
+message("\n")
+if(SECP256K1_EXPERIMENTAL)
+ message(
+ " ******\n"
+ " WARNING: experimental build\n"
+ " Experimental features do not have stable APIs or properties, and may not be safe for production use.\n"
+ " ******\n"
+ )
+endif()
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index 51c5960301..e3fdf4da27 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -47,7 +47,14 @@ noinst_HEADERS += src/modinv64_impl.h
noinst_HEADERS += src/precomputed_ecmult.h
noinst_HEADERS += src/precomputed_ecmult_gen.h
noinst_HEADERS += src/assumptions.h
+noinst_HEADERS += src/checkmem.h
noinst_HEADERS += src/util.h
+noinst_HEADERS += src/int128.h
+noinst_HEADERS += src/int128_impl.h
+noinst_HEADERS += src/int128_native.h
+noinst_HEADERS += src/int128_native_impl.h
+noinst_HEADERS += src/int128_struct.h
+noinst_HEADERS += src/int128_struct_impl.h
noinst_HEADERS += src/scratch.h
noinst_HEADERS += src/scratch_impl.h
noinst_HEADERS += src/selftest.h
@@ -58,17 +65,18 @@ noinst_HEADERS += src/hash_impl.h
noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
-noinst_HEADERS += src/basic-config.h
noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
-noinst_HEADERS += examples/random.h
+noinst_HEADERS += examples/examples_util.h
PRECOMPUTED_LIB = libsecp256k1_precomputed.la
noinst_LTLIBRARIES = $(PRECOMPUTED_LIB)
libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c
-libsecp256k1_precomputed_la_CPPFLAGS = $(SECP_INCLUDES)
+# We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree.
+# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo).
+libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_CONFIG_DEFINES)
if USE_EXTERNAL_ASM
COMMON_LIB = libsecp256k1_common.la
@@ -87,55 +95,58 @@ endif
endif
libsecp256k1_la_SOURCES = src/secp256k1.c
-libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
-libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
+libsecp256k1_la_CPPFLAGS = $(SECP_CONFIG_DEFINES)
+libsecp256k1_la_LIBADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE)
-if VALGRIND_ENABLED
-libsecp256k1_la_CPPFLAGS += -DVALGRIND
-endif
-
noinst_PROGRAMS =
if USE_BENCHMARK
noinst_PROGRAMS += bench bench_internal bench_ecmult
bench_SOURCES = src/bench.c
-bench_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
+bench_LDADD = libsecp256k1.la
+bench_CPPFLAGS = $(SECP_CONFIG_DEFINES)
bench_internal_SOURCES = src/bench_internal.c
-bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
-bench_internal_CPPFLAGS = $(SECP_INCLUDES)
+bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
+bench_internal_CPPFLAGS = $(SECP_CONFIG_DEFINES)
bench_ecmult_SOURCES = src/bench_ecmult.c
-bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
-bench_ecmult_CPPFLAGS = $(SECP_INCLUDES)
+bench_ecmult_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
+bench_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
endif
TESTS =
if USE_TESTS
+TESTS += noverify_tests
+noinst_PROGRAMS += noverify_tests
+noverify_tests_SOURCES = src/tests.c
+noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
+noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
+noverify_tests_LDFLAGS = -static
+if !ENABLE_COVERAGE
+TESTS += tests
noinst_PROGRAMS += tests
-tests_SOURCES = src/tests.c
-tests_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
-if VALGRIND_ENABLED
-tests_CPPFLAGS += -DVALGRIND
-noinst_PROGRAMS += valgrind_ctime_test
-valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c
-valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
+tests_SOURCES = $(noverify_tests_SOURCES)
+tests_CPPFLAGS = $(noverify_tests_CPPFLAGS) -DVERIFY
+tests_LDADD = $(noverify_tests_LDADD)
+tests_LDFLAGS = $(noverify_tests_LDFLAGS)
endif
-if !ENABLE_COVERAGE
-tests_CPPFLAGS += -DVERIFY
endif
-tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
-tests_LDFLAGS = -static
-TESTS += tests
+
+if USE_CTIME_TESTS
+noinst_PROGRAMS += ctime_tests
+ctime_tests_SOURCES = src/ctime_tests.c
+ctime_tests_LDADD = libsecp256k1.la
+ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
endif
if USE_EXHAUSTIVE_TESTS
noinst_PROGRAMS += exhaustive_tests
exhaustive_tests_SOURCES = src/tests_exhaustive.c
-exhaustive_tests_CPPFLAGS = $(SECP_INCLUDES)
+exhaustive_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
if !ENABLE_COVERAGE
exhaustive_tests_CPPFLAGS += -DVERIFY
endif
# Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables).
-exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+exhaustive_tests_LDADD = $(COMMON_LIB)
exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests
endif
@@ -179,12 +190,12 @@ EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen
CLEANFILES = $(EXTRA_PROGRAMS)
precompute_ecmult_SOURCES = src/precompute_ecmult.c
-precompute_ecmult_CPPFLAGS = $(SECP_INCLUDES)
-precompute_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
+precompute_ecmult_LDADD = $(COMMON_LIB)
precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c
-precompute_ecmult_gen_CPPFLAGS = $(SECP_INCLUDES)
-precompute_ecmult_gen_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES)
+precompute_ecmult_gen_LDADD = $(COMMON_LIB)
# See Automake manual, Section "Errors with distclean".
# We don't list any dependencies for the prebuilt files here because
@@ -211,7 +222,15 @@ maintainer-clean-local: clean-precomp
clean-precomp:
rm -f $(PRECOMP)
-EXTRA_DIST = autogen.sh SECURITY.md
+EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md
+EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md
+EXTRA_DIST += examples/EXAMPLES_COPYING
+EXTRA_DIST += sage/gen_exhaustive_groups.sage
+EXTRA_DIST += sage/gen_split_lambda_constants.sage
+EXTRA_DIST += sage/group_prover.sage
+EXTRA_DIST += sage/prove_group_implementations.sage
+EXTRA_DIST += sage/secp256k1_params.sage
+EXTRA_DIST += sage/weierstrass_prover.sage
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md
index f5db915e83..19dabe8505 100644
--- a/src/secp256k1/README.md
+++ b/src/secp256k1/README.md
@@ -2,6 +2,8 @@ libsecp256k1
============
[![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/secp256k1.svg?branch=master)](https://cirrus-ci.com/github/bitcoin-core/secp256k1)
+![Dependencies: None](https://img.shields.io/badge/dependencies-none-success)
+[![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](https://web.libera.chat/#secp256k1)
Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
@@ -15,6 +17,7 @@ Features:
* Derandomized ECDSA (via RFC6979 or with a caller provided function.)
* Very efficient implementation.
* Suitable for embedded systems.
+* No runtime dependencies.
* Optional module for public key recovery.
* Optional module for ECDH key exchange.
* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
@@ -57,10 +60,8 @@ Implementation details
* Optional runtime blinding which attempts to frustrate differential power analysis.
* The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally.
-Build steps
------------
-
-libsecp256k1 is built using autotools:
+Building with Autotools
+-----------------------
$ ./autogen.sh
$ ./configure
@@ -70,13 +71,51 @@ libsecp256k1 is built using autotools:
To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags.
+Building with CMake (experimental)
+----------------------------------
+
+To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree.
+
+### Building on POSIX systems
+
+ $ mkdir build && cd build
+ $ cmake ..
+ $ make
+ $ make check # run the test suite
+ $ sudo make install # optional
+
+To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags.
+
+### Cross compiling
+
+To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory.
+For example, to cross compile for Windows:
+
+ $ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-w64-mingw32.toolchain.cmake
+
+To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set):
+
+ $ cmake .. -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28
+
+### Building on Windows
+
+To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree.
+
+The following example assumes using of Visual Studio 2022 and CMake v3.21+.
+
+In "Developer Command Prompt for VS 2022":
+
+ >cmake -G "Visual Studio 17 2022" -A x64 -S . -B build
+ >cmake --build build --config RelWithDebInfo
+
Usage examples
-----------
- Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
+Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
* [ECDSA example](examples/ecdsa.c)
* [Schnorr signatures example](examples/schnorr.c)
* [Deriving a shared secret (ECDH) example](examples/ecdh.c)
- To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
+
+To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
Test coverage
-----------
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index 9cb54de098..624f5e956e 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -10,6 +10,7 @@ AC_MSG_RESULT([$has_64bit_asm])
])
AC_DEFUN([SECP_VALGRIND_CHECK],[
+AC_MSG_CHECKING([for valgrind support])
if test x"$has_valgrind" != x"yes"; then
CPPFLAGS_TEMP="$CPPFLAGS"
CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS"
@@ -19,8 +20,9 @@ if test x"$has_valgrind" != x"yes"; then
#if defined(NVALGRIND)
# error "Valgrind does not support this platform."
#endif
- ]])], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed, and it supports the host platform])])
+ ]])], [has_valgrind=yes])
fi
+AC_MSG_RESULT($has_valgrind)
])
dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)
diff --git a/src/secp256k1/ci/cirrus.sh b/src/secp256k1/ci/cirrus.sh
index b85f012d3f..8495c39203 100755
--- a/src/secp256k1/ci/cirrus.sh
+++ b/src/secp256k1/ci/cirrus.sh
@@ -1,14 +1,58 @@
#!/bin/sh
-set -e
-set -x
+set -eux
export LC_ALL=C
+# Print relevant CI environment to allow reproducing the job outside of CI.
+print_environment() {
+ # Turn off -x because it messes up the output
+ set +x
+ # There are many ways to print variable names and their content. This one
+ # does not rely on bash.
+ for var in WERROR_CFLAGS MAKEFLAGS BUILD \
+ ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
+ EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \
+ SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
+ EXAMPLES \
+ HOST WRAPPER_CMD \
+ CC CFLAGS CPPFLAGS AR NM
+ do
+ eval "isset=\${$var+x}"
+ if [ -n "$isset" ]; then
+ eval "val=\${$var}"
+ # shellcheck disable=SC2154
+ printf '%s="%s" ' "$var" "$val"
+ fi
+ done
+ echo "$0"
+ set -x
+}
+print_environment
+
+# Start persistent wineserver if necessary.
+# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously.
+case "$WRAPPER_CMD" in
+ *wine*)
+ # Make sure to shutdown wineserver whenever we exit.
+ trap "wineserver -k || true" EXIT INT HUP
+ # This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards.
+ wineserver -p && wine hh.exe
+ ;;
+esac
+
env >> test_env.log
-$CC -v || true
-valgrind --version || true
+if [ -n "${CC+x}" ]; then
+ # The MSVC compiler "cl" doesn't understand "-v"
+ $CC -v || true
+fi
+if [ "$WITH_VALGRIND" = "yes" ]; then
+ valgrind --version
+fi
+if [ -n "$WRAPPER_CMD" ]; then
+ $WRAPPER_CMD --version
+fi
./autogen.sh
@@ -20,6 +64,7 @@ valgrind --version || true
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--enable-module-schnorrsig="$SCHNORRSIG" \
--enable-examples="$EXAMPLES" \
+ --enable-ctime-tests="$CTIMETESTS" \
--with-valgrind="$WITH_VALGRIND" \
--host="$HOST" $EXTRAFLAGS
@@ -36,14 +81,15 @@ export LOG_COMPILER="$WRAPPER_CMD"
make "$BUILD"
+# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
+EXEC='./libtool --mode=execute'
+if [ -n "$WRAPPER_CMD" ]
+then
+ EXEC="$EXEC $WRAPPER_CMD"
+fi
+
if [ "$BENCH" = "yes" ]
then
- # Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
- EXEC='./libtool --mode=execute'
- if [ -n "$WRAPPER_CMD" ]
- then
- EXEC="$EXEC $WRAPPER_CMD"
- fi
{
$EXEC ./bench_ecmult
$EXEC ./bench_internal
@@ -51,9 +97,13 @@ then
} >> bench.log 2>&1
fi
-if [ "$CTIMETEST" = "yes" ]
+if [ "$CTIMETESTS" = "yes" ]
then
- ./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1
+ if [ "$WITH_VALGRIND" = "yes" ]; then
+ ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1
+ else
+ $EXEC ./ctime_tests > ctime_tests.log 2>&1
+ fi
fi
# Rebuild precomputed files (if not cross-compiling).
diff --git a/src/secp256k1/ci/linux-debian.Dockerfile b/src/secp256k1/ci/linux-debian.Dockerfile
index 5cccbb5565..a83a4e36db 100644
--- a/src/secp256k1/ci/linux-debian.Dockerfile
+++ b/src/secp256k1/ci/linux-debian.Dockerfile
@@ -1,15 +1,14 @@
FROM debian:stable
-RUN dpkg --add-architecture i386
-RUN dpkg --add-architecture s390x
-RUN dpkg --add-architecture armhf
-RUN dpkg --add-architecture arm64
-RUN dpkg --add-architecture ppc64el
-RUN apt-get update
+RUN dpkg --add-architecture i386 && \
+ dpkg --add-architecture s390x && \
+ dpkg --add-architecture armhf && \
+ dpkg --add-architecture arm64 && \
+ dpkg --add-architecture ppc64el
# dkpg-dev: to make pkg-config work in cross-builds
# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces
-RUN apt-get install --no-install-recommends --no-upgrade -y \
+RUN apt-get update && apt-get install --no-install-recommends -y \
git ca-certificates \
make automake libtool pkg-config dpkg-dev valgrind qemu-user \
gcc clang llvm libc6-dbg \
@@ -19,8 +18,20 @@ RUN apt-get install --no-install-recommends --no-upgrade -y \
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
- wine gcc-mingw-w64-x86-64 \
+ gcc-mingw-w64-x86-64-win32 wine64 wine \
+ gcc-mingw-w64-i686-win32 wine32 \
sagemath
-# Run a dummy command in wine to make it set up configuration
-RUN wine64-stable xcopy || true
+WORKDIR /root
+# The "wine" package provides a convience wrapper that we need
+RUN apt-get update && apt-get install --no-install-recommends -y \
+ git ca-certificates wine64 wine python3-simplejson python3-six msitools winbind procps && \
+ git clone https://github.com/mstorsjo/msvc-wine && \
+ mkdir /opt/msvc && \
+ python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \
+ msvc-wine/install.sh /opt/msvc
+
+# Initialize the wine environment. Wait until the wineserver process has
+# exited before closing the session, to avoid corrupting the wine prefix.
+RUN wine64 wineboot --init && \
+ while (ps -A | grep wineserver) > /dev/null; do sleep 1; done
diff --git a/src/secp256k1/cmake/Check64bitAssembly.cmake b/src/secp256k1/cmake/Check64bitAssembly.cmake
new file mode 100644
index 0000000000..3f65887765
--- /dev/null
+++ b/src/secp256k1/cmake/Check64bitAssembly.cmake
@@ -0,0 +1,14 @@
+include(CheckCSourceCompiles)
+
+function(check_64bit_assembly)
+ check_c_source_compiles("
+ #include <stdint.h>
+
+ int main()
+ {
+ uint64_t a = 11, tmp;
+ __asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");
+ }
+ " HAS_64BIT_ASM)
+ set(HAS_64BIT_ASM ${HAS_64BIT_ASM} PARENT_SCOPE)
+endfunction()
diff --git a/src/secp256k1/cmake/CheckStringOptionValue.cmake b/src/secp256k1/cmake/CheckStringOptionValue.cmake
new file mode 100644
index 0000000000..bc4d7b5749
--- /dev/null
+++ b/src/secp256k1/cmake/CheckStringOptionValue.cmake
@@ -0,0 +1,12 @@
+function(check_string_option_value option)
+ get_property(expected_values CACHE ${option} PROPERTY STRINGS)
+ if(expected_values)
+ foreach(value IN LISTS expected_values)
+ if(value STREQUAL "${${option}}")
+ return()
+ endif()
+ endforeach()
+ message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.")
+ endif()
+ message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.")
+endfunction()
diff --git a/src/secp256k1/cmake/FindValgrind.cmake b/src/secp256k1/cmake/FindValgrind.cmake
new file mode 100644
index 0000000000..f6c1f58649
--- /dev/null
+++ b/src/secp256k1/cmake/FindValgrind.cmake
@@ -0,0 +1,41 @@
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ find_program(BREW_COMMAND brew)
+ execute_process(
+ COMMAND ${BREW_COMMAND} --prefix valgrind
+ OUTPUT_VARIABLE valgrind_brew_prefix
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+endif()
+
+set(hints_paths)
+if(valgrind_brew_prefix)
+ set(hints_paths ${valgrind_brew_prefix}/include)
+endif()
+
+find_path(Valgrind_INCLUDE_DIR
+ NAMES valgrind/memcheck.h
+ HINTS ${hints_paths}
+)
+
+if(Valgrind_INCLUDE_DIR)
+ include(CheckCSourceCompiles)
+ set(CMAKE_REQUIRED_INCLUDES ${Valgrind_INCLUDE_DIR})
+ check_c_source_compiles("
+ #include <valgrind/memcheck.h>
+ #if defined(NVALGRIND)
+ # error \"Valgrind does not support this platform.\"
+ #endif
+
+ int main() {}
+ " Valgrind_WORKS)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Valgrind
+ REQUIRED_VARS Valgrind_INCLUDE_DIR Valgrind_WORKS
+)
+
+mark_as_advanced(
+ Valgrind_INCLUDE_DIR
+)
diff --git a/src/secp256k1/cmake/TryAddCompileOption.cmake b/src/secp256k1/cmake/TryAddCompileOption.cmake
new file mode 100644
index 0000000000..f53c252c2d
--- /dev/null
+++ b/src/secp256k1/cmake/TryAddCompileOption.cmake
@@ -0,0 +1,23 @@
+include(CheckCCompilerFlag)
+
+function(try_add_compile_option option)
+ string(MAKE_C_IDENTIFIER ${option} result)
+ string(TOUPPER ${result} result)
+ set(result "C_SUPPORTS${result}")
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+ if(NOT MSVC)
+ set(CMAKE_REQUIRED_FLAGS "-Werror")
+ endif()
+ check_c_compiler_flag(${option} ${result})
+ if(${result})
+ get_property(compile_options
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ PROPERTY COMPILE_OPTIONS
+ )
+ list(APPEND compile_options "${option}")
+ set_property(
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ PROPERTY COMPILE_OPTIONS "${compile_options}"
+ )
+ endif()
+endfunction()
diff --git a/src/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake b/src/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake
new file mode 100644
index 0000000000..0d91912b6d
--- /dev/null
+++ b/src/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake
@@ -0,0 +1,3 @@
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR arm)
+set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
diff --git a/src/secp256k1/cmake/config.cmake.in b/src/secp256k1/cmake/config.cmake.in
new file mode 100644
index 0000000000..46b180ab19
--- /dev/null
+++ b/src/secp256k1/cmake/config.cmake.in
@@ -0,0 +1,5 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
+
+check_required_components(@PROJECT_NAME@)
diff --git a/src/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake b/src/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake
new file mode 100644
index 0000000000..96119b72d1
--- /dev/null
+++ b/src/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake
@@ -0,0 +1,3 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR x86_64)
+set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 2db59a8ff3..a46a0a7be3 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -4,27 +4,24 @@ AC_PREREQ([2.60])
# the API. All changes in experimental modules are treated as
# backwards-compatible and therefore at most increase the minor version.
define(_PKG_VERSION_MAJOR, 0)
-define(_PKG_VERSION_MINOR, 1)
-define(_PKG_VERSION_BUILD, 0)
-define(_PKG_VERSION_IS_RELEASE, false)
+define(_PKG_VERSION_MINOR, 3)
+define(_PKG_VERSION_PATCH, 0)
+define(_PKG_VERSION_IS_RELEASE, true)
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
-define(_LIB_VERSION_CURRENT, 0)
+define(_LIB_VERSION_CURRENT, 2)
define(_LIB_VERSION_REVISION, 0)
define(_LIB_VERSION_AGE, 0)
-AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_BUILD)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-pre]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
+AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
AC_CANONICAL_HOST
-AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
-AH_TOP([#define LIBSECP256K1_CONFIG_H])
-AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
# Require Automake 1.11.2 for AM_PROG_AR
AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
@@ -33,12 +30,14 @@ AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CC
-if test x"$ac_cv_prog_cc_c89" = x"no"; then
- AC_MSG_ERROR([c89 compiler support required])
-fi
AM_PROG_AS
AM_PROG_AR
+# Clear some cache variables as a workaround for a bug that appears due to a bad
+# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe.
+# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421
+AS_UNSET(ac_cv_prog_AR)
+AS_UNSET(ac_cv_prog_ac_ct_AR)
LT_INIT([win32-dll])
build_windows=no
@@ -87,23 +86,42 @@ esac
#
# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues.
AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
- # Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
- # not error out if it gets unknown warning flags and the checks here will always succeed
- # no matter if clang knows the flag or not.
- SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
- SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
-
- SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
- SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
- SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
- SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
- SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
- SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
- SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
- SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
- SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
-
- CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
+ # GCC and compatible (incl. clang)
+ if test "x$GCC" = "xyes"; then
+ # Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
+ # not error out if it gets unknown warning flags and the checks here will always succeed
+ # no matter if clang knows the flag or not.
+ SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
+ SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
+
+ SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
+ SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
+ SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
+ SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
+ SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
+ SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
+ SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
+ SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
+ SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only
+ SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
+
+ CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
+ fi
+
+ # MSVC
+ # Assume MSVC if we're building for Windows but not with GCC or compatible;
+ # libtool makes the same assumption internally.
+ # Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path.
+ if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
+ SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned"
+ SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files
+ # We pass -ignore:4217 to the MSVC linker to suppress warning 4217 when
+ # importing variables from a statically linked secp256k1.
+ # (See the libtool manual, section "Windows DLLs" for background.)
+ # Unfortunately, libtool tries to be too clever and strips "-Xlinker arg"
+ # into "arg", so this will be " -Xlinker -ignore:4217" after stripping.
+ LDFLAGS="-Xlinker -Xlinker -Xlinker -ignore:4217 $LDFLAGS"
+ fi
])
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
@@ -128,6 +146,10 @@ AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [],
[SECP_SET_DEFAULT([enable_tests], [yes], [yes])])
+AC_ARG_ENABLE(ctime_tests,
+ AS_HELP_STRING([--enable-ctime-tests],[compile constant-time tests [default=yes if valgrind enabled]]), [],
+ [SECP_SET_DEFAULT([enable_ctime_tests], [auto], [auto])])
+
AC_ARG_ENABLE(experimental,
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [],
[SECP_SET_DEFAULT([enable_experimental], [no], [yes])])
@@ -141,27 +163,31 @@ AC_ARG_ENABLE(examples,
[SECP_SET_DEFAULT([enable_examples], [no], [yes])])
AC_ARG_ENABLE(module_ecdh,
- AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [],
- [SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])])
+ AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [],
+ [SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])])
AC_ARG_ENABLE(module_recovery,
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])])
AC_ARG_ENABLE(module_extrakeys,
- AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=no]]), [],
- [SECP_SET_DEFAULT([enable_module_extrakeys], [no], [yes])])
+ AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [],
+ [SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])])
AC_ARG_ENABLE(module_schnorrsig,
- AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [],
- [SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])])
+ AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
+ [SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
# Test-only override of the (autodetected by the C code) "widemul" setting.
-# Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
+# Legal values are:
+# * int64 (for [u]int64_t),
+# * int128 (for [unsigned] __int128),
+# * int128_struct (for int128 implemented as a structure),
+# * and auto (the default).
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
@@ -207,10 +233,13 @@ else
enable_valgrind=yes
fi
fi
-AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
+
+if test x"$enable_ctime_tests" = x"auto"; then
+ enable_ctime_tests=$enable_valgrind
+fi
if test x"$enable_coverage" = x"yes"; then
- AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1"
SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS"
LDFLAGS="--coverage $LDFLAGS"
else
@@ -252,7 +281,7 @@ enable_external_asm=no
case $set_asm in
x86_64)
- AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1"
;;
arm)
enable_external_asm=yes
@@ -265,17 +294,20 @@ no)
esac
if test x"$enable_external_asm" = x"yes"; then
- AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_ASM=1"
fi
# Select wide multiplication implementation
case $set_widemul in
+int128_struct)
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128_STRUCT=1"
+ ;;
int128)
- AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128=1"
;;
int64)
- AC_DEFINE(USE_FORCE_WIDEMUL_INT64, 1, [Define this symbol to force the use of the (u)int64_t based wide multiplication implementation])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT64=1"
;;
auto)
;;
@@ -302,7 +334,7 @@ case $set_ecmult_window in
# not in range
AC_MSG_ERROR($error_window_size)
fi
- AC_DEFINE_UNQUOTED(ECMULT_WINDOW_SIZE, $set_ecmult_window, [Set window size for ecmult precomputation])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_WINDOW_SIZE=$set_ecmult_window"
;;
esac
@@ -315,7 +347,7 @@ fi
case $set_ecmult_gen_precision in
2|4|8)
- AC_DEFINE_UNQUOTED(ECMULT_GEN_PREC_BITS, $set_ecmult_gen_precision, [Set ecmult gen precision bits])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_GEN_PREC_BITS=$set_ecmult_gen_precision"
;;
*)
AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"'])
@@ -323,10 +355,12 @@ case $set_ecmult_gen_precision in
esac
if test x"$enable_valgrind" = x"yes"; then
- SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS"
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES $VALGRIND_CPPFLAGS -DVALGRIND"
fi
-# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI)
+# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI).
+# We don't want to set the user variable CFLAGS in CI because this would disable
+# autoconf's logic for setting default CFLAGS, which we would like to test in CI.
SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
###
@@ -334,26 +368,26 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
###
if test x"$enable_module_ecdh" = x"yes"; then
- AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
fi
if test x"$enable_module_recovery" = x"yes"; then
- AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1"
fi
if test x"$enable_module_schnorrsig" = x"yes"; then
- AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1"
enable_module_extrakeys=yes
fi
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
# module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then
- AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1"
fi
if test x"$enable_external_default_callbacks" = x"yes"; then
- AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1"
fi
###
@@ -375,15 +409,12 @@ fi
### Generate output
###
-AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
-AC_SUBST(SECP_INCLUDES)
-AC_SUBST(SECP_LIBS)
-AC_SUBST(SECP_TEST_LIBS)
-AC_SUBST(SECP_TEST_INCLUDES)
AC_SUBST(SECP_CFLAGS)
+AC_SUBST(SECP_CONFIG_DEFINES)
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
+AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
@@ -405,6 +436,7 @@ echo "Build Options:"
echo " with external callbacks = $enable_external_default_callbacks"
echo " with benchmarks = $enable_benchmark"
echo " with tests = $enable_tests"
+echo " with ctime tests = $enable_ctime_tests"
echo " with coverage = $enable_coverage"
echo " with examples = $enable_examples"
echo " module ecdh = $enable_module_ecdh"
diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
index 1a8ad8ae0c..3749e418fe 100644
--- a/src/secp256k1/contrib/lax_der_privatekey_parsing.h
+++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
@@ -43,8 +43,7 @@ extern "C" {
/** Export a private key in DER format.
*
* Returns: 1 if the private key was valid.
- * Args: ctx: pointer to a context object, initialized for signing (cannot
- * be NULL)
+ * Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: privkey: pointer to an array for storing the private key in BER.
* Should have space for 279 bytes, and cannot be NULL.
* privkeylen: Pointer to an int where the length of the private key in
diff --git a/src/secp256k1/doc/CHANGELOG.md b/src/secp256k1/doc/CHANGELOG.md
deleted file mode 100644
index 3c4c2e4583..0000000000
--- a/src/secp256k1/doc/CHANGELOG.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Changelog
-
-This file is currently only a template for future use.
-
-Each change falls into one of the following categories: Added, Changed, Deprecated, Removed, Fixed or Security.
-
-## [Unreleased]
-
-## [MAJOR.MINOR.PATCH] - YYYY-MM-DD
-
-### Added/Changed/Deprecated/Removed/Fixed/Security
-- [Title with link to Pull Request](https://link-to-pr)
diff --git a/src/secp256k1/doc/release-process.md b/src/secp256k1/doc/release-process.md
index a35b8a9db3..b522f89657 100644
--- a/src/secp256k1/doc/release-process.md
+++ b/src/secp256k1/doc/release-process.md
@@ -1,14 +1,52 @@
# Release Process
-1. Open PR to master that
- 1. adds release notes to `doc/CHANGELOG.md` and
- 2. if this is **not** a patch release, updates `_PKG_VERSION_{MAJOR,MINOR}` and `_LIB_VERSIONS_*` in `configure.ac`
-2. After the PR is merged,
- * if this is **not** a patch release, create a release branch with name `MAJOR.MINOR`.
- Make sure that the branch contains the right commits.
- Create commit on the release branch that sets `_PKG_VERSION_IS_RELEASE` in `configure.ac` to `true`.
- * if this **is** a patch release, open a pull request with the bugfixes to the `MAJOR.MINOR` branch.
- Also include the release note commit bump `_PKG_VERSION_BUILD` and `_LIB_VERSIONS_*` in `configure.ac`.
-4. Tag the commit with `git tag -s vMAJOR.MINOR.PATCH`.
-5. Push branch and tag with `git push origin --tags`.
-6. Create a new GitHub release with a link to the corresponding entry in `doc/CHANGELOG.md`.
+This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`.
+
+We distinguish between two types of releases: *regular* and *maintenance* releases.
+Regular releases are releases of a new major or minor version as well as patches of the most recent release.
+Maintenance releases, on the other hand, are required for patches of older releases.
+
+You should coordinate with the other maintainers on the release date, if possible.
+This date will be part of the release entry in [CHANGELOG.md](../CHANGELOG.md) and it should match the dates of the remaining steps in the release process (including the date of the tag and the GitHub release).
+It is best if the maintainers are present during the release, so they can help ensure that the process is followed correctly and, in the case of a regular release, they are aware that they should not modify the master branch between merging the PR in step 1 and the PR in step 3.
+
+This process also assumes that there will be no minor releases for old major releases.
+
+## Regular release
+
+1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that
+ * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) (make sure to include an entry for `### ABI Compatibility`) and
+ * updates `_PKG_VERSION_*`, `_LIB_VERSION_*`, and sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`.
+2. After the PR is merged, tag the commit and push it:
+ ```
+ RELEASE_COMMIT=<merge commit of step 1>
+ git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT
+ git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
+ ```
+3. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that sets `_PKG_VERSION_IS_RELEASE` to `false` and `_PKG_VERSION_PATCH` to `$PATCH + 1` and increases `_LIB_VERSION_REVISION`. If other maintainers are not present to approve the PR, it can be merged without ACKs.
+4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
+
+## Maintenance release
+
+Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists.
+
+1. If `$PATCH = 1`, create maintenance branch `$MAJOR.$MINOR`:
+ ```
+ git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.0
+ git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
+ ```
+2. Open a pull request to the `$MAJOR.$MINOR` branch that
+ * includes the bugfixes,
+ * finalizes the release notes,
+ * bumps `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` (with commit message `"release: update PKG_ and LIB_VERSION for $MAJOR.$MINOR.$PATCH"`, for example).
+3. After the PRs are merged, update the release branch and tag the commit:
+ ```
+ git checkout $MAJOR.$MINOR && git pull
+ git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH"
+ ```
+4. Push tag:
+ ```
+ git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
+ ```
+5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
+6. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md).
diff --git a/src/secp256k1/doc/safegcd_implementation.md b/src/secp256k1/doc/safegcd_implementation.md
index 063aa8efae..5dbbb7bbd2 100644
--- a/src/secp256k1/doc/safegcd_implementation.md
+++ b/src/secp256k1/doc/safegcd_implementation.md
@@ -1,7 +1,7 @@
# The safegcd implementation in libsecp256k1 explained
-This document explains the modular inverse implementation in the `src/modinv*.h` files. It is based
-on the paper
+This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files.
+It is based on the paper
["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd)
by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version.
@@ -410,7 +410,7 @@ sufficient even. Given that every loop iteration performs *N* divsteps, it will
To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise
operations (and hope the C compiler isn't smart enough to turn them back into branches; see
-`valgrind_ctime_test.c` for automated tests that this isn't the case). To do so, observe that a
+`ctime_tests.c` for automated tests that this isn't the case). To do so, observe that a
divstep can be written instead as (compare to the inner loop of `gcd` in section 1).
```python
@@ -769,3 +769,51 @@ def modinv_var(M, Mi, x):
d, e = update_de(d, e, t, M, Mi)
return normalize(f, d, Mi)
```
+
+## 8. From GCDs to Jacobi symbol
+
+We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an
+extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we
+make corresponding updates to *j* using
+[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties):
+* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*).
+* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*).
+
+These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied
+very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this
+calculation is slightly simpler than the one for the modular inverse because we no longer need to
+keep track of *d* and *e*.
+
+However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for
+positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative
+values. We resolve this by using the following modified steps:
+
+```python
+ # Before
+ if delta > 0 and g & 1:
+ delta, f, g = 1 - delta, g, (g - f) // 2
+
+ # After
+ if delta > 0 and g & 1:
+ delta, f, g = 1 - delta, g, (g + f) // 2
+```
+
+The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4
+and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm
+will converge. The justification for posdivsteps is completely empirical: in practice, it appears
+that the vast majority of nonzero inputs converge to *f=g=gcd(f<sub>0</sub>, g<sub>0</sub>)* in a
+number of steps proportional to their logarithm.
+
+Note that:
+- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached.
+- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect.
+- We need to update the termination condition from *g=0* to *f=1*.
+
+We account for the possibility of nonconvergence by only performing a bounded number of
+posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not
+yet been found.
+
+The optimizations in sections 3-7 above are described in the context of the original divsteps, but
+in the C implementation we also adapt most of them (not including "avoiding modulus operations",
+since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate
+Jacobi symbols for secret data) to the posdivsteps version.
diff --git a/src/secp256k1/examples/CMakeLists.txt b/src/secp256k1/examples/CMakeLists.txt
new file mode 100644
index 0000000000..0884b645e0
--- /dev/null
+++ b/src/secp256k1/examples/CMakeLists.txt
@@ -0,0 +1,34 @@
+add_library(example INTERFACE)
+target_include_directories(example INTERFACE
+ ${PROJECT_SOURCE_DIR}/include
+)
+target_compile_options(example INTERFACE
+ $<$<C_COMPILER_ID:MSVC>:/wd4005>
+)
+target_link_libraries(example INTERFACE
+ $<$<PLATFORM_ID:Windows>:bcrypt>
+)
+if(SECP256K1_BUILD_SHARED)
+ target_link_libraries(example INTERFACE secp256k1)
+elseif(SECP256K1_BUILD_STATIC)
+ target_link_libraries(example INTERFACE secp256k1_static)
+ if(MSVC)
+ target_link_options(example INTERFACE /IGNORE:4217)
+ endif()
+endif()
+
+add_executable(ecdsa_example ecdsa.c)
+target_link_libraries(ecdsa_example example)
+add_test(ecdsa_example ecdsa_example)
+
+if(SECP256K1_ENABLE_MODULE_ECDH)
+ add_executable(ecdh_example ecdh.c)
+ target_link_libraries(ecdh_example example)
+ add_test(ecdh_example ecdh_example)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
+ add_executable(schnorr_example schnorr.c)
+ target_link_libraries(schnorr_example example)
+ add_test(schnorr_example schnorr_example)
+endif()
diff --git a/src/secp256k1/examples/ecdh.c b/src/secp256k1/examples/ecdh.c
index d7e8add361..4b7b7d6154 100644
--- a/src/secp256k1/examples/ecdh.c
+++ b/src/secp256k1/examples/ecdh.c
@@ -14,8 +14,7 @@
#include <secp256k1.h>
#include <secp256k1_ecdh.h>
-#include "random.h"
-
+#include "examples_util.h"
int main(void) {
unsigned char seckey1[32];
@@ -30,12 +29,8 @@ int main(void) {
secp256k1_pubkey pubkey1;
secp256k1_pubkey pubkey2;
- /* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create`
- * needs a context object initialized for signing, which is why we create
- * a context with the SECP256K1_CONTEXT_SIGN flag.
- * (The docs for `secp256k1_ecdh` don't require any special context, just
- * some initialized context) */
- secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ /* Before we can call actual API functions, we need to create a "context". */
+ secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
@@ -116,12 +111,12 @@ int main(void) {
* example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
- * TODO: Prevent these writes from being optimized out, as any good compiler
+ * Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
- memset(seckey1, 0, sizeof(seckey1));
- memset(seckey2, 0, sizeof(seckey2));
- memset(shared_secret1, 0, sizeof(shared_secret1));
- memset(shared_secret2, 0, sizeof(shared_secret2));
+ secure_erase(seckey1, sizeof(seckey1));
+ secure_erase(seckey2, sizeof(seckey2));
+ secure_erase(shared_secret1, sizeof(shared_secret1));
+ secure_erase(shared_secret2, sizeof(shared_secret2));
return 0;
}
diff --git a/src/secp256k1/examples/ecdsa.c b/src/secp256k1/examples/ecdsa.c
index 434c856ba0..d1d2b0e365 100644
--- a/src/secp256k1/examples/ecdsa.c
+++ b/src/secp256k1/examples/ecdsa.c
@@ -13,9 +13,7 @@
#include <secp256k1.h>
-#include "random.h"
-
-
+#include "examples_util.h"
int main(void) {
/* Instead of signing the message directly, we must sign a 32-byte hash.
@@ -34,16 +32,12 @@ int main(void) {
unsigned char compressed_pubkey[33];
unsigned char serialized_signature[64];
size_t len;
- int is_signature_valid;
+ int is_signature_valid, is_signature_valid2;
int return_val;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
- /* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create` needs
- * a context object initialized for signing and `secp256k1_ecdsa_verify` needs
- * a context initialized for verification, which is why we create a context
- * for both signing and verification with the SECP256K1_CONTEXT_SIGN and
- * SECP256K1_CONTEXT_VERIFY flags. */
- secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ /* Before we can call actual API functions, we need to create a "context". */
+ secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
@@ -120,18 +114,26 @@ int main(void) {
printf("Signature: ");
print_hex(serialized_signature, sizeof(serialized_signature));
-
/* This will clear everything from the context and free the memory */
secp256k1_context_destroy(ctx);
+ /* Bonus example: if all we need is signature verification (and no key
+ generation or signing), we don't need to use a context created via
+ secp256k1_context_create(). We can simply use the static (i.e., global)
+ context secp256k1_context_static. See its description in
+ include/secp256k1.h for details. */
+ is_signature_valid2 = secp256k1_ecdsa_verify(secp256k1_context_static,
+ &sig, msg_hash, &pubkey);
+ assert(is_signature_valid2 == is_signature_valid);
+
/* It's best practice to try to clear secrets from memory after using them.
* This is done because some bugs can allow an attacker to leak memory, for
* example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
- * TODO: Prevent these writes from being optimized out, as any good compiler
+ * Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
- memset(seckey, 0, sizeof(seckey));
+ secure_erase(seckey, sizeof(seckey));
return 0;
}
diff --git a/src/secp256k1/examples/random.h b/src/secp256k1/examples/examples_util.h
index 439226f09f..a52b1fa115 100644
--- a/src/secp256k1/examples/random.h
+++ b/src/secp256k1/examples/examples_util.h
@@ -71,3 +71,32 @@ static void print_hex(unsigned char* data, size_t size) {
}
printf("\n");
}
+
+#if defined(_MSC_VER)
+// For SecureZeroMemory
+#include <Windows.h>
+#endif
+/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
+static SECP256K1_INLINE void secure_erase(void *ptr, size_t len) {
+#if defined(_MSC_VER)
+ /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
+ SecureZeroMemory(ptr, len);
+#elif defined(__GNUC__)
+ /* We use a memory barrier that scares the compiler away from optimizing out the memset.
+ *
+ * Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
+ * in BoringSSL (ISC License):
+ * As best as we can tell, this is sufficient to break any optimisations that
+ * might try to eliminate "superfluous" memsets.
+ * This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is
+ * pretty efficient, because the compiler can still implement the memset() efficently,
+ * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
+ * Yang et al. (USENIX Security 2017) for more background.
+ */
+ memset(ptr, 0, len);
+ __asm__ __volatile__("" : : "r"(ptr) : "memory");
+#else
+ void *(*volatile const volatile_memset)(void *, int, size_t) = memset;
+ volatile_memset(ptr, 0, len);
+#endif
+}
diff --git a/src/secp256k1/examples/schnorr.c b/src/secp256k1/examples/schnorr.c
index 82eb07d5d7..4c0dd1c1a9 100644
--- a/src/secp256k1/examples/schnorr.c
+++ b/src/secp256k1/examples/schnorr.c
@@ -15,7 +15,7 @@
#include <secp256k1_extrakeys.h>
#include <secp256k1_schnorrsig.h>
-#include "random.h"
+#include "examples_util.h"
int main(void) {
unsigned char msg[12] = "Hello World!";
@@ -26,16 +26,12 @@ int main(void) {
unsigned char auxiliary_rand[32];
unsigned char serialized_pubkey[32];
unsigned char signature[64];
- int is_signature_valid;
+ int is_signature_valid, is_signature_valid2;
int return_val;
secp256k1_xonly_pubkey pubkey;
secp256k1_keypair keypair;
- /* The specification in secp256k1_extrakeys.h states that `secp256k1_keypair_create`
- * needs a context object initialized for signing. And in secp256k1_schnorrsig.h
- * they state that `secp256k1_schnorrsig_verify` needs a context initialized for
- * verification, which is why we create a context for both signing and verification
- * with the SECP256K1_CONTEXT_SIGN and SECP256K1_CONTEXT_VERIFY flags. */
- secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ /* Before we can call actual API functions, we need to create a "context". */
+ secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
@@ -139,14 +135,22 @@ int main(void) {
/* This will clear everything from the context and free the memory */
secp256k1_context_destroy(ctx);
+ /* Bonus example: if all we need is signature verification (and no key
+ generation or signing), we don't need to use a context created via
+ secp256k1_context_create(). We can simply use the static (i.e., global)
+ context secp256k1_context_static. See its description in
+ include/secp256k1.h for details. */
+ is_signature_valid2 = secp256k1_schnorrsig_verify(secp256k1_context_static,
+ signature, msg_hash, 32, &pubkey);
+ assert(is_signature_valid2 == is_signature_valid);
+
/* It's best practice to try to clear secrets from memory after using them.
* This is done because some bugs can allow an attacker to leak memory, for
* example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
- * TODO: Prevent these writes from being optimized out, as any good compiler
+ * Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
- memset(seckey, 0, sizeof(seckey));
-
+ secure_erase(seckey, sizeof(seckey));
return 0;
}
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index dddab346ae..325f35eb04 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -7,7 +7,7 @@ extern "C" {
#include <stddef.h>
-/* Unless explicitly stated all pointer arguments must not be NULL.
+/** Unless explicitly stated all pointer arguments must not be NULL.
*
* The following rules specify the order of arguments in API calls:
*
@@ -24,15 +24,19 @@ extern "C" {
* 5. Opaque data pointers follow the function pointer they are to be passed to.
*/
-/** Opaque data structure that holds context information (precomputed tables etc.).
+/** Opaque data structure that holds context information
*
- * The purpose of context structures is to cache large precomputed data tables
- * that are expensive to construct, and also to maintain the randomization data
- * for blinding.
+ * The primary purpose of context objects is to store randomization data for
+ * enhanced protection against side-channel leakage. This protection is only
+ * effective if the context is randomized after its creation. See
+ * secp256k1_context_create for creation of contexts and
+ * secp256k1_context_randomize for randomization.
*
- * Do not create a new context object for each operation, as construction is
- * far slower than all other API calls (~100 times slower than an ECDSA
- * verification).
+ * A secondary purpose of context objects is to store pointers to callback
+ * functions that the library will call when certain error states arise. See
+ * secp256k1_context_set_error_callback as well as
+ * secp256k1_context_set_illegal_callback for details. Future library versions
+ * may use context objects for additional purposes.
*
* A constructed context can safely be used from multiple threads
* simultaneously, but API calls that take a non-const pointer to a context
@@ -45,7 +49,7 @@ extern "C" {
*/
typedef struct secp256k1_context_struct secp256k1_context;
-/** Opaque data structure that holds rewriteable "scratch space"
+/** Opaque data structure that holds rewritable "scratch space"
*
* The purpose of this structure is to replace dynamic memory allocations,
* because we target architectures where this may not be available. It is
@@ -130,7 +134,7 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_INLINE inline
# endif
-/** When this header is used at build-time the SECP256K1_BUILD define needs to be set
+/* When this header is used at build-time the SECP256K1_BUILD define needs to be set
* to correctly setup export attributes and nullness checks. This is normally done
* by secp256k1.c but to guard against this header being included before secp256k1.c
* has had a chance to set the define (e.g. via test harnesses that just includes
@@ -141,27 +145,34 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_NO_BUILD
#endif
-/** At secp256k1 build-time DLL_EXPORT is defined when building objects destined
- * for a shared library, but not for those intended for static libraries.
- */
-
-#ifndef SECP256K1_API
-# if defined(_WIN32)
-# if defined(SECP256K1_BUILD) && defined(DLL_EXPORT)
-# define SECP256K1_API __declspec(dllexport)
-# else
-# define SECP256K1_API
+/* Symbol visibility. See libtool manual, section "Windows DLLs". */
+#if defined(_WIN32) && !defined(__GNUC__)
+# ifdef SECP256K1_BUILD
+# ifdef DLL_EXPORT
+# define SECP256K1_API __declspec (dllexport)
+# define SECP256K1_API_VAR extern __declspec (dllexport)
# endif
-# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
-# define SECP256K1_API __attribute__ ((visibility ("default")))
+# elif defined _MSC_VER
+# define SECP256K1_API
+# define SECP256K1_API_VAR extern __declspec (dllimport)
+# elif defined DLL_EXPORT
+# define SECP256K1_API __declspec (dllimport)
+# define SECP256K1_API_VAR extern __declspec (dllimport)
+# endif
+#endif
+#ifndef SECP256K1_API
+# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
+# define SECP256K1_API __attribute__ ((visibility ("default")))
+# define SECP256K1_API_VAR extern __attribute__ ((visibility ("default")))
# else
# define SECP256K1_API
+# define SECP256K1_API_VAR extern
# endif
#endif
-/**Warning attributes
- * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
- * some paranoid null checks. */
+/* Warning attributes
+ * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
+ * some paranoid null checks. */
# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
# else
@@ -173,7 +184,7 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_ARG_NONNULL(_x)
# endif
-/** Attribute for marking functions, types, and variables as deprecated */
+/* Attribute for marking functions, types, and variables as deprecated */
#if !defined(SECP256K1_BUILD) && defined(__has_attribute)
# if __has_attribute(__deprecated__)
# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg)))
@@ -184,22 +195,26 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_DEPRECATED(_msg)
#endif
-/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
+/* All flags' lower 8 bits indicate what they're for. Do not use directly. */
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1)
-/** The higher bits contain the actual data. Do not use directly. */
+/* The higher bits contain the actual data. Do not use directly. */
#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10)
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
-/** Flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
+/** Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
* secp256k1_context_preallocated_create. */
+#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
+
+/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */
#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
+
+/* Testing flag. Do not use. */
#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY)
-#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
/** Flag to pass to secp256k1_ec_pubkey_serialize. */
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
@@ -212,23 +227,66 @@ typedef int (*secp256k1_nonce_function)(
#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
-/** A simple secp256k1 context object with no precomputed tables. These are useful for
- * type serialization/parsing functions which require a context object to maintain
- * API consistency, but currently do not require expensive precomputations or dynamic
- * allocations.
+/** A built-in constant secp256k1 context object with static storage duration, to be
+ * used in conjunction with secp256k1_selftest.
+ *
+ * This context object offers *only limited functionality* , i.e., it cannot be used
+ * for API functions that perform computations involving secret keys, e.g., signing
+ * and public key generation. If this restriction applies to a specific API function,
+ * it is mentioned in its documentation. See secp256k1_context_create if you need a
+ * full context object that supports all functionality offered by the library.
+ *
+ * It is highly recommended to call secp256k1_selftest before using this context.
+ */
+SECP256K1_API_VAR const secp256k1_context *secp256k1_context_static;
+
+/** Deprecated alias for secp256k1_context_static. */
+SECP256K1_API_VAR const secp256k1_context *secp256k1_context_no_precomp
+SECP256K1_DEPRECATED("Use secp256k1_context_static instead");
+
+/** Perform basic self tests (to be used in conjunction with secp256k1_context_static)
+ *
+ * This function performs self tests that detect some serious usage errors and
+ * similar conditions, e.g., when the library is compiled for the wrong endianness.
+ * This is a last resort measure to be used in production. The performed tests are
+ * very rudimentary and are not intended as a replacement for running the test
+ * binaries.
+ *
+ * It is highly recommended to call this before using secp256k1_context_static.
+ * It is not necessary to call this function before using a context created with
+ * secp256k1_context_create (or secp256k1_context_preallocated_create), which will
+ * take care of performing the self tests.
+ *
+ * If the tests fail, this function will call the default error handler to abort the
+ * program (see secp256k1_context_set_error_callback).
*/
-SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
+SECP256K1_API void secp256k1_selftest(void);
+
/** Create a secp256k1 context object (in dynamically allocated memory).
*
* This function uses malloc to allocate memory. It is guaranteed that malloc is
* called at most once for every call of this function. If you need to avoid dynamic
- * memory allocation entirely, see the functions in secp256k1_preallocated.h.
+ * memory allocation entirely, see secp256k1_context_static and the functions in
+ * secp256k1_preallocated.h.
*
* Returns: a newly created context object.
- * In: flags: which parts of the context to initialize.
+ * In: flags: Always set to SECP256K1_CONTEXT_NONE (see below).
+ *
+ * The only valid non-deprecated flag in recent library versions is
+ * SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality
+ * offered by the library. All other (deprecated) flags will be treated as equivalent
+ * to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for
+ * historical reasons, future versions of the library may introduce new flags.
+ *
+ * If the context is intended to be used for API functions that perform computations
+ * involving secret keys, e.g., signing and public key generation, then it is highly
+ * recommended to call secp256k1_context_randomize on the context before calling
+ * those API functions. This will provide enhanced protection against side-channel
+ * leakage, see secp256k1_context_randomize for details.
*
- * See also secp256k1_context_randomize.
+ * Do not create a new context object for each operation, as construction and
+ * randomization can take non-negligible time.
*/
SECP256K1_API secp256k1_context* secp256k1_context_create(
unsigned int flags
@@ -240,8 +298,11 @@ SECP256K1_API secp256k1_context* secp256k1_context_create(
* called at most once for every call of this function. If you need to avoid dynamic
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
*
+ * Cloning secp256k1_context_static is not possible, and should not be emulated by
+ * the caller (e.g., using memcpy). Create a new context instead.
+ *
* Returns: a newly created context object.
- * Args: ctx: an existing context to copy
+ * Args: ctx: an existing context to copy (not secp256k1_context_static)
*/
SECP256K1_API secp256k1_context* secp256k1_context_clone(
const secp256k1_context* ctx
@@ -259,6 +320,7 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone(
*
* Args: ctx: an existing context to destroy, constructed using
* secp256k1_context_create or secp256k1_context_clone
+ * (i.e., not secp256k1_context_static).
*/
SECP256K1_API void secp256k1_context_destroy(
secp256k1_context* ctx
@@ -308,7 +370,10 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
) SECP256K1_ARG_NONNULL(1);
/** Set a callback function to be called when an internal consistency check
- * fails. The default is crashing.
+ * fails.
+ *
+ * The default callback writes an error message to stderr and calls abort
+ * to abort the program.
*
* This can only trigger in case of a hardware failure, miscompilation,
* memory corruption, serious bug in the library, or other error would can
@@ -426,8 +491,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
* encoding is invalid. R and S with value 0 are allowed in the encoding.
*
* After the call, sig will always be initialized. If parsing failed or R or
- * S are zero, the resulting sig value is guaranteed to fail validation for any
- * message and public key.
+ * S are zero, the resulting sig value is guaranteed to fail verification for
+ * any message and public key.
*/
SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
const secp256k1_context* ctx,
@@ -447,7 +512,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
* encoded numbers are out of range.
*
* After the call, sig will always be initialized. If parsing failed or the
- * encoded numbers are out of range, signature validation with it is
+ * encoded numbers are out of range, signature verification with it is
* guaranteed to fail for every message and public key.
*/
SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
@@ -494,7 +559,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
*
* Returns: 1: correct signature
* 0: incorrect or unparseable signature
- * Args: ctx: a secp256k1 context object, initialized for verification.
+ * Args: ctx: a secp256k1 context object.
* In: sig: the signature being verified.
* msghash32: the 32-byte message hash being verified.
* The verifier must make sure to apply a cryptographic
@@ -511,7 +576,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
*
* If you need to accept ECDSA signatures from sources that do not obey this
* rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to
- * validation, but be aware that doing so results in malleable signatures.
+ * verification, but be aware that doing so results in malleable signatures.
*
* For details, see the comments for that function.
*/
@@ -573,16 +638,16 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize(
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
* extra entropy.
*/
-SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
+SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
-SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default;
+SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_default;
/** Create an ECDSA signature.
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
- * Args: ctx: pointer to a context object, initialized for signing.
+ * Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig: pointer to an array where the signature will be placed.
* In: msghash32: the 32-byte message hash being signed.
* seckey: pointer to a 32-byte secret key.
@@ -626,7 +691,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
*
* Returns: 1: secret was valid, public key stores.
* 0: secret was invalid, try again.
- * Args: ctx: pointer to a context object, initialized for signing.
+ * Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: pubkey: pointer to the created public key.
* In: seckey: pointer to a 32-byte secret key.
*/
@@ -705,7 +770,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
* Returns: 0 if the arguments are invalid or the resulting public key would be
* invalid (only when the tweak is the negation of the corresponding
* secret key). 1 otherwise.
- * Args: ctx: pointer to a context object initialized for validation.
+ * Args: ctx: pointer to a context object.
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
@@ -750,7 +815,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
/** Tweak a public key by multiplying it by a tweak value.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
- * Args: ctx: pointer to a context object initialized for validation.
+ * Args: ctx: pointer to a context object.
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
@@ -764,30 +829,37 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Updates the context randomization to protect against side-channel leakage.
- * Returns: 1: randomization successfully updated or nothing to randomize
+/** Randomizes the context to provide enhanced protection against side-channel leakage.
+ *
+ * Returns: 1: randomization successful
* 0: error
- * Args: ctx: pointer to a context object.
- * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
+ * Args: ctx: pointer to a context object (not secp256k1_context_static).
+ * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state).
*
- * While secp256k1 code is written to be constant-time no matter what secret
- * values are, it's possible that a future compiler may output code which isn't,
+ * While secp256k1 code is written and tested to be constant-time no matter what
+ * secret values are, it is possible that a compiler may output code which is not,
* and also that the CPU may not emit the same radio frequencies or draw the same
- * amount power for all values.
- *
- * This function provides a seed which is combined into the blinding value: that
- * blinding value is added before each multiplication (and removed afterwards) so
- * that it does not affect function results, but shields against attacks which
- * rely on any input-dependent behaviour.
- *
- * This function has currently an effect only on contexts initialized for signing
- * because randomization is currently used only for signing. However, this is not
- * guaranteed and may change in the future. It is safe to call this function on
- * contexts not initialized for signing; then it will have no effect and return 1.
- *
- * You should call this after secp256k1_context_create or
- * secp256k1_context_clone (and secp256k1_context_preallocated_create or
- * secp256k1_context_clone, resp.), and you may call this repeatedly afterwards.
+ * amount of power for all values. Randomization of the context shields against
+ * side-channel observations which aim to exploit secret-dependent behaviour in
+ * certain computations which involve secret keys.
+ *
+ * It is highly recommended to call this function on contexts returned from
+ * secp256k1_context_create or secp256k1_context_clone (or from the corresponding
+ * functions in secp256k1_preallocated.h) before using these contexts to call API
+ * functions that perform computations involving secret keys, e.g., signing and
+ * public key generation. It is possible to call this function more than once on
+ * the same context, and doing so before every few computations involving secret
+ * keys is recommended as a defense-in-depth measure. Randomization of the static
+ * context secp256k1_context_static is not supported.
+ *
+ * Currently, the random seed is mainly used for blinding multiplications of a
+ * secret scalar with the elliptic curve base point. Multiplications of this
+ * kind are performed by exactly those API functions which are documented to
+ * require a context that is not secp256k1_context_static. As a rule of thumb,
+ * these are all functions which take a secret key (or a keypair) as an input.
+ * A notable exception to that rule is the ECDH module, which relies on a different
+ * kind of elliptic curve point multiplication and thus does not benefit from
+ * enhanced protection against side-channel leakage currently.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
secp256k1_context* ctx,
diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h
index c8577984b1..625061b282 100644
--- a/src/secp256k1/include/secp256k1_ecdh.h
+++ b/src/secp256k1/include/secp256k1_ecdh.h
@@ -27,11 +27,11 @@ typedef int (*secp256k1_ecdh_hash_function)(
/** An implementation of SHA256 hash function that applies to compressed public key.
* Populates the output parameter with 32 bytes. */
-SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
+SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256).
* Populates the output parameter with 32 bytes. */
-SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
+SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
/** Compute an EC Diffie-Hellman secret in constant time
*
diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h
index 09cbeaaa80..3591bc0012 100644
--- a/src/secp256k1/include/secp256k1_extrakeys.h
+++ b/src/secp256k1/include/secp256k1_extrakeys.h
@@ -108,7 +108,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke
* invalid (only when the tweak is the negation of the corresponding
* secret key). 1 otherwise.
*
- * Args: ctx: pointer to a context object initialized for verification.
+ * Args: ctx: pointer to a context object.
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0.
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
@@ -137,7 +137,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
*
* Returns: 0 if the arguments are invalid or the tweaked pubkey is not the
* result of tweaking the internal_pubkey with tweak32. 1 otherwise.
- * Args: ctx: pointer to a context object initialized for verification.
+ * Args: ctx: pointer to a context object.
* In: tweaked_pubkey32: pointer to a serialized xonly_pubkey.
* tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
* is passed in as tweaked_pubkey32). This must match the
@@ -159,7 +159,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
*
* Returns: 1: secret was valid, keypair is ready to use
* 0: secret was invalid, try again with a different secret
- * Args: ctx: pointer to a context object, initialized for signing.
+ * Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: keypair: pointer to the created keypair.
* In: seckey: pointer to a 32-byte secret key.
*/
@@ -228,7 +228,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
* invalid (only when the tweak is the negation of the keypair's
* secret key). 1 otherwise.
*
- * Args: ctx: pointer to a context object initialized for verification.
+ * Args: ctx: pointer to a context object.
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
* an invalid value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according
diff --git a/src/secp256k1/include/secp256k1_preallocated.h b/src/secp256k1/include/secp256k1_preallocated.h
index d2d9014f02..ffa96dd339 100644
--- a/src/secp256k1/include/secp256k1_preallocated.h
+++ b/src/secp256k1/include/secp256k1_preallocated.h
@@ -58,6 +58,8 @@ SECP256K1_API size_t secp256k1_context_preallocated_size(
* bytes, as detailed above.
* flags: which parts of the context to initialize.
*
+ * See secp256k1_context_create (in secp256k1.h) for further details.
+ *
* See also secp256k1_context_randomize (in secp256k1.h)
* and secp256k1_context_preallocated_destroy.
*/
@@ -86,8 +88,11 @@ SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
* the lifetime of this context object, see the description of
* secp256k1_context_preallocated_create for details.
*
+ * Cloning secp256k1_context_static is not possible, and should not be emulated by
+ * the caller (e.g., using memcpy). Create a new context instead.
+ *
* Returns: a newly created context object.
- * Args: ctx: an existing context to copy.
+ * Args: ctx: an existing context to copy (not secp256k1_context_static).
* In: prealloc: a pointer to a rewritable contiguous block of memory of
* size at least secp256k1_context_preallocated_size(flags)
* bytes, as detailed above.
@@ -115,7 +120,8 @@ SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
*
* Args: ctx: an existing context to destroy, constructed using
* secp256k1_context_preallocated_create or
- * secp256k1_context_preallocated_clone.
+ * secp256k1_context_preallocated_clone
+ * (i.e., not secp256k1_context_static).
*/
SECP256K1_API void secp256k1_context_preallocated_destroy(
secp256k1_context* ctx
diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h
index 0e2847db96..824c604025 100644
--- a/src/secp256k1/include/secp256k1_recovery.h
+++ b/src/secp256k1/include/secp256k1_recovery.h
@@ -72,7 +72,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
- * Args: ctx: pointer to a context object, initialized for signing.
+ * Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig: pointer to an array where the signature will be placed.
* In: msghash32: the 32-byte message hash being signed.
* seckey: pointer to a 32-byte secret key.
@@ -94,7 +94,7 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
*
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
* 0: otherwise.
- * Args: ctx: pointer to a context object, initialized for verification.
+ * Args: ctx: pointer to a context object.
* Out: pubkey: pointer to the recovered public key.
* In: sig: pointer to initialized signature that supports pubkey recovery.
* msghash32: the 32-byte message hash assumed to be signed.
diff --git a/src/secp256k1/include/secp256k1_schnorrsig.h b/src/secp256k1/include/secp256k1_schnorrsig.h
index 5fedcb07b0..4cd2d98256 100644
--- a/src/secp256k1/include/secp256k1_schnorrsig.h
+++ b/src/secp256k1/include/secp256k1_schnorrsig.h
@@ -61,7 +61,7 @@ typedef int (*secp256k1_nonce_function_hardened)(
* Therefore, to create BIP-340 compliant signatures, algo must be set to
* "BIP0340/nonce" and algolen to 13.
*/
-SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
+SECP256K1_API_VAR const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
/** Data structure that contains additional arguments for schnorrsig_sign_custom.
*
@@ -106,7 +106,7 @@ typedef struct {
* signatures from being valid in multiple contexts by accident.
*
* Returns 1 on success, 0 on failure.
- * Args: ctx: pointer to a context object, initialized for signing.
+ * Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig64: pointer to a 64-byte array to store the serialized signature.
* In: msg32: the 32-byte message being signed.
* keypair: pointer to an initialized keypair.
@@ -161,7 +161,7 @@ SECP256K1_API int secp256k1_schnorrsig_sign_custom(
*
* Returns: 1: correct signature
* 0: incorrect signature
- * Args: ctx: a secp256k1 context object, initialized for verification.
+ * Args: ctx: a secp256k1 context object.
* In: sig64: pointer to the 64-byte signature to verify.
* msg: the message being verified. Can only be NULL if msglen is 0.
* msglen: length of the message
diff --git a/src/secp256k1/libsecp256k1.pc.in b/src/secp256k1/libsecp256k1.pc.in
index 694e98eef5..0fb6f48a6c 100644
--- a/src/secp256k1/libsecp256k1.pc.in
+++ b/src/secp256k1/libsecp256k1.pc.in
@@ -9,5 +9,4 @@ URL: https://github.com/bitcoin-core/secp256k1
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -lsecp256k1
-Libs.private: @SECP_LIBS@
diff --git a/src/secp256k1/sage/gen_exhaustive_groups.sage b/src/secp256k1/sage/gen_exhaustive_groups.sage
index 01d15dcdea..070bc1285f 100644
--- a/src/secp256k1/sage/gen_exhaustive_groups.sage
+++ b/src/secp256k1/sage/gen_exhaustive_groups.sage
@@ -1,124 +1,156 @@
load("secp256k1_params.sage")
+MAX_ORDER = 1000
+
+# Set of (curve) orders we have encountered so far.
orders_done = set()
-results = {}
-first = True
+
+# Map from (subgroup) orders to [b, int(gen.x), int(gen.y), gen, lambda] for those subgroups.
+solutions = {}
+
+# Iterate over curves of the form y^2 = x^3 + B.
for b in range(1, P):
- # There are only 6 curves (up to isomorphism) of the form y^2=x^3+B. Stop once we have tried all.
+ # There are only 6 curves (up to isomorphism) of the form y^2 = x^3 + B. Stop once we have tried all.
if len(orders_done) == 6:
break
E = EllipticCurve(F, [0, b])
print("Analyzing curve y^2 = x^3 + %i" % b)
n = E.order()
+
# Skip curves with an order we've already tried
if n in orders_done:
print("- Isomorphic to earlier curve")
+ print()
continue
orders_done.add(n)
+
# Skip curves isomorphic to the real secp256k1
if n.is_pseudoprime():
- print(" - Isomorphic to secp256k1")
+ assert E.is_isomorphic(C)
+ print("- Isomorphic to secp256k1")
+ print()
continue
- print("- Finding subgroups")
-
- # Find what prime subgroups exist
- for f, _ in n.factor():
- print("- Analyzing subgroup of order %i" % f)
- # Skip subgroups of order >1000
- if f < 4 or f > 1000:
- print(" - Bad size")
- continue
-
- # Iterate over X coordinates until we find one that is on the curve, has order f,
- # and for which curve isomorphism exists that maps it to X coordinate 1.
- for x in range(1, P):
- # Skip X coordinates not on the curve, and construct the full point otherwise.
- if not E.is_x_coord(x):
- continue
- G = E.lift_x(F(x))
+ print("- Finding prime subgroups")
- print(" - Analyzing (multiples of) point with X=%i" % x)
+ # Map from group_order to a set of independent generators for that order.
+ curve_gens = {}
- # Skip points whose order is not a multiple of f. Project the point to have
- # order f otherwise.
- if (G.order() % f):
- print(" - Bad order")
+ for g in E.gens():
+ # Find what prime subgroups of group generated by g exist.
+ g_order = g.order()
+ for f, _ in g.order().factor():
+ # Skip subgroups that have bad size.
+ if f < 4:
+ print(f" - Subgroup of size {f}: too small")
+ continue
+ if f > MAX_ORDER:
+ print(f" - Subgroup of size {f}: too large")
continue
- G = G * (G.order() // f)
+
+ # Construct a generator for that subgroup.
+ gen = g * (g_order // f)
+ assert(gen.order() == f)
+
+ # Add to set the minimal multiple of gen.
+ curve_gens.setdefault(f, set()).add(min([j*gen for j in range(1, f)]))
+ print(f" - Subgroup of size {f}: ok")
+
+ for f in sorted(curve_gens.keys()):
+ print(f"- Constructing group of order {f}")
+ cbrts = sorted([int(c) for c in Integers(f)(1).nth_root(3, all=true) if c != 1])
+ gens = list(curve_gens[f])
+ sol_count = 0
+ no_endo_count = 0
+
+ # Consider all non-zero linear combinations of the independent generators.
+ for j in range(1, f**len(gens)):
+ gen = sum(gens[k] * ((j // f**k) % f) for k in range(len(gens)))
+ assert not gen.is_zero()
+ assert (f*gen).is_zero()
# Find lambda for endomorphism. Skip if none can be found.
lam = None
- for l in Integers(f)(1).nth_root(3, all=True):
- if int(l)*G == E(BETA*G[0], G[1]):
- lam = int(l)
+ for l in cbrts:
+ if l*gen == E(BETA*gen[0], gen[1]):
+ lam = l
break
+
if lam is None:
- print(" - No endomorphism for this subgroup")
- break
-
- # Now look for an isomorphism of the curve that gives this point an X
- # coordinate equal to 1.
- # If (x,y) is on y^2 = x^3 + b, then (a^2*x, a^3*y) is on y^2 = x^3 + a^6*b.
- # So look for m=a^2=1/x.
- m = F(1)/G[0]
- if not m.is_square():
- print(" - No curve isomorphism maps it to a point with X=1")
- continue
- a = m.sqrt()
- rb = a^6*b
- RE = EllipticCurve(F, [0, rb])
-
- # Use as generator twice the image of G under the above isormorphism.
- # This means that generator*(1/2 mod f) will have X coordinate 1.
- RG = RE(1, a^3*G[1]) * 2
- # And even Y coordinate.
- if int(RG[1]) % 2:
- RG = -RG
- assert(RG.order() == f)
- assert(lam*RG == RE(BETA*RG[0], RG[1]))
-
- # We have found curve RE:y^2=x^3+rb with generator RG of order f. Remember it
- results[f] = {"b": rb, "G": RG, "lambda": lam}
- print(" - Found solution")
- break
-
- print("")
-
-print("")
-print("")
-print("/* To be put in src/group_impl.h: */")
+ no_endo_count += 1
+ else:
+ sol_count += 1
+ solutions.setdefault(f, []).append((b, int(gen[0]), int(gen[1]), gen, lam))
+
+ print(f" - Found {sol_count} generators (plus {no_endo_count} without endomorphism)")
+
+ print()
+
+def output_generator(g, name):
+ print(f"#define {name} SECP256K1_GE_CONST(\\")
+ print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
+ print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
+ print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
+ print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
+ print(")")
+
+def output_b(b):
+ print(f"#define SECP256K1_B {int(b)}")
+
+print()
+print("To be put in src/group_impl.h:")
+print()
+print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */")
+for f in sorted(solutions.keys()):
+ # Use as generator/2 the one with lowest b, and lowest (x, y) generator (interpreted as non-negative integers).
+ b, _, _, HALF_G, lam = min(solutions[f])
+ output_generator(2 * HALF_G, f"SECP256K1_G_ORDER_{f}")
+print("/** Generator for secp256k1, value 'g' defined in")
+print(" * \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.")
+print(" */")
+output_generator(G, "SECP256K1_G")
+print("/* These exhaustive group test orders and generators are chosen such that:")
+print(" * - The field size is equal to that of secp256k1, so field code is the same.")
+print(" * - The curve equation is of the form y^2=x^3+B for some small constant B.")
+print(" * - The subgroup has a generator 2*P, where P.x is as small as possible.")
+print(f" * - The subgroup has size less than {MAX_ORDER} to permit exhaustive testing.")
+print(" * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).")
+print(" */")
+print("#if defined(EXHAUSTIVE_TEST_ORDER)")
first = True
-for f in sorted(results.keys()):
- b = results[f]["b"]
- G = results[f]["G"]
- print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f))
+for f in sorted(solutions.keys()):
+ b, _, _, _, lam = min(solutions[f])
+ print(f"# {'if' if first else 'elif'} EXHAUSTIVE_TEST_ORDER == {f}")
first = False
- print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(")
- print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
- print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
- print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
- print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
- print(");")
- print("static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(")
- print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
- print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
- print(");")
+ print()
+ print(f"static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_{f};")
+ output_b(b)
+ print()
print("# else")
print("# error No known generator for the specified exhaustive test group order.")
print("# endif")
+print("#else")
+print()
+print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;")
+output_b(7)
+print()
+print("#endif")
+print("/* End of section generated by sage/gen_exhaustive_groups.sage. */")
+
-print("")
-print("")
-print("/* To be put in src/scalar_impl.h: */")
+print()
+print()
+print("To be put in src/scalar_impl.h:")
+print()
+print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */")
first = True
-for f in sorted(results.keys()):
- lam = results[f]["lambda"]
+for f in sorted(solutions.keys()):
+ _, _, _, _, lam = min(solutions[f])
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f))
first = False
print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam)
print("# else")
print("# error No known lambda for the specified exhaustive test group order.")
print("# endif")
-print("")
+print("/* End of section generated by sage/gen_exhaustive_groups.sage. */")
diff --git a/src/secp256k1/sage/prove_group_implementations.sage b/src/secp256k1/sage/prove_group_implementations.sage
index 652bd87f11..23799be52b 100644
--- a/src/secp256k1/sage/prove_group_implementations.sage
+++ b/src/secp256k1/sage/prove_group_implementations.sage
@@ -148,7 +148,7 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
zeroes = {}
nonzeroes = {}
a_infinity = False
- if (branch & 4) != 0:
+ if (branch & 2) != 0:
nonzeroes.update({a.Infinity : 'a_infinite'})
a_infinity = True
else:
@@ -167,15 +167,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
m_alt = -u2
tt = u1 * m_alt
rr = rr + tt
- degenerate = (branch & 3) == 3
- if (branch & 1) != 0:
+ degenerate = (branch & 1) != 0
+ if degenerate:
zeroes.update({m : 'm_zero'})
else:
nonzeroes.update({m : 'm_nonzero'})
- if (branch & 2) != 0:
- zeroes.update({rr : 'rr_zero'})
- else:
- nonzeroes.update({rr : 'rr_nonzero'})
rr_alt = s1
rr_alt = rr_alt * 2
m_alt = m_alt + u1
@@ -190,13 +186,6 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
n = m
t = rr_alt^2
rz = a.Z * m_alt
- infinity = False
- if (branch & 8) != 0:
- if not a_infinity:
- infinity = True
- zeroes.update({rz : 'r.z=0'})
- else:
- nonzeroes.update({rz : 'r.z!=0'})
t = t + q
rx = t
t = t * 2
@@ -209,8 +198,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
rx = b.X
ry = b.Y
rz = 1
- if infinity:
+ if (branch & 4) != 0:
+ zeroes.update({rz : 'r.z = 0'})
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity())
+ else:
+ nonzeroes.update({rz : 'r.z != 0'})
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz))
def formula_secp256k1_gej_add_ge_old(branch, a, b):
@@ -280,14 +272,14 @@ if __name__ == "__main__":
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
- success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
+ success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge)
success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old))
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
- success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
+ success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge, 43)
success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43))
sys.exit(int(not success))
diff --git a/src/secp256k1/src/CMakeLists.txt b/src/secp256k1/src/CMakeLists.txt
new file mode 100644
index 0000000000..26272d0950
--- /dev/null
+++ b/src/secp256k1/src/CMakeLists.txt
@@ -0,0 +1,151 @@
+# Must be included before CMAKE_INSTALL_INCLUDEDIR is used.
+include(GNUInstallDirs)
+set(${PROJECT_NAME}_installables "")
+
+if(SECP256K1_ASM STREQUAL "arm")
+ add_library(common OBJECT
+ asm/field_10x26_arm.s
+ )
+ set(common_obj "$<TARGET_OBJECTS:common>")
+else()
+ set(common_obj "")
+endif()
+
+add_library(precomputed OBJECT
+ precomputed_ecmult.c
+ precomputed_ecmult_gen.c
+)
+set(internal_obj "$<TARGET_OBJECTS:precomputed>" "${common_obj}")
+
+add_library(secp256k1 SHARED EXCLUDE_FROM_ALL
+ secp256k1.c
+ ${internal_obj}
+)
+target_include_directories(secp256k1 INTERFACE
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+target_compile_definitions(secp256k1 PRIVATE
+ $<$<PLATFORM_ID:Windows>:DLL_EXPORT>
+)
+set_target_properties(secp256k1 PROPERTIES
+ VERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}"
+ SOVERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}"
+)
+if(SECP256K1_BUILD_SHARED)
+ get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
+ set_target_properties(precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
+ set_target_properties(secp256k1 PROPERTIES EXCLUDE_FROM_ALL FALSE)
+ list(APPEND ${PROJECT_NAME}_installables secp256k1)
+endif()
+
+add_library(secp256k1_static STATIC EXCLUDE_FROM_ALL
+ secp256k1.c
+ ${internal_obj}
+)
+target_include_directories(secp256k1_static INTERFACE
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+if(NOT MSVC)
+ set_target_properties(secp256k1_static PROPERTIES
+ OUTPUT_NAME secp256k1
+ )
+endif()
+if(SECP256K1_BUILD_STATIC)
+ set_target_properties(secp256k1_static PROPERTIES EXCLUDE_FROM_ALL FALSE)
+ list(APPEND ${PROJECT_NAME}_installables secp256k1_static)
+endif()
+
+add_library(binary_interface INTERFACE)
+target_compile_definitions(binary_interface INTERFACE
+ $<$<C_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>
+)
+
+add_library(link_library INTERFACE)
+if(SECP256K1_BUILD_SHARED)
+ target_link_libraries(link_library INTERFACE secp256k1)
+elseif(SECP256K1_BUILD_STATIC)
+ target_link_libraries(link_library INTERFACE secp256k1_static)
+endif()
+
+if(SECP256K1_BUILD_BENCHMARK)
+ add_executable(bench bench.c)
+ target_link_libraries(bench binary_interface link_library)
+ add_executable(bench_internal bench_internal.c ${internal_obj})
+ target_link_libraries(bench_internal binary_interface)
+ add_executable(bench_ecmult bench_ecmult.c ${internal_obj})
+ target_link_libraries(bench_ecmult binary_interface)
+endif()
+
+if(SECP256K1_BUILD_TESTS)
+ add_executable(noverify_tests tests.c ${internal_obj})
+ target_link_libraries(noverify_tests binary_interface)
+ add_test(noverify_tests noverify_tests)
+ if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
+ add_executable(tests tests.c ${internal_obj})
+ target_compile_definitions(tests PRIVATE VERIFY)
+ target_link_libraries(tests binary_interface)
+ add_test(tests tests)
+ endif()
+endif()
+
+if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
+ # Note: do not include $<TARGET_OBJECTS:precomputed> in exhaustive_tests (it uses runtime-generated tables).
+ add_executable(exhaustive_tests tests_exhaustive.c ${common_obj})
+ target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
+ target_link_libraries(exhaustive_tests binary_interface)
+ add_test(exhaustive_tests exhaustive_tests)
+endif()
+
+if(SECP256K1_BUILD_CTIME_TESTS)
+ add_executable(ctime_tests ctime_tests.c)
+ target_link_libraries(ctime_tests binary_interface link_library)
+endif()
+
+install(TARGETS ${${PROJECT_NAME}_installables}
+ EXPORT ${PROJECT_NAME}-targets
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+set(${PROJECT_NAME}_headers
+ "${PROJECT_SOURCE_DIR}/include/secp256k1.h"
+ "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h"
+)
+if(SECP256K1_ENABLE_MODULE_ECDH)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h")
+endif()
+if(SECP256K1_ENABLE_MODULE_RECOVERY)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h")
+endif()
+if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h")
+endif()
+if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
+endif()
+install(FILES ${${PROJECT_NAME}_headers}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+)
+
+install(EXPORT ${PROJECT_NAME}-targets
+ FILE ${PROJECT_NAME}-targets.cmake
+ NAMESPACE ${PROJECT_NAME}::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+)
+
+include(CMakePackageConfigHelpers)
+configure_package_config_file(
+ ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in
+ ${PROJECT_NAME}-config.cmake
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+ NO_SET_AND_CHECK_MACRO
+)
+write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake
+ COMPATIBILITY SameMajorVersion
+)
+install(
+ FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+)
diff --git a/src/secp256k1/src/assumptions.h b/src/secp256k1/src/assumptions.h
index 6dc527b288..8ed04209e9 100644
--- a/src/secp256k1/src/assumptions.h
+++ b/src/secp256k1/src/assumptions.h
@@ -10,6 +10,9 @@
#include <limits.h>
#include "util.h"
+#if defined(SECP256K1_INT128_NATIVE)
+#include "int128_native.h"
+#endif
/* This library, like most software, relies on a number of compiler implementation defined (but not undefined)
behaviours. Although the behaviours we require are essentially universal we test them specifically here to
@@ -55,7 +58,7 @@ struct secp256k1_assumption_checker {
/* To int64_t. */
((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
-#if defined(SECP256K1_WIDEMUL_INT128)
+#if defined(SECP256K1_INT128_NATIVE)
((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) &&
(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) &&
(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) &&
@@ -71,7 +74,7 @@ struct secp256k1_assumption_checker {
((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) &&
((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) &&
((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) &&
-#if defined(SECP256K1_WIDEMUL_INT128)
+#if defined(SECP256K1_INT128_NATIVE)
((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
#endif
1) * 2 - 1];
diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h
deleted file mode 100644
index 6f7693cb8f..0000000000
--- a/src/secp256k1/src/basic-config.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/***********************************************************************
- * Copyright (c) 2013, 2014 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
- ***********************************************************************/
-
-#ifndef SECP256K1_BASIC_CONFIG_H
-#define SECP256K1_BASIC_CONFIG_H
-
-#ifdef USE_BASIC_CONFIG
-
-#define ECMULT_WINDOW_SIZE 15
-#define ECMULT_GEN_PREC_BITS 4
-
-#endif /* USE_BASIC_CONFIG */
-
-#endif /* SECP256K1_BASIC_CONFIG_H */
diff --git a/src/secp256k1/src/bench.c b/src/secp256k1/src/bench.c
index d5937b763f..833f70718b 100644
--- a/src/secp256k1/src/bench.c
+++ b/src/secp256k1/src/bench.c
@@ -11,7 +11,7 @@
#include "util.h"
#include "bench.h"
-void help(int default_iters) {
+static void help(int default_iters) {
printf("Benchmarks the following algorithms:\n");
printf(" - ECDSA signing/verification\n");
@@ -164,7 +164,7 @@ int main(int argc, char** argv) {
/* Check if the user tries to benchmark optional module without building it */
#ifndef ENABLE_MODULE_ECDH
- if (have_flag(argc, argv, "ecdh")) {
+ if (have_flag(argc, argv, "ecdh")) {
fprintf(stderr, "./bench: ECDH module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n");
return 1;
@@ -172,7 +172,7 @@ int main(int argc, char** argv) {
#endif
#ifndef ENABLE_MODULE_RECOVERY
- if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
+ if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
fprintf(stderr, "./bench: Public key recovery module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n");
return 1;
@@ -180,15 +180,15 @@ int main(int argc, char** argv) {
#endif
#ifndef ENABLE_MODULE_SCHNORRSIG
- if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
+ if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n");
return 1;
}
#endif
- /* ECDSA verification benchmark */
- data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ /* ECDSA benchmark */
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
for (i = 0; i < 32; i++) {
data.msg[i] = 1 + i;
@@ -206,11 +206,6 @@ int main(int argc, char** argv) {
print_output_table_header_row();
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
- secp256k1_context_destroy(data.ctx);
-
- /* ECDSA signing benchmark */
- data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
-
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
secp256k1_context_destroy(data.ctx);
diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h
index aa275fe919..bf9a932ff4 100644
--- a/src/secp256k1/src/bench.h
+++ b/src/secp256k1/src/bench.h
@@ -7,22 +7,38 @@
#ifndef SECP256K1_BENCH_H
#define SECP256K1_BENCH_H
+#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
-#include "sys/time.h"
+
+#if (defined(_MSC_VER) && _MSC_VER >= 1900)
+# include <time.h>
+#else
+# include "sys/time.h"
+#endif
static int64_t gettime_i64(void) {
+#if (defined(_MSC_VER) && _MSC_VER >= 1900)
+ /* C11 way to get wallclock time */
+ struct timespec tv;
+ if (!timespec_get(&tv, TIME_UTC)) {
+ fputs("timespec_get failed!", stderr);
+ exit(1);
+ }
+ return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL;
+#else
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
+#endif
}
#define FP_EXP (6)
#define FP_MULT (1000000LL)
/* Format fixed point number. */
-void print_number(const int64_t x) {
+static void print_number(const int64_t x) {
int64_t x_abs, y;
int c, i, rounding, g; /* g = integer part size, c = fractional part size */
size_t ptr;
@@ -79,7 +95,7 @@ void print_number(const int64_t x) {
printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */
}
-void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
+static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
int i;
int64_t min = INT64_MAX;
int64_t sum = 0;
@@ -113,7 +129,7 @@ void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void
printf("\n");
}
-int have_flag(int argc, char** argv, char *flag) {
+static int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc;
argv++;
while (argv != argm) {
@@ -129,7 +145,7 @@ int have_flag(int argc, char** argv, char *flag) {
returns:
- 1 if the user entered an invalid argument
- 0 if all the user entered arguments are valid */
-int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
+static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
size_t i;
int found_valid;
char** argm = argv + argc;
@@ -151,7 +167,7 @@ int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
return 0;
}
-int get_iters(int default_iters) {
+static int get_iters(int default_iters) {
char* env = getenv("SECP256K1_BENCH_ITERS");
if (env) {
return strtol(env, NULL, 0);
@@ -160,7 +176,7 @@ int get_iters(int default_iters) {
}
}
-void print_output_table_header_row(void) {
+static void print_output_table_header_row(void) {
char* bench_str = "Benchmark"; /* left justified */
char* min_str = " Min(us) "; /* center alignment */
char* avg_str = " Avg(us) ";
diff --git a/src/secp256k1/src/bench_ecmult.c b/src/secp256k1/src/bench_ecmult.c
index 4030e0263f..98fb798d82 100644
--- a/src/secp256k1/src/bench_ecmult.c
+++ b/src/secp256k1/src/bench_ecmult.c
@@ -18,7 +18,7 @@
#define POINTS 32768
-void help(char **argv) {
+static void help(char **argv) {
printf("Benchmark EC multiplication algorithms\n");
printf("\n");
printf("Usage: %s <help|pippenger_wnaf|strauss_wnaf|simple>\n", argv[0]);
@@ -84,9 +84,7 @@ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset
}
}
secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars);
- secp256k1_gej_neg(&tmp, &tmp);
- secp256k1_gej_add_var(&tmp, &tmp, &sum_output, NULL);
- CHECK(secp256k1_gej_is_infinity(&tmp));
+ CHECK(secp256k1_gej_eq_var(&tmp, &sum_output));
}
static void bench_ecmult_setup(void* arg) {
@@ -308,7 +306,7 @@ int main(int argc, char **argv) {
}
}
- data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
if (!have_flag(argc, argv, "simple")) {
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index 7eb3af28d7..c248ab8ebc 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -27,7 +27,7 @@ typedef struct {
int wnaf[256];
} bench_inv;
-void bench_setup(void* arg) {
+static void bench_setup(void* arg) {
bench_inv *data = (bench_inv*)arg;
static const unsigned char init[4][32] = {
@@ -79,7 +79,7 @@ void bench_setup(void* arg) {
memcpy(data->data + 32, init[1], 32);
}
-void bench_scalar_add(void* arg, int iters) {
+static void bench_scalar_add(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
@@ -89,7 +89,7 @@ void bench_scalar_add(void* arg, int iters) {
CHECK(j <= iters);
}
-void bench_scalar_negate(void* arg, int iters) {
+static void bench_scalar_negate(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -98,7 +98,7 @@ void bench_scalar_negate(void* arg, int iters) {
}
}
-void bench_scalar_mul(void* arg, int iters) {
+static void bench_scalar_mul(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -107,18 +107,19 @@ void bench_scalar_mul(void* arg, int iters) {
}
}
-void bench_scalar_split(void* arg, int iters) {
+static void bench_scalar_split(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
+ secp256k1_scalar tmp;
for (i = 0; i < iters; i++) {
- secp256k1_scalar_split_lambda(&data->scalar[0], &data->scalar[1], &data->scalar[0]);
- j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
+ secp256k1_scalar_split_lambda(&tmp, &data->scalar[1], &data->scalar[0]);
+ j += secp256k1_scalar_add(&data->scalar[0], &tmp, &data->scalar[1]);
}
CHECK(j <= iters);
}
-void bench_scalar_inverse(void* arg, int iters) {
+static void bench_scalar_inverse(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
@@ -129,7 +130,7 @@ void bench_scalar_inverse(void* arg, int iters) {
CHECK(j <= iters);
}
-void bench_scalar_inverse_var(void* arg, int iters) {
+static void bench_scalar_inverse_var(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
@@ -140,7 +141,7 @@ void bench_scalar_inverse_var(void* arg, int iters) {
CHECK(j <= iters);
}
-void bench_field_half(void* arg, int iters) {
+static void bench_field_half(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -149,7 +150,7 @@ void bench_field_half(void* arg, int iters) {
}
}
-void bench_field_normalize(void* arg, int iters) {
+static void bench_field_normalize(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -158,7 +159,7 @@ void bench_field_normalize(void* arg, int iters) {
}
}
-void bench_field_normalize_weak(void* arg, int iters) {
+static void bench_field_normalize_weak(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -167,7 +168,7 @@ void bench_field_normalize_weak(void* arg, int iters) {
}
}
-void bench_field_mul(void* arg, int iters) {
+static void bench_field_mul(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -176,7 +177,7 @@ void bench_field_mul(void* arg, int iters) {
}
}
-void bench_field_sqr(void* arg, int iters) {
+static void bench_field_sqr(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -185,7 +186,7 @@ void bench_field_sqr(void* arg, int iters) {
}
}
-void bench_field_inverse(void* arg, int iters) {
+static void bench_field_inverse(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -195,7 +196,7 @@ void bench_field_inverse(void* arg, int iters) {
}
}
-void bench_field_inverse_var(void* arg, int iters) {
+static void bench_field_inverse_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -205,7 +206,7 @@ void bench_field_inverse_var(void* arg, int iters) {
}
}
-void bench_field_sqrt(void* arg, int iters) {
+static void bench_field_sqrt(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
secp256k1_fe t;
@@ -218,7 +219,20 @@ void bench_field_sqrt(void* arg, int iters) {
CHECK(j <= iters);
}
-void bench_group_double_var(void* arg, int iters) {
+static void bench_field_is_square_var(void* arg, int iters) {
+ int i, j = 0;
+ bench_inv *data = (bench_inv*)arg;
+ secp256k1_fe t = data->fe[0];
+
+ for (i = 0; i < iters; i++) {
+ j += secp256k1_fe_is_square_var(&t);
+ secp256k1_fe_add(&t, &data->fe[1]);
+ secp256k1_fe_normalize_var(&t);
+ }
+ CHECK(j <= iters);
+}
+
+static void bench_group_double_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -227,7 +241,7 @@ void bench_group_double_var(void* arg, int iters) {
}
}
-void bench_group_add_var(void* arg, int iters) {
+static void bench_group_add_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -236,7 +250,7 @@ void bench_group_add_var(void* arg, int iters) {
}
}
-void bench_group_add_affine(void* arg, int iters) {
+static void bench_group_add_affine(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -245,7 +259,7 @@ void bench_group_add_affine(void* arg, int iters) {
}
}
-void bench_group_add_affine_var(void* arg, int iters) {
+static void bench_group_add_affine_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -254,7 +268,7 @@ void bench_group_add_affine_var(void* arg, int iters) {
}
}
-void bench_group_add_zinv_var(void* arg, int iters) {
+static void bench_group_add_zinv_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -263,7 +277,7 @@ void bench_group_add_zinv_var(void* arg, int iters) {
}
}
-void bench_group_to_affine_var(void* arg, int iters) {
+static void bench_group_to_affine_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -283,7 +297,7 @@ void bench_group_to_affine_var(void* arg, int iters) {
}
}
-void bench_ecmult_wnaf(void* arg, int iters) {
+static void bench_ecmult_wnaf(void* arg, int iters) {
int i, bits = 0, overflow = 0;
bench_inv *data = (bench_inv*)arg;
@@ -295,7 +309,7 @@ void bench_ecmult_wnaf(void* arg, int iters) {
CHECK(bits <= 256*iters);
}
-void bench_wnaf_const(void* arg, int iters) {
+static void bench_wnaf_const(void* arg, int iters) {
int i, bits = 0, overflow = 0;
bench_inv *data = (bench_inv*)arg;
@@ -307,8 +321,7 @@ void bench_wnaf_const(void* arg, int iters) {
CHECK(bits <= 256*iters);
}
-
-void bench_sha256(void* arg, int iters) {
+static void bench_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_sha256 sha;
@@ -320,7 +333,7 @@ void bench_sha256(void* arg, int iters) {
}
}
-void bench_hmac_sha256(void* arg, int iters) {
+static void bench_hmac_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_hmac_sha256 hmac;
@@ -332,7 +345,7 @@ void bench_hmac_sha256(void* arg, int iters) {
}
}
-void bench_rfc6979_hmac_sha256(void* arg, int iters) {
+static void bench_rfc6979_hmac_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_rfc6979_hmac_sha256 rng;
@@ -343,19 +356,11 @@ void bench_rfc6979_hmac_sha256(void* arg, int iters) {
}
}
-void bench_context_verify(void* arg, int iters) {
- int i;
- (void)arg;
- for (i = 0; i < iters; i++) {
- secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY));
- }
-}
-
-void bench_context_sign(void* arg, int iters) {
+static void bench_context(void* arg, int iters) {
int i;
(void)arg;
for (i = 0; i < iters; i++) {
- secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN));
+ secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_NONE));
}
}
@@ -379,6 +384,7 @@ int main(int argc, char **argv) {
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "issquare")) run_benchmark("field_is_square_var", bench_field_is_square_var, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10);
@@ -395,8 +401,7 @@ int main(int argc, char **argv) {
if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters);
- if (d || have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 1 + iters/1000);
- if (d || have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 1 + iters/100);
+ if (d || have_flag(argc, argv, "context")) run_benchmark("context_create", bench_context, bench_setup, NULL, &data, 10, iters);
return 0;
}
diff --git a/src/secp256k1/src/checkmem.h b/src/secp256k1/src/checkmem.h
new file mode 100644
index 0000000000..571e4cc389
--- /dev/null
+++ b/src/secp256k1/src/checkmem.h
@@ -0,0 +1,88 @@
+/***********************************************************************
+ * Copyright (c) 2022 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+/* The code here is inspired by Kris Kwiatkowski's approach in
+ * https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h
+ * to provide a general interface for memory-checking mechanisms, primarily
+ * for constant-time checking.
+ */
+
+/* These macros are defined by this header file:
+ *
+ * - SECP256K1_CHECKMEM_ENABLED:
+ * - 1 if memory-checking integration is available, 0 otherwise.
+ * This is just a compile-time macro. Use the next macro to check it is actually
+ * available at runtime.
+ * - SECP256K1_CHECKMEM_RUNNING():
+ * - Acts like a function call, returning 1 if memory checking is available
+ * at runtime.
+ * - SECP256K1_CHECKMEM_CHECK(p, len):
+ * - Assert or otherwise fail in case the len-byte memory block pointed to by p is
+ * not considered entirely defined.
+ * - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len):
+ * - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode.
+ * - SECP256K1_CHECKMEM_UNDEFINE(p, len):
+ * - marks the len-byte memory block pointed to by p as undefined data (secret data,
+ * in the context of constant-time checking).
+ * - SECP256K1_CHECKMEM_DEFINE(p, len):
+ * - marks the len-byte memory pointed to by p as defined data (public data, in the
+ * context of constant-time checking).
+ *
+ */
+
+#ifndef SECP256K1_CHECKMEM_H
+#define SECP256K1_CHECKMEM_H
+
+/* Define a statement-like macro that ignores the arguments. */
+#define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0)
+
+/* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan.
+ * Choose this preferentially, even when VALGRIND is defined, as msan-compiled
+ * binaries can't be run under valgrind anyway. */
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+# include <sanitizer/msan_interface.h>
+# define SECP256K1_CHECKMEM_ENABLED 1
+# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
+# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len))
+# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len))
+# define SECP256K1_CHECKMEM_RUNNING() (1)
+# endif
+#endif
+
+/* If valgrind integration is desired (through the VALGRIND define), implement the
+ * SECP256K1_CHECKMEM_* macros using valgrind. */
+#if !defined SECP256K1_CHECKMEM_ENABLED
+# if defined VALGRIND
+# include <stddef.h>
+# include <valgrind/memcheck.h>
+# define SECP256K1_CHECKMEM_ENABLED 1
+# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len))
+# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len))
+# define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len))
+ /* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck.
+ * This is more precise than the RUNNING_ON_VALGRIND macro, which
+ * checks for valgrind in general instead of memcheck specifically. */
+# define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0)
+# endif
+#endif
+
+/* As a fall-back, map these macros to dummy statements. */
+#if !defined SECP256K1_CHECKMEM_ENABLED
+# define SECP256K1_CHECKMEM_ENABLED 0
+# define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
+# define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
+# define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
+# define SECP256K1_CHECKMEM_RUNNING() (0)
+#endif
+
+#if defined VERIFY
+#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len))
+#else
+#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
+#endif
+
+#endif /* SECP256K1_CHECKMEM_H */
diff --git a/src/secp256k1/src/valgrind_ctime_test.c b/src/secp256k1/src/ctime_tests.c
index 6ff0085d34..713eb427d3 100644
--- a/src/secp256k1/src/valgrind_ctime_test.c
+++ b/src/secp256k1/src/ctime_tests.c
@@ -4,12 +4,15 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
-#include <valgrind/memcheck.h>
#include <stdio.h>
#include "../include/secp256k1.h"
#include "assumptions.h"
-#include "util.h"
+#include "checkmem.h"
+
+#if !SECP256K1_CHECKMEM_ENABLED
+# error "This tool cannot be compiled without memory-checking interface (valgrind or msan)"
+#endif
#ifdef ENABLE_MODULE_ECDH
# include "../include/secp256k1_ecdh.h"
@@ -27,21 +30,19 @@
#include "../include/secp256k1_schnorrsig.h"
#endif
-void run_tests(secp256k1_context *ctx, unsigned char *key);
+static void run_tests(secp256k1_context *ctx, unsigned char *key);
int main(void) {
secp256k1_context* ctx;
unsigned char key[32];
int ret, i;
- if (!RUNNING_ON_VALGRIND) {
- fprintf(stderr, "This test can only usefully be run inside valgrind.\n");
- fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n");
+ if (!SECP256K1_CHECKMEM_RUNNING()) {
+ fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n");
+ fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n");
return 1;
}
- ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN
- | SECP256K1_CONTEXT_VERIFY
- | SECP256K1_CONTEXT_DECLASSIFY);
+ ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY);
/** In theory, testing with a single secret input should be sufficient:
* If control flow depended on secrets the tool would generate an error.
*/
@@ -53,16 +54,16 @@ int main(void) {
/* Test context randomisation. Do this last because it leaves the context
* tainted. */
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_context_randomize(ctx, key);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret);
secp256k1_context_destroy(ctx);
return 0;
}
-void run_tests(secp256k1_context *ctx, unsigned char *key) {
+static void run_tests(secp256k1_context *ctx, unsigned char *key) {
secp256k1_ecdsa_signature signature;
secp256k1_pubkey pubkey;
size_t siglen = 74;
@@ -85,89 +86,89 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
}
/* Test keygen. */
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key);
- VALGRIND_MAKE_MEM_DEFINED(&pubkey, sizeof(secp256k1_pubkey));
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&pubkey, sizeof(secp256k1_pubkey));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret);
CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
/* Test signing. */
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL);
- VALGRIND_MAKE_MEM_DEFINED(&signature, sizeof(secp256k1_ecdsa_signature));
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&signature, sizeof(secp256k1_ecdsa_signature));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret);
CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature));
#ifdef ENABLE_MODULE_ECDH
/* Test ECDH. */
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
#endif
#ifdef ENABLE_MODULE_RECOVERY
/* Test signing a recoverable signature. */
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL);
- VALGRIND_MAKE_MEM_DEFINED(&recoverable_signature, sizeof(recoverable_signature));
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&recoverable_signature, sizeof(recoverable_signature));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature));
CHECK(recid >= 0 && recid <= 3);
#endif
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ec_seckey_verify(ctx, key);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ec_seckey_negate(ctx, key);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
- VALGRIND_MAKE_MEM_UNDEFINED(msg, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(msg, 32);
ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
- VALGRIND_MAKE_MEM_UNDEFINED(msg, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(msg, 32);
ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
/* Test keypair_create and keypair_xonly_tweak_add. */
#ifdef ENABLE_MODULE_EXTRAKEYS
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_keypair_create(ctx, &keypair, key);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
/* The tweak is not treated as a secret in keypair_tweak_add */
- VALGRIND_MAKE_MEM_DEFINED(msg, 32);
+ SECP256K1_CHECKMEM_DEFINE(msg, 32);
ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
- VALGRIND_MAKE_MEM_UNDEFINED(&keypair, sizeof(keypair));
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(&keypair, sizeof(keypair));
ret = secp256k1_keypair_sec(ctx, key, &keypair);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
#endif
#ifdef ENABLE_MODULE_SCHNORRSIG
- VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_keypair_create(ctx, &keypair, key);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL);
- VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
#endif
}
diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h
index b47d8f494a..e28c602506 100644
--- a/src/secp256k1/src/ecmult.h
+++ b/src/secp256k1/src/ecmult.h
@@ -11,6 +11,17 @@
#include "scalar.h"
#include "scratch.h"
+#ifndef ECMULT_WINDOW_SIZE
+# define ECMULT_WINDOW_SIZE 15
+# ifdef DEBUG_CONFIG
+# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value")
+# endif
+#endif
+
+#ifdef DEBUG_CONFIG
+# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE)
+#endif
+
/* Noone will ever need more than a window size of 24. The code might
* be correct for larger values of ECMULT_WINDOW_SIZE but this is not
* tested.
diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h
index f48f266461..a430e8d5d9 100644
--- a/src/secp256k1/src/ecmult_gen.h
+++ b/src/secp256k1/src/ecmult_gen.h
@@ -10,9 +10,21 @@
#include "scalar.h"
#include "group.h"
+#ifndef ECMULT_GEN_PREC_BITS
+# define ECMULT_GEN_PREC_BITS 4
+# ifdef DEBUG_CONFIG
+# pragma message DEBUG_CONFIG_MSG("ECMULT_GEN_PREC_BITS undefined, assuming default value")
+# endif
+#endif
+
+#ifdef DEBUG_CONFIG
+# pragma message DEBUG_CONFIG_DEF(ECMULT_GEN_PREC_BITS)
+#endif
+
#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8
# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8."
#endif
+
#define ECMULT_GEN_PREC_G(bits) (1 << bits)
#define ECMULT_GEN_PREC_N(bits) (256 / bits)
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 2c8a503acc..4f5ea9f3c0 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -88,31 +88,31 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
unsigned char nonce32[32];
secp256k1_rfc6979_hmac_sha256 rng;
int overflow;
- unsigned char keydata[64] = {0};
+ unsigned char keydata[64];
if (seed32 == NULL) {
/* When seed is NULL, reset the initial point and blinding value. */
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
secp256k1_scalar_set_int(&ctx->blind, 1);
+ return;
}
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
- secp256k1_scalar_get_b32(nonce32, &ctx->blind);
+ secp256k1_scalar_get_b32(keydata, &ctx->blind);
/** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
* asking the caller for blinding values directly and expecting them to retry on failure.
*/
- memcpy(keydata, nonce32, 32);
- if (seed32 != NULL) {
- memcpy(keydata + 32, seed32, 32);
- }
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);
+ VERIFY_CHECK(seed32 != NULL);
+ memcpy(keydata + 32, seed32, 32);
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
memset(keydata, 0, sizeof(keydata));
/* Accept unobservably small non-uniformity. */
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
overflow = !secp256k1_fe_set_b32(&s, nonce32);
overflow |= secp256k1_fe_is_zero(&s);
secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
- /* Randomize the projection to defend against multiplier sidechannels. */
+ /* Randomize the projection to defend against multiplier sidechannels.
+ Do this before our own call to secp256k1_ecmult_gen below. */
secp256k1_gej_rescale(&ctx->initial, &s);
secp256k1_fe_clear(&s);
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
@@ -121,6 +121,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
memset(nonce32, 0, 32);
+ /* The random projection in ctx->initial ensures that gb will have a random projection. */
secp256k1_ecmult_gen(ctx, &gb, &b);
secp256k1_scalar_negate(&b, &b);
ctx->blind = b;
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index bbc820c77c..3776fe73fc 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -200,9 +200,15 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
bit += now;
}
#ifdef VERIFY
- CHECK(carry == 0);
- while (bit < 256) {
- CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0);
+ {
+ int verify_bit = bit;
+
+ VERIFY_CHECK(carry == 0);
+
+ while (verify_bit < 256) {
+ VERIFY_CHECK(secp256k1_scalar_get_bits(&s, verify_bit, 1) == 0);
+ verify_bit++;
+ }
}
#endif
return last_set_bit + 1;
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 2584a494ee..64ceead4d2 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -18,10 +18,6 @@
* imply normality.
*/
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
#include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128)
@@ -89,6 +85,9 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
* as an argument. The magnitude of the output is one higher. */
static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
+/** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */
+static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
+
/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
* small integer. */
static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
@@ -139,4 +138,7 @@ static void secp256k1_fe_half(secp256k1_fe *r);
* magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
+/** Determine whether a is a square (modulo p). */
+static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
+
#endif /* SECP256K1_FIELD_H */
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 21742bf6eb..46b72ce78d 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -7,6 +7,7 @@
#ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H
+#include "checkmem.h"
#include "util.h"
#include "field.h"
#include "modinv32_impl.h"
@@ -481,6 +482,20 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
#endif
}
+SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
+#ifdef VERIFY
+ secp256k1_fe_verify(r);
+ VERIFY_CHECK(a >= 0);
+ VERIFY_CHECK(a <= 0x7FFF);
+#endif
+ r->n[0] += a;
+#ifdef VERIFY
+ r->magnitude += 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+#endif
+}
+
#if defined(USE_EXTERNAL_ASM)
/* External assembler implementation */
@@ -1132,7 +1147,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint32_t mask0, mask1;
- VG_CHECK_VERIFY(r->n, sizeof(r->n));
+ SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -1231,7 +1246,7 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint32_t mask0, mask1;
- VG_CHECK_VERIFY(r->n, sizeof(r->n));
+ SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -1364,4 +1379,31 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
}
+static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
+ secp256k1_fe tmp;
+ secp256k1_modinv32_signed30 s;
+ int jac, ret;
+
+ tmp = *x;
+ secp256k1_fe_normalize_var(&tmp);
+ /* secp256k1_jacobi32_maybe_var cannot deal with input 0. */
+ if (secp256k1_fe_is_zero(&tmp)) return 1;
+ secp256k1_fe_to_signed30(&s, &tmp);
+ jac = secp256k1_jacobi32_maybe_var(&s, &secp256k1_const_modinfo_fe);
+ if (jac == 0) {
+ /* secp256k1_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back
+ * to computing a square root. This should be extremely rare with random
+ * input (except in VERIFY mode, where a lower iteration count is used). */
+ secp256k1_fe dummy;
+ ret = secp256k1_fe_sqrt(&dummy, &tmp);
+ } else {
+#ifdef VERIFY
+ secp256k1_fe dummy;
+ VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
+#endif
+ ret = jac >= 0;
+ }
+ return ret;
+}
+
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index 6bd202f587..4c4466eceb 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -7,10 +7,7 @@
#ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
+#include "checkmem.h"
#include "util.h"
#include "field.h"
#include "modinv64_impl.h"
@@ -428,6 +425,20 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
#endif
}
+SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
+#ifdef VERIFY
+ secp256k1_fe_verify(r);
+ VERIFY_CHECK(a >= 0);
+ VERIFY_CHECK(a <= 0x7FFF);
+#endif
+ r->n[0] += a;
+#ifdef VERIFY
+ r->magnitude += 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+#endif
+}
+
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
secp256k1_fe_verify(a);
@@ -476,7 +487,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint64_t mask0, mask1;
- VG_CHECK_VERIFY(r->n, sizeof(r->n));
+ SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -559,7 +570,7 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint64_t mask0, mask1;
- VG_CHECK_VERIFY(r->n, sizeof(r->n));
+ SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -667,4 +678,31 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
#endif
}
+static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
+ secp256k1_fe tmp;
+ secp256k1_modinv64_signed62 s;
+ int jac, ret;
+
+ tmp = *x;
+ secp256k1_fe_normalize_var(&tmp);
+ /* secp256k1_jacobi64_maybe_var cannot deal with input 0. */
+ if (secp256k1_fe_is_zero(&tmp)) return 1;
+ secp256k1_fe_to_signed62(&s, &tmp);
+ jac = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe);
+ if (jac == 0) {
+ /* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back
+ * to computing a square root. This should be extremely rare with random
+ * input (except in VERIFY mode, where a lower iteration count is used). */
+ secp256k1_fe dummy;
+ ret = secp256k1_fe_sqrt(&dummy, &tmp);
+ } else {
+#ifdef VERIFY
+ secp256k1_fe dummy;
+ VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
+#endif
+ ret = jac >= 0;
+ }
+ return ret;
+}
+
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index 0ed6118cc9..18567b95f3 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -9,14 +9,18 @@
#include <stdint.h>
+#include "int128.h"
+
#ifdef VERIFY
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
+#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n)))
#else
#define VERIFY_BITS(x, n) do { } while(0)
+#define VERIFY_BITS_128(x, n) do { } while(0)
#endif
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
- uint128_t c, d;
+ secp256k1_uint128 c, d;
uint64_t t3, t4, tx, u0;
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
@@ -40,121 +44,119 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
* Note that [x 0 0 0 0 0] = [x*R].
*/
- d = (uint128_t)a0 * b[3]
- + (uint128_t)a1 * b[2]
- + (uint128_t)a2 * b[1]
- + (uint128_t)a3 * b[0];
- VERIFY_BITS(d, 114);
+ secp256k1_u128_mul(&d, a0, b[3]);
+ secp256k1_u128_accum_mul(&d, a1, b[2]);
+ secp256k1_u128_accum_mul(&d, a2, b[1]);
+ secp256k1_u128_accum_mul(&d, a3, b[0]);
+ VERIFY_BITS_128(&d, 114);
/* [d 0 0 0] = [p3 0 0 0] */
- c = (uint128_t)a4 * b[4];
- VERIFY_BITS(c, 112);
+ secp256k1_u128_mul(&c, a4, b[4]);
+ VERIFY_BITS_128(&c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
- d += (uint128_t)R * (uint64_t)c; c >>= 64;
- VERIFY_BITS(d, 115);
- VERIFY_BITS(c, 48);
+ secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64);
+ VERIFY_BITS_128(&d, 115);
+ VERIFY_BITS_128(&c, 48);
/* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
- t3 = d & M; d >>= 52;
+ t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t3, 52);
- VERIFY_BITS(d, 63);
+ VERIFY_BITS_128(&d, 63);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
- d += (uint128_t)a0 * b[4]
- + (uint128_t)a1 * b[3]
- + (uint128_t)a2 * b[2]
- + (uint128_t)a3 * b[1]
- + (uint128_t)a4 * b[0];
- VERIFY_BITS(d, 115);
+ secp256k1_u128_accum_mul(&d, a0, b[4]);
+ secp256k1_u128_accum_mul(&d, a1, b[3]);
+ secp256k1_u128_accum_mul(&d, a2, b[2]);
+ secp256k1_u128_accum_mul(&d, a3, b[1]);
+ secp256k1_u128_accum_mul(&d, a4, b[0]);
+ VERIFY_BITS_128(&d, 115);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- d += (uint128_t)(R << 12) * (uint64_t)c;
- VERIFY_BITS(d, 116);
+ secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c));
+ VERIFY_BITS_128(&d, 116);
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- t4 = d & M; d >>= 52;
+ t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t4, 52);
- VERIFY_BITS(d, 64);
+ VERIFY_BITS_128(&d, 64);
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
tx = (t4 >> 48); t4 &= (M >> 4);
VERIFY_BITS(tx, 4);
VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- c = (uint128_t)a0 * b[0];
- VERIFY_BITS(c, 112);
+ secp256k1_u128_mul(&c, a0, b[0]);
+ VERIFY_BITS_128(&c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
- d += (uint128_t)a1 * b[4]
- + (uint128_t)a2 * b[3]
- + (uint128_t)a3 * b[2]
- + (uint128_t)a4 * b[1];
- VERIFY_BITS(d, 115);
+ secp256k1_u128_accum_mul(&d, a1, b[4]);
+ secp256k1_u128_accum_mul(&d, a2, b[3]);
+ secp256k1_u128_accum_mul(&d, a3, b[2]);
+ secp256k1_u128_accum_mul(&d, a4, b[1]);
+ VERIFY_BITS_128(&d, 115);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- u0 = d & M; d >>= 52;
+ u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(u0, 52);
- VERIFY_BITS(d, 63);
+ VERIFY_BITS_128(&d, 63);
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = (u0 << 4) | tx;
VERIFY_BITS(u0, 56);
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- c += (uint128_t)u0 * (R >> 4);
- VERIFY_BITS(c, 115);
+ secp256k1_u128_accum_mul(&c, u0, R >> 4);
+ VERIFY_BITS_128(&c, 115);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- r[0] = c & M; c >>= 52;
+ r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[0], 52);
- VERIFY_BITS(c, 61);
+ VERIFY_BITS_128(&c, 61);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
- c += (uint128_t)a0 * b[1]
- + (uint128_t)a1 * b[0];
- VERIFY_BITS(c, 114);
+ secp256k1_u128_accum_mul(&c, a0, b[1]);
+ secp256k1_u128_accum_mul(&c, a1, b[0]);
+ VERIFY_BITS_128(&c, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
- d += (uint128_t)a2 * b[4]
- + (uint128_t)a3 * b[3]
- + (uint128_t)a4 * b[2];
- VERIFY_BITS(d, 114);
+ secp256k1_u128_accum_mul(&d, a2, b[4]);
+ secp256k1_u128_accum_mul(&d, a3, b[3]);
+ secp256k1_u128_accum_mul(&d, a4, b[2]);
+ VERIFY_BITS_128(&d, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- c += (d & M) * R; d >>= 52;
- VERIFY_BITS(c, 115);
- VERIFY_BITS(d, 62);
+ secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52);
+ VERIFY_BITS_128(&c, 115);
+ VERIFY_BITS_128(&d, 62);
/* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- r[1] = c & M; c >>= 52;
+ r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[1], 52);
- VERIFY_BITS(c, 63);
+ VERIFY_BITS_128(&c, 63);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- c += (uint128_t)a0 * b[2]
- + (uint128_t)a1 * b[1]
- + (uint128_t)a2 * b[0];
- VERIFY_BITS(c, 114);
+ secp256k1_u128_accum_mul(&c, a0, b[2]);
+ secp256k1_u128_accum_mul(&c, a1, b[1]);
+ secp256k1_u128_accum_mul(&c, a2, b[0]);
+ VERIFY_BITS_128(&c, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
- d += (uint128_t)a3 * b[4]
- + (uint128_t)a4 * b[3];
- VERIFY_BITS(d, 114);
+ secp256k1_u128_accum_mul(&d, a3, b[4]);
+ secp256k1_u128_accum_mul(&d, a4, b[3]);
+ VERIFY_BITS_128(&d, 114);
/* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += (uint128_t)R * (uint64_t)d; d >>= 64;
- VERIFY_BITS(c, 115);
- VERIFY_BITS(d, 50);
+ secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64);
+ VERIFY_BITS_128(&c, 115);
+ VERIFY_BITS_128(&d, 50);
/* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- r[2] = c & M; c >>= 52;
+ r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[2], 52);
- VERIFY_BITS(c, 63);
+ VERIFY_BITS_128(&c, 63);
/* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += (uint128_t)(R << 12) * (uint64_t)d + t3;
- VERIFY_BITS(c, 100);
+ secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d));
+ secp256k1_u128_accum_u64(&c, t3);
+ VERIFY_BITS_128(&c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- r[3] = c & M; c >>= 52;
+ r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[3], 52);
- VERIFY_BITS(c, 48);
+ VERIFY_BITS_128(&c, 48);
/* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += t4;
- VERIFY_BITS(c, 49);
- /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- r[4] = c;
+ r[4] = secp256k1_u128_to_u64(&c) + t4;
VERIFY_BITS(r[4], 49);
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
- uint128_t c, d;
+ secp256k1_uint128 c, d;
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
int64_t t3, t4, tx, u0;
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
@@ -170,107 +172,105 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
* Note that [x 0 0 0 0 0] = [x*R].
*/
- d = (uint128_t)(a0*2) * a3
- + (uint128_t)(a1*2) * a2;
- VERIFY_BITS(d, 114);
+ secp256k1_u128_mul(&d, a0*2, a3);
+ secp256k1_u128_accum_mul(&d, a1*2, a2);
+ VERIFY_BITS_128(&d, 114);
/* [d 0 0 0] = [p3 0 0 0] */
- c = (uint128_t)a4 * a4;
- VERIFY_BITS(c, 112);
+ secp256k1_u128_mul(&c, a4, a4);
+ VERIFY_BITS_128(&c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
- d += (uint128_t)R * (uint64_t)c; c >>= 64;
- VERIFY_BITS(d, 115);
- VERIFY_BITS(c, 48);
+ secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64);
+ VERIFY_BITS_128(&d, 115);
+ VERIFY_BITS_128(&c, 48);
/* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
- t3 = d & M; d >>= 52;
+ t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t3, 52);
- VERIFY_BITS(d, 63);
+ VERIFY_BITS_128(&d, 63);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
a4 *= 2;
- d += (uint128_t)a0 * a4
- + (uint128_t)(a1*2) * a3
- + (uint128_t)a2 * a2;
- VERIFY_BITS(d, 115);
+ secp256k1_u128_accum_mul(&d, a0, a4);
+ secp256k1_u128_accum_mul(&d, a1*2, a3);
+ secp256k1_u128_accum_mul(&d, a2, a2);
+ VERIFY_BITS_128(&d, 115);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- d += (uint128_t)(R << 12) * (uint64_t)c;
- VERIFY_BITS(d, 116);
+ secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c));
+ VERIFY_BITS_128(&d, 116);
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- t4 = d & M; d >>= 52;
+ t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t4, 52);
- VERIFY_BITS(d, 64);
+ VERIFY_BITS_128(&d, 64);
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
tx = (t4 >> 48); t4 &= (M >> 4);
VERIFY_BITS(tx, 4);
VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- c = (uint128_t)a0 * a0;
- VERIFY_BITS(c, 112);
+ secp256k1_u128_mul(&c, a0, a0);
+ VERIFY_BITS_128(&c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
- d += (uint128_t)a1 * a4
- + (uint128_t)(a2*2) * a3;
- VERIFY_BITS(d, 114);
+ secp256k1_u128_accum_mul(&d, a1, a4);
+ secp256k1_u128_accum_mul(&d, a2*2, a3);
+ VERIFY_BITS_128(&d, 114);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- u0 = d & M; d >>= 52;
+ u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(u0, 52);
- VERIFY_BITS(d, 62);
+ VERIFY_BITS_128(&d, 62);
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = (u0 << 4) | tx;
VERIFY_BITS(u0, 56);
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- c += (uint128_t)u0 * (R >> 4);
- VERIFY_BITS(c, 113);
+ secp256k1_u128_accum_mul(&c, u0, R >> 4);
+ VERIFY_BITS_128(&c, 113);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- r[0] = c & M; c >>= 52;
+ r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[0], 52);
- VERIFY_BITS(c, 61);
+ VERIFY_BITS_128(&c, 61);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
a0 *= 2;
- c += (uint128_t)a0 * a1;
- VERIFY_BITS(c, 114);
+ secp256k1_u128_accum_mul(&c, a0, a1);
+ VERIFY_BITS_128(&c, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
- d += (uint128_t)a2 * a4
- + (uint128_t)a3 * a3;
- VERIFY_BITS(d, 114);
+ secp256k1_u128_accum_mul(&d, a2, a4);
+ secp256k1_u128_accum_mul(&d, a3, a3);
+ VERIFY_BITS_128(&d, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- c += (d & M) * R; d >>= 52;
- VERIFY_BITS(c, 115);
- VERIFY_BITS(d, 62);
+ secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52);
+ VERIFY_BITS_128(&c, 115);
+ VERIFY_BITS_128(&d, 62);
/* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- r[1] = c & M; c >>= 52;
+ r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[1], 52);
- VERIFY_BITS(c, 63);
+ VERIFY_BITS_128(&c, 63);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- c += (uint128_t)a0 * a2
- + (uint128_t)a1 * a1;
- VERIFY_BITS(c, 114);
+ secp256k1_u128_accum_mul(&c, a0, a2);
+ secp256k1_u128_accum_mul(&c, a1, a1);
+ VERIFY_BITS_128(&c, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
- d += (uint128_t)a3 * a4;
- VERIFY_BITS(d, 114);
+ secp256k1_u128_accum_mul(&d, a3, a4);
+ VERIFY_BITS_128(&d, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += (uint128_t)R * (uint64_t)d; d >>= 64;
- VERIFY_BITS(c, 115);
- VERIFY_BITS(d, 50);
+ secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64);
+ VERIFY_BITS_128(&c, 115);
+ VERIFY_BITS_128(&d, 50);
/* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- r[2] = c & M; c >>= 52;
+ r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[2], 52);
- VERIFY_BITS(c, 63);
+ VERIFY_BITS_128(&c, 63);
/* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += (uint128_t)(R << 12) * (uint64_t)d + t3;
- VERIFY_BITS(c, 100);
+ secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d));
+ secp256k1_u128_accum_u64(&c, t3);
+ VERIFY_BITS_128(&c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- r[3] = c & M; c >>= 52;
+ r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[3], 52);
- VERIFY_BITS(c, 48);
+ VERIFY_BITS_128(&c, 48);
/* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += t4;
- VERIFY_BITS(c, 49);
- /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- r[4] = c;
+ r[4] = secp256k1_u128_to_u64(&c) + t4;
VERIFY_BITS(r[4], 49);
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 0a4a04d9ac..0a03076bbc 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -7,10 +7,6 @@
#ifndef SECP256K1_FIELD_IMPL_H
#define SECP256K1_FIELD_IMPL_H
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
#include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128)
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index bb7dae1cf7..b79ba597db 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -23,7 +23,7 @@ typedef struct {
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
/** A group element of the secp256k1 curve, in jacobian coordinates.
- * Note: For exhastive test mode, sepc256k1 is replaced by a small subgroup of a different curve.
+ * Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve.
*/
typedef struct {
secp256k1_fe x; /* actual X: x/z^2 */
@@ -97,6 +97,9 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r);
/** Set a group element (jacobian) equal to another which is given in affine coordinates. */
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);
+/** Check two group elements (jacobian) for equality in variable time. */
+static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b);
+
/** Compare the X coordinate of a group element (jacobian). */
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 63735ab682..82ce3f8d8b 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -10,59 +10,69 @@
#include "field.h"
#include "group.h"
+/* Begin of section generated by sage/gen_exhaustive_groups.sage. */
+#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\
+ 0x66625d13, 0x317ffe44, 0x63d32cff, 0x1ca02b9b,\
+ 0xe5c6d070, 0x50b4b05e, 0x81cc30db, 0xf5166f0a,\
+ 0x1e60e897, 0xa7c00c7c, 0x2df53eb6, 0x98274ff4,\
+ 0x64252f42, 0x8ca44e17, 0x3b25418c, 0xff4ab0cf\
+)
#define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\
- 0xc3459c3d, 0x35326167, 0xcd86cce8, 0x07a2417f,\
- 0x5b8bd567, 0xde8538ee, 0x0d507b0c, 0xd128f5bb,\
- 0x8e467fec, 0xcd30000a, 0x6cc1184e, 0x25d382c2,\
- 0xa2f4494e, 0x2fbe9abc, 0x8b64abac, 0xd005fb24\
+ 0xa2482ff8, 0x4bf34edf, 0xa51262fd, 0xe57921db,\
+ 0xe0dd2cb7, 0xa5914790, 0xbc71631f, 0xc09704fb,\
+ 0x942536cb, 0xa3e49492, 0x3a701cc3, 0xee3e443f,\
+ 0xdf182aa9, 0x15b8aa6a, 0x166d3b19, 0xba84b045\
)
#define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\
- 0x226e653f, 0xc8df7744, 0x9bacbf12, 0x7d1dcbf9,\
- 0x87f05b2a, 0xe7edbd28, 0x1f564575, 0xc48dcf18,\
- 0xa13872c2, 0xe933bb17, 0x5d9ffd5b, 0xb5b6e10c,\
- 0x57fe3c00, 0xbaaaa15a, 0xe003ec3e, 0x9c269bae\
+ 0x7fb07b5c, 0xd07c3bda, 0x553902e2, 0x7a87ea2c,\
+ 0x35108a7f, 0x051f41e5, 0xb76abad5, 0x1f2703ad,\
+ 0x0a251539, 0x5b4c4438, 0x952a634f, 0xac10dd4d,\
+ 0x6d6f4745, 0x98990c27, 0x3a4f3116, 0xd32ff969\
)
/** Generator for secp256k1, value 'g' defined in
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
*/
#define SECP256K1_G SECP256K1_GE_CONST(\
- 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL,\
- 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL,\
- 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL,\
- 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL\
+ 0x79be667e, 0xf9dcbbac, 0x55a06295, 0xce870b07,\
+ 0x029bfcdb, 0x2dce28d9, 0x59f2815b, 0x16f81798,\
+ 0x483ada77, 0x26a3c465, 0x5da4fbfc, 0x0e1108a8,\
+ 0xfd17b448, 0xa6855419, 0x9c47d08f, 0xfb10d4b8\
)
/* These exhaustive group test orders and generators are chosen such that:
* - The field size is equal to that of secp256k1, so field code is the same.
- * - The curve equation is of the form y^2=x^3+B for some constant B.
- * - The subgroup has a generator 2*P, where P.x=1.
+ * - The curve equation is of the form y^2=x^3+B for some small constant B.
+ * - The subgroup has a generator 2*P, where P.x is as small as possible.
* - The subgroup has size less than 1000 to permit exhaustive testing.
* - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).
- *
- * These parameters are generated using sage/gen_exhaustive_groups.sage.
*/
#if defined(EXHAUSTIVE_TEST_ORDER)
-# if EXHAUSTIVE_TEST_ORDER == 13
+# if EXHAUSTIVE_TEST_ORDER == 7
+
+static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_7;
+#define SECP256K1_B 6
+
+# elif EXHAUSTIVE_TEST_ORDER == 13
+
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_13;
+#define SECP256K1_B 2
-static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(
- 0x3d3486b2, 0x159a9ca5, 0xc75638be, 0xb23a69bc,
- 0x946a45ab, 0x24801247, 0xb4ed2b8e, 0x26b6a417
-);
# elif EXHAUSTIVE_TEST_ORDER == 199
+
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_199;
+#define SECP256K1_B 4
-static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(
- 0x2cca28fa, 0xfc614b80, 0x2a3db42b, 0x00ba00b1,
- 0xbea8d943, 0xdace9ab2, 0x9536daea, 0x0074defb
-);
# else
# error No known generator for the specified exhaustive test group order.
# endif
#else
+
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
+#define SECP256K1_B 7
-static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7);
#endif
+/* End of section generated by sage/gen_exhaustive_groups.sage. */
+
+static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, SECP256K1_B);
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
secp256k1_fe zi2;
@@ -217,7 +227,7 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o
secp256k1_fe_sqr(&x2, x);
secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0;
- secp256k1_fe_add(&x3, &secp256k1_fe_const_b);
+ secp256k1_fe_add_int(&x3, SECP256K1_B);
if (!secp256k1_fe_sqrt(&r->y, &x3)) {
return 0;
}
@@ -236,6 +246,13 @@ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
secp256k1_fe_set_int(&r->z, 1);
}
+static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) {
+ secp256k1_gej tmp;
+ secp256k1_gej_neg(&tmp, a);
+ secp256k1_gej_add_var(&tmp, &tmp, b, NULL);
+ return secp256k1_gej_is_infinity(&tmp);
+}
+
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
secp256k1_fe r, r2;
VERIFY_CHECK(!a->infinity);
@@ -265,7 +282,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
/* y^2 = x^3 + 7 */
secp256k1_fe_sqr(&y2, &a->y);
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
- secp256k1_fe_add(&x3, &secp256k1_fe_const_b);
+ secp256k1_fe_add_int(&x3, SECP256K1_B);
secp256k1_fe_normalize_weak(&x3);
return secp256k1_fe_equal_var(&y2, &x3);
}
@@ -515,11 +532,11 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
/* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
secp256k1_fe m_alt, rr_alt;
- int infinity, degenerate;
+ int degenerate;
VERIFY_CHECK(!b->infinity);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
- /** In:
+ /* In:
* Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks.
* In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002.
* we find as solution for a unified addition/doubling formula:
@@ -581,10 +598,9 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */
secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */
secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */
- /** If lambda = R/M = 0/0 we have a problem (except in the "trivial"
- * case that Z = z1z2 = 0, and this is special-cased later on). */
- degenerate = secp256k1_fe_normalizes_to_zero(&m) &
- secp256k1_fe_normalizes_to_zero(&rr);
+ /* If lambda = R/M = R/0 we have a problem (except in the "trivial"
+ * case that Z = z1z2 = 0, and this is special-cased later on). */
+ degenerate = secp256k1_fe_normalizes_to_zero(&m);
/* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2.
* This means either x1 == beta*x2 or beta*x1 == x2, where beta is
* a nontrivial cube root of one. In either case, an alternate
@@ -596,7 +612,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_cmov(&rr_alt, &rr, !degenerate);
secp256k1_fe_cmov(&m_alt, &m, !degenerate);
- /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0.
+ /* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0.
* From here on out Ralt and Malt represent the numerator
* and denominator of lambda; R and M represent the explicit
* expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
@@ -611,7 +627,6 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */
- infinity = secp256k1_fe_normalizes_to_zero(&r->z) & ~a->infinity;
secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */
r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */
secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */
@@ -621,11 +636,28 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */
secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */
- /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
+ /* In case a->infinity == 1, replace r with (b->x, b->y, 1). */
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity);
- r->infinity = infinity;
+
+ /* Set r->infinity if r->z is 0.
+ *
+ * If a->infinity is set, then r->infinity = (r->z == 0) = (1 == 0) = false,
+ * which is correct because the function assumes that b is not infinity.
+ *
+ * Now assume !a->infinity. This implies Z = Z1 != 0.
+ *
+ * Case y1 = -y2:
+ * In this case we could have a = -b, namely if x1 = x2.
+ * We have degenerate = true, r->z = (x1 - x2) * Z.
+ * Then r->infinity = ((x1 - x2)Z == 0) = (x1 == x2) = (a == -b).
+ *
+ * Case y1 != -y2:
+ * In this case, we can't have a = -b.
+ * We have degenerate = false, r->z = (y1 + y2) * Z.
+ * Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */
+ r->infinity = secp256k1_fe_normalizes_to_zero(&r->z);
}
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
diff --git a/src/secp256k1/src/int128.h b/src/secp256k1/src/int128.h
new file mode 100644
index 0000000000..5355fbfae0
--- /dev/null
+++ b/src/secp256k1/src/int128.h
@@ -0,0 +1,90 @@
+#ifndef SECP256K1_INT128_H
+#define SECP256K1_INT128_H
+
+#include "util.h"
+
+#if defined(SECP256K1_WIDEMUL_INT128)
+# if defined(SECP256K1_INT128_NATIVE)
+# include "int128_native.h"
+# elif defined(SECP256K1_INT128_STRUCT)
+# include "int128_struct.h"
+# else
+# error "Please select int128 implementation"
+# endif
+
+/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */
+static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo);
+
+/* Multiply two unsigned 64-bit values a and b and write the result to r. */
+static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
+
+/* Multiply two unsigned 64-bit values a and b and add the result to r.
+ * The final result is taken modulo 2^128.
+ */
+static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
+
+/* Add an unsigned 64-bit value a to r.
+ * The final result is taken modulo 2^128.
+ */
+static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a);
+
+/* Unsigned (logical) right shift.
+ * Non-constant time in n.
+ */
+static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n);
+
+/* Return the low 64-bits of a 128-bit value as an unsigned 64-bit value. */
+static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a);
+
+/* Return the high 64-bits of a 128-bit value as an unsigned 64-bit value. */
+static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a);
+
+/* Write an unsigned 64-bit value to r. */
+static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a);
+
+/* Tests if r is strictly less than to 2^n.
+ * n must be strictly less than 128.
+ */
+static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n);
+
+/* Construct an signed 128-bit value from a high and a low 64-bit value. */
+static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo);
+
+/* Multiply two signed 64-bit values a and b and write the result to r. */
+static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b);
+
+/* Multiply two signed 64-bit values a and b and add the result to r.
+ * Overflow or underflow from the addition is undefined behaviour.
+ */
+static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b);
+
+/* Compute a*d - b*c from signed 64-bit values and write the result to r. */
+static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d);
+
+/* Signed (arithmetic) right shift.
+ * Non-constant time in b.
+ */
+static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b);
+
+/* Return the input value modulo 2^64. */
+static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a);
+
+/* Return the value as a signed 64-bit value.
+ * Requires the input to be between INT64_MIN and INT64_MAX.
+ */
+static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a);
+
+/* Write a signed 64-bit value to r. */
+static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a);
+
+/* Compare two 128-bit values for equality. */
+static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b);
+
+/* Tests if r is equal to sign*2^n (sign must be 1 or -1).
+ * n must be strictly less than 127.
+ */
+static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign);
+
+#endif
+
+#endif
diff --git a/src/secp256k1/src/int128_impl.h b/src/secp256k1/src/int128_impl.h
new file mode 100644
index 0000000000..cfc573408a
--- /dev/null
+++ b/src/secp256k1/src/int128_impl.h
@@ -0,0 +1,18 @@
+#ifndef SECP256K1_INT128_IMPL_H
+#define SECP256K1_INT128_IMPL_H
+
+#include "util.h"
+
+#include "int128.h"
+
+#if defined(SECP256K1_WIDEMUL_INT128)
+# if defined(SECP256K1_INT128_NATIVE)
+# include "int128_native_impl.h"
+# elif defined(SECP256K1_INT128_STRUCT)
+# include "int128_struct_impl.h"
+# else
+# error "Please select int128 implementation"
+# endif
+#endif
+
+#endif
diff --git a/src/secp256k1/src/int128_native.h b/src/secp256k1/src/int128_native.h
new file mode 100644
index 0000000000..7c97aafc74
--- /dev/null
+++ b/src/secp256k1/src/int128_native.h
@@ -0,0 +1,19 @@
+#ifndef SECP256K1_INT128_NATIVE_H
+#define SECP256K1_INT128_NATIVE_H
+
+#include <stdint.h>
+#include "util.h"
+
+#if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__)
+SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
+SECP256K1_GNUC_EXT typedef __int128 int128_t;
+# define UINT128_MAX ((uint128_t)(-1))
+# define INT128_MAX ((int128_t)(UINT128_MAX >> 1))
+# define INT128_MIN (-INT128_MAX - 1)
+/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */
+#endif
+
+typedef uint128_t secp256k1_uint128;
+typedef int128_t secp256k1_int128;
+
+#endif
diff --git a/src/secp256k1/src/int128_native_impl.h b/src/secp256k1/src/int128_native_impl.h
new file mode 100644
index 0000000000..996e542cf9
--- /dev/null
+++ b/src/secp256k1/src/int128_native_impl.h
@@ -0,0 +1,93 @@
+#ifndef SECP256K1_INT128_NATIVE_IMPL_H
+#define SECP256K1_INT128_NATIVE_IMPL_H
+
+#include "int128.h"
+
+static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
+ *r = (((uint128_t)hi) << 64) + lo;
+}
+
+static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
+ *r = (uint128_t)a * b;
+}
+
+static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
+ *r += (uint128_t)a * b;
+}
+
+static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) {
+ *r += a;
+}
+
+static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) {
+ VERIFY_CHECK(n < 128);
+ *r >>= n;
+}
+
+static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) {
+ return (uint64_t)(*a);
+}
+
+static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) {
+ return (uint64_t)(*a >> 64);
+}
+
+static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) {
+ *r = a;
+}
+
+static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) {
+ VERIFY_CHECK(n < 128);
+ return (*r >> n == 0);
+}
+
+static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
+ *r = (((uint128_t)(uint64_t)hi) << 64) + lo;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
+ *r = (int128_t)a * b;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
+ int128_t ab = (int128_t)a * b;
+ VERIFY_CHECK(0 <= ab ? *r <= INT128_MAX - ab : INT128_MIN - ab <= *r);
+ *r += ab;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) {
+ int128_t ad = (int128_t)a * d;
+ int128_t bc = (int128_t)b * c;
+ VERIFY_CHECK(0 <= bc ? INT128_MIN + bc <= ad : ad <= INT128_MAX + bc);
+ *r = ad - bc;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) {
+ VERIFY_CHECK(n < 128);
+ *r >>= n;
+}
+
+static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
+ return (uint64_t)*a;
+}
+
+static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
+ VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX);
+ return *a;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
+ *r = a;
+}
+
+static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) {
+ return *a == *b;
+}
+
+static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) {
+ VERIFY_CHECK(n < 127);
+ VERIFY_CHECK(sign == 1 || sign == -1);
+ return (*r == (int128_t)((uint128_t)sign << n));
+}
+
+#endif
diff --git a/src/secp256k1/src/int128_struct.h b/src/secp256k1/src/int128_struct.h
new file mode 100644
index 0000000000..6156f82cc2
--- /dev/null
+++ b/src/secp256k1/src/int128_struct.h
@@ -0,0 +1,14 @@
+#ifndef SECP256K1_INT128_STRUCT_H
+#define SECP256K1_INT128_STRUCT_H
+
+#include <stdint.h>
+#include "util.h"
+
+typedef struct {
+ uint64_t lo;
+ uint64_t hi;
+} secp256k1_uint128;
+
+typedef secp256k1_uint128 secp256k1_int128;
+
+#endif
diff --git a/src/secp256k1/src/int128_struct_impl.h b/src/secp256k1/src/int128_struct_impl.h
new file mode 100644
index 0000000000..2eb337cb54
--- /dev/null
+++ b/src/secp256k1/src/int128_struct_impl.h
@@ -0,0 +1,199 @@
+#ifndef SECP256K1_INT128_STRUCT_IMPL_H
+#define SECP256K1_INT128_STRUCT_IMPL_H
+
+#include "int128.h"
+
+#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */
+# include <intrin.h>
+# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
+/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications.
+ (Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64,
+ which supports both __(u)mulh and _umul128.) */
+# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
+# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.")
+# endif
+static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
+ *hi = __umulh(a, b);
+ return a * b;
+}
+
+static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
+ *hi = __mulh(a, b);
+ return (uint64_t)a * (uint64_t)b;
+}
+# else
+/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */
+# define secp256k1_umul128 _umul128
+# define secp256k1_mul128 _mul128
+# endif
+#else
+/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */
+static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
+ uint64_t lh = (uint32_t)a * (b >> 32);
+ uint64_t hl = (a >> 32) * (uint32_t)b;
+ uint64_t hh = (a >> 32) * (b >> 32);
+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
+ *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
+ return (mid34 << 32) + (uint32_t)ll;
+}
+
+static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
+ int64_t lh = (uint32_t)a * (b >> 32);
+ int64_t hl = (a >> 32) * (uint32_t)b;
+ int64_t hh = (a >> 32) * (b >> 32);
+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
+ *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
+ return (mid34 << 32) + (uint32_t)ll;
+}
+#endif
+
+static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
+ r->hi = hi;
+ r->lo = lo;
+}
+
+static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
+ r->lo = secp256k1_umul128(a, b, &r->hi);
+}
+
+static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
+ uint64_t lo, hi;
+ lo = secp256k1_umul128(a, b, &hi);
+ r->lo += lo;
+ r->hi += hi + (r->lo < lo);
+}
+
+static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) {
+ r->lo += a;
+ r->hi += r->lo < a;
+}
+
+/* Unsigned (logical) right shift.
+ * Non-constant time in n.
+ */
+static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) {
+ VERIFY_CHECK(n < 128);
+ if (n >= 64) {
+ r->lo = r->hi >> (n-64);
+ r->hi = 0;
+ } else if (n > 0) {
+ r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
+ r->hi >>= n;
+ }
+}
+
+static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) {
+ return a->lo;
+}
+
+static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) {
+ return a->hi;
+}
+
+static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) {
+ r->hi = 0;
+ r->lo = a;
+}
+
+static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) {
+ VERIFY_CHECK(n < 128);
+ return n >= 64 ? r->hi >> (n - 64) == 0
+ : r->hi == 0 && r->lo >> n == 0;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
+ r->hi = hi;
+ r->lo = lo;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
+ int64_t hi;
+ r->lo = (uint64_t)secp256k1_mul128(a, b, &hi);
+ r->hi = (uint64_t)hi;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
+ int64_t hi;
+ uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
+ r->lo += lo;
+ hi += r->lo < lo;
+ /* Verify no overflow.
+ * If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set),
+ * then we require that the resulting value also be positive (the sign bit is not set).
+ * Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1).
+ */
+ VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu));
+ /* Verify no underflow.
+ * If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set),
+ * then we require that the resulting value also be negative (the sign bit is set).
+ */
+ VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu));
+ r->hi += hi;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
+ int64_t hi;
+ uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
+ hi += r->lo < lo;
+ /* Verify no overflow.
+ * If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set),
+ * then we require that the resulting value also be positive (the sign bit is not set).
+ */
+ VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu));
+ /* Verify no underflow.
+ * If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set),
+ * then we require that the resulting value also be negative (the sign bit is set).
+ */
+ VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu));
+ r->hi -= hi;
+ r->lo -= lo;
+}
+
+static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) {
+ secp256k1_i128_mul(r, a, d);
+ secp256k1_i128_dissip_mul(r, b, c);
+}
+
+/* Signed (arithmetic) right shift.
+ * Non-constant time in n.
+ */
+static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) {
+ VERIFY_CHECK(n < 128);
+ if (n >= 64) {
+ r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64));
+ r->hi = (uint64_t)((int64_t)(r->hi) >> 63);
+ } else if (n > 0) {
+ r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
+ r->hi = (uint64_t)((int64_t)(r->hi) >> n);
+ }
+}
+
+static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
+ return a->lo;
+}
+
+static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
+ /* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */
+ VERIFY_CHECK(a->hi == -(a->lo >> 63));
+ return (int64_t)secp256k1_i128_to_u64(a);
+}
+
+static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
+ r->hi = (uint64_t)(a >> 63);
+ r->lo = (uint64_t)a;
+}
+
+static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) {
+ return a->hi == b->hi && a->lo == b->lo;
+}
+
+static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) {
+ VERIFY_CHECK(n < 127);
+ VERIFY_CHECK(sign == 1 || sign == -1);
+ return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0
+ : r->hi == (uint64_t)((sign - 1) >> 1) && r->lo == (uint64_t)sign << n;
+}
+
+#endif
diff --git a/src/secp256k1/src/modinv32.h b/src/secp256k1/src/modinv32.h
index 0efdda9ab5..846c642f8c 100644
--- a/src/secp256k1/src/modinv32.h
+++ b/src/secp256k1/src/modinv32.h
@@ -7,10 +7,6 @@
#ifndef SECP256K1_MODINV32_H
#define SECP256K1_MODINV32_H
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
#include "util.h"
/* A signed 30-bit limb representation of integers.
@@ -39,4 +35,9 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
/* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */
static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
+/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus
+ * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result
+ * cannot be computed. */
+static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
+
#endif /* SECP256K1_MODINV32_H */
diff --git a/src/secp256k1/src/modinv32_impl.h b/src/secp256k1/src/modinv32_impl.h
index 661c5fc04c..643750560e 100644
--- a/src/secp256k1/src/modinv32_impl.h
+++ b/src/secp256k1/src/modinv32_impl.h
@@ -232,6 +232,21 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
return zeta;
}
+/* inv256[i] = -(2*i+1)^-1 (mod 256) */
+static const uint8_t secp256k1_modinv32_inv256[128] = {
+ 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
+ 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
+ 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89,
+ 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61,
+ 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9,
+ 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91,
+ 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9,
+ 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1,
+ 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19,
+ 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1,
+ 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01
+};
+
/* Compute the transition matrix and eta for 30 divsteps (variable time).
*
* Input: eta: initial eta
@@ -243,21 +258,6 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
* Implements the divsteps_n_matrix_var function from the explanation.
*/
static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) {
- /* inv256[i] = -(2*i+1)^-1 (mod 256) */
- static const uint8_t inv256[128] = {
- 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
- 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
- 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89,
- 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61,
- 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9,
- 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91,
- 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9,
- 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1,
- 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19,
- 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1,
- 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01
- };
-
/* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */
uint32_t u = 1, v = 0, q = 0, r = 1;
uint32_t f = f0, g = g0, m;
@@ -297,7 +297,7 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint
VERIFY_CHECK(limit > 0 && limit <= 30);
m = (UINT32_MAX >> (32 - limit)) & 255U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
- w = (g * inv256[(f >> 1) & 127]) & m;
+ w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
/* Do so. */
g += f * w;
q += u * w;
@@ -317,6 +317,86 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint
return eta;
}
+/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track
+ * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because
+ * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
+ *
+ * Input: eta: initial eta
+ * f0: bottom limb of initial f
+ * g0: bottom limb of initial g
+ * Output: t: transition matrix
+ * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
+ * by applying the returned transformation matrix to it. The other bits of *jacp may
+ * change, but are meaningless.
+ * Return: final eta
+ */
+static int32_t secp256k1_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t, int *jacp) {
+ /* Transformation matrix. */
+ uint32_t u = 1, v = 0, q = 0, r = 1;
+ uint32_t f = f0, g = g0, m;
+ uint16_t w;
+ int i = 30, limit, zeros;
+ int jac = *jacp;
+
+ for (;;) {
+ /* Use a sentinel bit to count zeros only up to i. */
+ zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i));
+ /* Perform zeros divsteps at once; they all just divide g by two. */
+ g >>= zeros;
+ u <<= zeros;
+ v <<= zeros;
+ eta -= zeros;
+ i -= zeros;
+ /* Update the bottom bit of jac: when dividing g by an odd power of 2,
+ * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
+ jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
+ /* We're done once we've done 30 posdivsteps. */
+ if (i == 0) break;
+ VERIFY_CHECK((f & 1) == 1);
+ VERIFY_CHECK((g & 1) == 1);
+ VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i));
+ VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i));
+ /* If eta is negative, negate it and replace f,g with g,f. */
+ if (eta < 0) {
+ uint32_t tmp;
+ eta = -eta;
+ /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
+ * if both f and g are 3 mod 4. */
+ jac ^= ((f & g) >> 1);
+ tmp = f; f = g; g = tmp;
+ tmp = u; u = q; q = tmp;
+ tmp = v; v = r; r = tmp;
+ }
+ /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more
+ * than i can be cancelled out (as we'd be done before that point), and no more than eta+1
+ * can be done as its sign will flip once that happens. */
+ limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
+ /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */
+ VERIFY_CHECK(limit > 0 && limit <= 30);
+ m = (UINT32_MAX >> (32 - limit)) & 255U;
+ /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
+ w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
+ /* Do so. */
+ g += f * w;
+ q += u * w;
+ r += v * w;
+ VERIFY_CHECK((g & m) == 0);
+ }
+ /* Return data in t and return value. */
+ t->u = (int32_t)u;
+ t->v = (int32_t)v;
+ t->q = (int32_t)q;
+ t->r = (int32_t)r;
+ /* The determinant of t must be a power of two. This guarantees that multiplication with t
+ * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
+ * will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
+ * the aggregate of 30 of them will have determinant 2^30 or -2^30. */
+ VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 ||
+ (int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30));
+ *jacp = jac;
+ return eta;
+}
+
/* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps.
*
* On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range
@@ -335,10 +415,8 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
- VERIFY_CHECK((labs(u) + labs(v)) >= 0); /* |u|+|v| doesn't overflow */
- VERIFY_CHECK((labs(q) + labs(r)) >= 0); /* |q|+|r| doesn't overflow */
- VERIFY_CHECK((labs(u) + labs(v)) <= M30 + 1); /* |u|+|v| <= 2^30 */
- VERIFY_CHECK((labs(q) + labs(r)) <= M30 + 1); /* |q|+|r| <= 2^30 */
+ VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */
+ VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */
#endif
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d->v[8] >> 31;
@@ -584,4 +662,74 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
*x = d;
}
+/* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1.
+ * In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */
+#ifdef VERIFY
+#define JACOBI32_ITERATIONS 25
+#else
+#define JACOBI32_ITERATIONS 50
+#endif
+
+/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */
+static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) {
+ /* Start with f=modulus, g=x, eta=-1. */
+ secp256k1_modinv32_signed30 f = modinfo->modulus;
+ secp256k1_modinv32_signed30 g = *x;
+ int j, len = 9;
+ int32_t eta = -1; /* eta = -delta; delta is initially 1 */
+ int32_t cond, fn, gn;
+ int jac = 0;
+ int count;
+
+ /* The input limbs must all be non-negative. */
+ VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0);
+
+ /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we
+ * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or
+ * time out). */
+ VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8]) != 0);
+
+ for (count = 0; count < JACOBI32_ITERATIONS; ++count) {
+ /* Compute transition matrix and new eta after 30 posdivsteps. */
+ secp256k1_modinv32_trans2x2 t;
+ eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac);
+ /* Update f,g using that transition matrix. */
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
+#endif
+ secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
+ /* If the bottom limb of f is 1, there is a chance that f=1. */
+ if (f.v[0] == 1) {
+ cond = 0;
+ /* Check if the other limbs are also 0. */
+ for (j = 1; j < len; ++j) {
+ cond |= f.v[j];
+ }
+ /* If so, we're done. If f=1, the Jacobi symbol (g | f)=1. */
+ if (cond == 0) return 1 - 2*(jac & 1);
+ }
+
+ /* Determine if len>1 and limb (len-1) of both f and g is 0. */
+ fn = f.v[len - 1];
+ gn = g.v[len - 1];
+ cond = ((int32_t)len - 2) >> 31;
+ cond |= fn;
+ cond |= gn;
+ /* If so, reduce length. */
+ if (cond == 0) --len;
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
+#endif
+ }
+
+ /* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */
+ return 0;
+}
+
#endif /* SECP256K1_MODINV32_IMPL_H */
diff --git a/src/secp256k1/src/modinv64.h b/src/secp256k1/src/modinv64.h
index da506dfa9f..f4208e6c23 100644
--- a/src/secp256k1/src/modinv64.h
+++ b/src/secp256k1/src/modinv64.h
@@ -7,10 +7,6 @@
#ifndef SECP256K1_MODINV64_H
#define SECP256K1_MODINV64_H
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
#include "util.h"
#ifndef SECP256K1_WIDEMUL_INT128
@@ -43,4 +39,9 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
/* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */
static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
+/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus
+ * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result
+ * cannot be computed. */
+static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
+
#endif /* SECP256K1_MODINV64_H */
diff --git a/src/secp256k1/src/modinv64_impl.h b/src/secp256k1/src/modinv64_impl.h
index 0743a9c821..e33727d385 100644
--- a/src/secp256k1/src/modinv64_impl.h
+++ b/src/secp256k1/src/modinv64_impl.h
@@ -7,10 +7,9 @@
#ifndef SECP256K1_MODINV64_IMPL_H
#define SECP256K1_MODINV64_IMPL_H
+#include "int128.h"
#include "modinv64.h"
-#include "util.h"
-
/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and
* modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
*
@@ -18,6 +17,15 @@
* implementation for N=62, using 62-bit signed limbs represented as int64_t.
*/
+/* Data type for transition matrices (see section 3 of explanation).
+ *
+ * t = [ u v ]
+ * [ q r ]
+ */
+typedef struct {
+ int64_t u, v, q, r;
+} secp256k1_modinv64_trans2x2;
+
#ifdef VERIFY
/* Helper function to compute the absolute value of an int64_t.
* (we don't use abs/labs/llabs as it depends on the int sizes). */
@@ -31,16 +39,18 @@ static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}};
/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */
static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) {
- const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
- int128_t c = 0;
+ const uint64_t M62 = UINT64_MAX >> 2;
+ secp256k1_int128 c, d;
int i;
+ secp256k1_i128_from_i64(&c, 0);
for (i = 0; i < 4; ++i) {
- if (i < alen) c += (int128_t)a->v[i] * factor;
- r->v[i] = (int64_t)c & M62; c >>= 62;
+ if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor);
+ r->v[i] = secp256k1_i128_to_u64(&c) & M62; secp256k1_i128_rshift(&c, 62);
}
- if (4 < alen) c += (int128_t)a->v[4] * factor;
- VERIFY_CHECK(c == (int64_t)c);
- r->v[4] = (int64_t)c;
+ if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor);
+ secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c));
+ VERIFY_CHECK(secp256k1_i128_eq_var(&c, &d));
+ r->v[4] = secp256k1_i128_to_i64(&c);
}
/* Return -1 for a<b*factor, 0 for a==b*factor, 1 for a>b*factor. A has alen limbs; b has 5. */
@@ -60,6 +70,15 @@ static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, i
}
return 0;
}
+
+/* Check if the determinant of t is equal to 1 << n. If abs, check if |det t| == 1 << n. */
+static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n, int abs) {
+ secp256k1_int128 a;
+ secp256k1_i128_det(&a, t->u, t->v, t->q, t->r);
+ if (secp256k1_i128_check_pow2(&a, n, 1)) return 1;
+ if (abs && secp256k1_i128_check_pow2(&a, n, -1)) return 1;
+ return 0;
+}
#endif
/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus
@@ -136,15 +155,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6
#endif
}
-/* Data type for transition matrices (see section 3 of explanation).
- *
- * t = [ u v ]
- * [ q r ]
- */
-typedef struct {
- int64_t u, v, q, r;
-} secp256k1_modinv64_trans2x2;
-
/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)).
* Note that the transformation matrix is scaled by 2^62 and not 2^59.
*
@@ -203,13 +213,15 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
+#ifdef VERIFY
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 59 of them will have determinant 2^59. Multiplying with the initial
* 8*identity (which has determinant 2^6) means the overall outputs has determinant
* 2^65. */
- VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 65);
+ VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0));
+#endif
return zeta;
}
@@ -256,7 +268,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
tmp = v; v = r; r = -tmp;
/* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
* out (as we'd be done before that point), and no more than eta+1 can be done as its
- * will flip again once that happens. */
+ * sign will flip again once that happens. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
VERIFY_CHECK(limit > 0 && limit <= 62);
/* m is a mask for the bottom min(limit, 6) bits. */
@@ -286,11 +298,105 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
+#ifdef VERIFY
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 62 of them will have determinant 2^62. */
- VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 62);
+ VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0));
+#endif
+ return eta;
+}
+
+/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track
+ * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because
+ * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
+ *
+ * Input: eta: initial eta
+ * f0: bottom limb of initial f
+ * g0: bottom limb of initial g
+ * Output: t: transition matrix
+ * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
+ * by applying the returned transformation matrix to it. The other bits of *jacp may
+ * change, but are meaningless.
+ * Return: final eta
+ */
+static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t, int *jacp) {
+ /* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */
+ uint64_t u = 1, v = 0, q = 0, r = 1;
+ uint64_t f = f0, g = g0, m;
+ uint32_t w;
+ int i = 62, limit, zeros;
+ int jac = *jacp;
+
+ for (;;) {
+ /* Use a sentinel bit to count zeros only up to i. */
+ zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i));
+ /* Perform zeros divsteps at once; they all just divide g by two. */
+ g >>= zeros;
+ u <<= zeros;
+ v <<= zeros;
+ eta -= zeros;
+ i -= zeros;
+ /* Update the bottom bit of jac: when dividing g by an odd power of 2,
+ * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
+ jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
+ /* We're done once we've done 62 posdivsteps. */
+ if (i == 0) break;
+ VERIFY_CHECK((f & 1) == 1);
+ VERIFY_CHECK((g & 1) == 1);
+ VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i));
+ VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i));
+ /* If eta is negative, negate it and replace f,g with g,f. */
+ if (eta < 0) {
+ uint64_t tmp;
+ eta = -eta;
+ tmp = f; f = g; g = tmp;
+ tmp = u; u = q; q = tmp;
+ tmp = v; v = r; r = tmp;
+ /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
+ * if both f and g are 3 mod 4. */
+ jac ^= ((f & g) >> 1);
+ /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
+ * out (as we'd be done before that point), and no more than eta+1 can be done as its
+ * sign will flip again once that happens. */
+ limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
+ VERIFY_CHECK(limit > 0 && limit <= 62);
+ /* m is a mask for the bottom min(limit, 6) bits. */
+ m = (UINT64_MAX >> (64 - limit)) & 63U;
+ /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6)
+ * bits. */
+ w = (f * g * (f * f - 2)) & m;
+ } else {
+ /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as
+ * eta tends to be smaller here. */
+ limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
+ VERIFY_CHECK(limit > 0 && limit <= 62);
+ /* m is a mask for the bottom min(limit, 4) bits. */
+ m = (UINT64_MAX >> (64 - limit)) & 15U;
+ /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4)
+ * bits. */
+ w = f + (((f + 1) & 4) << 1);
+ w = (-w * g) & m;
+ }
+ g += f * w;
+ q += u * w;
+ r += v * w;
+ VERIFY_CHECK((g & m) == 0);
+ }
+ /* Return data in t and return value. */
+ t->u = (int64_t)u;
+ t->v = (int64_t)v;
+ t->q = (int64_t)q;
+ t->r = (int64_t)r;
+#ifdef VERIFY
+ /* The determinant of t must be a power of two. This guarantees that multiplication with t
+ * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
+ * will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
+ * the aggregate of 62 of them will have determinant 2^62 or -2^62. */
+ VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1));
+#endif
+ *jacp = jac;
return eta;
}
@@ -302,21 +408,19 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
* This implements the update_de function from the explanation.
*/
static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) {
- const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
+ const uint64_t M62 = UINT64_MAX >> 2;
const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4];
const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4];
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int64_t md, me, sd, se;
- int128_t cd, ce;
+ secp256k1_int128 cd, ce;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
- VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) >= 0); /* |u|+|v| doesn't overflow */
- VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) >= 0); /* |q|+|r| doesn't overflow */
- VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= M62 + 1); /* |u|+|v| <= 2^62 */
- VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= M62 + 1); /* |q|+|r| <= 2^62 */
+ VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */
+ VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */
#endif
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d4 >> 63;
@@ -324,54 +428,64 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
md = (u & sd) + (v & se);
me = (q & sd) + (r & se);
/* Begin computing t*[d,e]. */
- cd = (int128_t)u * d0 + (int128_t)v * e0;
- ce = (int128_t)q * d0 + (int128_t)r * e0;
+ secp256k1_i128_mul(&cd, u, d0);
+ secp256k1_i128_accum_mul(&cd, v, e0);
+ secp256k1_i128_mul(&ce, q, d0);
+ secp256k1_i128_accum_mul(&ce, r, e0);
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */
- md -= (modinfo->modulus_inv62 * (uint64_t)cd + md) & M62;
- me -= (modinfo->modulus_inv62 * (uint64_t)ce + me) & M62;
+ md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62;
+ me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62;
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
- cd += (int128_t)modinfo->modulus.v[0] * md;
- ce += (int128_t)modinfo->modulus.v[0] * me;
+ secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md);
+ secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me);
/* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */
- VERIFY_CHECK(((int64_t)cd & M62) == 0); cd >>= 62;
- VERIFY_CHECK(((int64_t)ce & M62) == 0); ce >>= 62;
+ VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
+ VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
/* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */
- cd += (int128_t)u * d1 + (int128_t)v * e1;
- ce += (int128_t)q * d1 + (int128_t)r * e1;
+ secp256k1_i128_accum_mul(&cd, u, d1);
+ secp256k1_i128_accum_mul(&cd, v, e1);
+ secp256k1_i128_accum_mul(&ce, q, d1);
+ secp256k1_i128_accum_mul(&ce, r, e1);
if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */
- cd += (int128_t)modinfo->modulus.v[1] * md;
- ce += (int128_t)modinfo->modulus.v[1] * me;
+ secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md);
+ secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me);
}
- d->v[0] = (int64_t)cd & M62; cd >>= 62;
- e->v[0] = (int64_t)ce & M62; ce >>= 62;
+ d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
+ e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */
- cd += (int128_t)u * d2 + (int128_t)v * e2;
- ce += (int128_t)q * d2 + (int128_t)r * e2;
+ secp256k1_i128_accum_mul(&cd, u, d2);
+ secp256k1_i128_accum_mul(&cd, v, e2);
+ secp256k1_i128_accum_mul(&ce, q, d2);
+ secp256k1_i128_accum_mul(&ce, r, e2);
if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */
- cd += (int128_t)modinfo->modulus.v[2] * md;
- ce += (int128_t)modinfo->modulus.v[2] * me;
+ secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md);
+ secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me);
}
- d->v[1] = (int64_t)cd & M62; cd >>= 62;
- e->v[1] = (int64_t)ce & M62; ce >>= 62;
+ d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
+ e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */
- cd += (int128_t)u * d3 + (int128_t)v * e3;
- ce += (int128_t)q * d3 + (int128_t)r * e3;
+ secp256k1_i128_accum_mul(&cd, u, d3);
+ secp256k1_i128_accum_mul(&cd, v, e3);
+ secp256k1_i128_accum_mul(&ce, q, d3);
+ secp256k1_i128_accum_mul(&ce, r, e3);
if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */
- cd += (int128_t)modinfo->modulus.v[3] * md;
- ce += (int128_t)modinfo->modulus.v[3] * me;
+ secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md);
+ secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me);
}
- d->v[2] = (int64_t)cd & M62; cd >>= 62;
- e->v[2] = (int64_t)ce & M62; ce >>= 62;
+ d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
+ e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */
- cd += (int128_t)u * d4 + (int128_t)v * e4;
- ce += (int128_t)q * d4 + (int128_t)r * e4;
- cd += (int128_t)modinfo->modulus.v[4] * md;
- ce += (int128_t)modinfo->modulus.v[4] * me;
- d->v[3] = (int64_t)cd & M62; cd >>= 62;
- e->v[3] = (int64_t)ce & M62; ce >>= 62;
+ secp256k1_i128_accum_mul(&cd, u, d4);
+ secp256k1_i128_accum_mul(&cd, v, e4);
+ secp256k1_i128_accum_mul(&ce, q, d4);
+ secp256k1_i128_accum_mul(&ce, r, e4);
+ secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md);
+ secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me);
+ d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
+ e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
- d->v[4] = (int64_t)cd;
- e->v[4] = (int64_t)ce;
+ d->v[4] = secp256k1_i128_to_i64(&cd);
+ e->v[4] = secp256k1_i128_to_i64(&ce);
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
@@ -385,40 +499,50 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
* This implements the update_fg function from the explanation.
*/
static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
- const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
+ const uint64_t M62 = UINT64_MAX >> 2;
const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4];
const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4];
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
- int128_t cf, cg;
+ secp256k1_int128 cf, cg;
/* Start computing t*[f,g]. */
- cf = (int128_t)u * f0 + (int128_t)v * g0;
- cg = (int128_t)q * f0 + (int128_t)r * g0;
+ secp256k1_i128_mul(&cf, u, f0);
+ secp256k1_i128_accum_mul(&cf, v, g0);
+ secp256k1_i128_mul(&cg, q, f0);
+ secp256k1_i128_accum_mul(&cg, r, g0);
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
- VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62;
- VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62;
+ VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
+ VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
/* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */
- cf += (int128_t)u * f1 + (int128_t)v * g1;
- cg += (int128_t)q * f1 + (int128_t)r * g1;
- f->v[0] = (int64_t)cf & M62; cf >>= 62;
- g->v[0] = (int64_t)cg & M62; cg >>= 62;
+ secp256k1_i128_accum_mul(&cf, u, f1);
+ secp256k1_i128_accum_mul(&cf, v, g1);
+ secp256k1_i128_accum_mul(&cg, q, f1);
+ secp256k1_i128_accum_mul(&cg, r, g1);
+ f->v[0] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+ g->v[0] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 2 of t*[f,g], and store it as output limb 1. */
- cf += (int128_t)u * f2 + (int128_t)v * g2;
- cg += (int128_t)q * f2 + (int128_t)r * g2;
- f->v[1] = (int64_t)cf & M62; cf >>= 62;
- g->v[1] = (int64_t)cg & M62; cg >>= 62;
+ secp256k1_i128_accum_mul(&cf, u, f2);
+ secp256k1_i128_accum_mul(&cf, v, g2);
+ secp256k1_i128_accum_mul(&cg, q, f2);
+ secp256k1_i128_accum_mul(&cg, r, g2);
+ f->v[1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+ g->v[1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 3 of t*[f,g], and store it as output limb 2. */
- cf += (int128_t)u * f3 + (int128_t)v * g3;
- cg += (int128_t)q * f3 + (int128_t)r * g3;
- f->v[2] = (int64_t)cf & M62; cf >>= 62;
- g->v[2] = (int64_t)cg & M62; cg >>= 62;
+ secp256k1_i128_accum_mul(&cf, u, f3);
+ secp256k1_i128_accum_mul(&cf, v, g3);
+ secp256k1_i128_accum_mul(&cg, q, f3);
+ secp256k1_i128_accum_mul(&cg, r, g3);
+ f->v[2] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+ g->v[2] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 4 of t*[f,g], and store it as output limb 3. */
- cf += (int128_t)u * f4 + (int128_t)v * g4;
- cg += (int128_t)q * f4 + (int128_t)r * g4;
- f->v[3] = (int64_t)cf & M62; cf >>= 62;
- g->v[3] = (int64_t)cg & M62; cg >>= 62;
+ secp256k1_i128_accum_mul(&cf, u, f4);
+ secp256k1_i128_accum_mul(&cf, v, g4);
+ secp256k1_i128_accum_mul(&cg, q, f4);
+ secp256k1_i128_accum_mul(&cg, r, g4);
+ f->v[3] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+ g->v[3] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* What remains is limb 5 of t*[f,g]; store it as output limb 4. */
- f->v[4] = (int64_t)cf;
- g->v[4] = (int64_t)cg;
+ f->v[4] = secp256k1_i128_to_i64(&cf);
+ g->v[4] = secp256k1_i128_to_i64(&cg);
}
/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps.
@@ -428,33 +552,37 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp
* This implements the update_fg function from the explanation.
*/
static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
- const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
+ const uint64_t M62 = UINT64_MAX >> 2;
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int64_t fi, gi;
- int128_t cf, cg;
+ secp256k1_int128 cf, cg;
int i;
VERIFY_CHECK(len > 0);
/* Start computing t*[f,g]. */
fi = f->v[0];
gi = g->v[0];
- cf = (int128_t)u * fi + (int128_t)v * gi;
- cg = (int128_t)q * fi + (int128_t)r * gi;
+ secp256k1_i128_mul(&cf, u, fi);
+ secp256k1_i128_accum_mul(&cf, v, gi);
+ secp256k1_i128_mul(&cg, q, fi);
+ secp256k1_i128_accum_mul(&cg, r, gi);
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
- VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62;
- VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62;
+ VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
+ VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
* down by 62 bits). */
for (i = 1; i < len; ++i) {
fi = f->v[i];
gi = g->v[i];
- cf += (int128_t)u * fi + (int128_t)v * gi;
- cg += (int128_t)q * fi + (int128_t)r * gi;
- f->v[i - 1] = (int64_t)cf & M62; cf >>= 62;
- g->v[i - 1] = (int64_t)cg & M62; cg >>= 62;
+ secp256k1_i128_accum_mul(&cf, u, fi);
+ secp256k1_i128_accum_mul(&cf, v, gi);
+ secp256k1_i128_accum_mul(&cg, q, fi);
+ secp256k1_i128_accum_mul(&cg, r, gi);
+ f->v[i - 1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+ g->v[i - 1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
}
/* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
- f->v[len - 1] = (int64_t)cf;
- g->v[len - 1] = (int64_t)cg;
+ f->v[len - 1] = secp256k1_i128_to_i64(&cf);
+ g->v[len - 1] = secp256k1_i128_to_i64(&cg);
}
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */
@@ -590,4 +718,74 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
*x = d;
}
+/* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1.
+ * In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */
+#ifdef VERIFY
+#define JACOBI64_ITERATIONS 12
+#else
+#define JACOBI64_ITERATIONS 25
+#endif
+
+/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */
+static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) {
+ /* Start with f=modulus, g=x, eta=-1. */
+ secp256k1_modinv64_signed62 f = modinfo->modulus;
+ secp256k1_modinv64_signed62 g = *x;
+ int j, len = 5;
+ int64_t eta = -1; /* eta = -delta; delta is initially 1 */
+ int64_t cond, fn, gn;
+ int jac = 0;
+ int count;
+
+ /* The input limbs must all be non-negative. */
+ VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0);
+
+ /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we
+ * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or
+ * time out). */
+ VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4]) != 0);
+
+ for (count = 0; count < JACOBI64_ITERATIONS; ++count) {
+ /* Compute transition matrix and new eta after 62 posdivsteps. */
+ secp256k1_modinv64_trans2x2 t;
+ eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac);
+ /* Update f,g using that transition matrix. */
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
+#endif
+ secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
+ /* If the bottom limb of f is 1, there is a chance that f=1. */
+ if (f.v[0] == 1) {
+ cond = 0;
+ /* Check if the other limbs are also 0. */
+ for (j = 1; j < len; ++j) {
+ cond |= f.v[j];
+ }
+ /* If so, we're done. When f=1, the Jacobi symbol (g | f)=1. */
+ if (cond == 0) return 1 - 2*(jac & 1);
+ }
+
+ /* Determine if len>1 and limb (len-1) of both f and g is 0. */
+ fn = f.v[len - 1];
+ gn = g.v[len - 1];
+ cond = ((int64_t)len - 2) >> 63;
+ cond |= fn;
+ cond |= gn;
+ /* If so, reduce length. */
+ if (cond == 0) --len;
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
+#endif
+ }
+
+ /* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */
+ return 0;
+}
+
#endif /* SECP256K1_MODINV64_IMPL_H */
diff --git a/src/secp256k1/src/modules/ecdh/bench_impl.h b/src/secp256k1/src/modules/ecdh/bench_impl.h
index 94d833462f..c23aaa94d1 100644
--- a/src/secp256k1/src/modules/ecdh/bench_impl.h
+++ b/src/secp256k1/src/modules/ecdh/bench_impl.h
@@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_ECDH_BENCH_H
#define SECP256K1_MODULE_ECDH_BENCH_H
-#include "../include/secp256k1_ecdh.h"
+#include "../../../include/secp256k1_ecdh.h"
typedef struct {
secp256k1_context *ctx;
@@ -42,7 +42,7 @@ static void bench_ecdh(void* arg, int iters) {
}
}
-void run_ecdh_bench(int iters, int argc, char** argv) {
+static void run_ecdh_bench(int iters, int argc, char** argv) {
bench_ecdh_data data;
int d = argc == 1;
diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h
index 10b7075c38..fa6f232227 100644
--- a/src/secp256k1/src/modules/ecdh/tests_impl.h
+++ b/src/secp256k1/src/modules/ecdh/tests_impl.h
@@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
#define SECP256K1_MODULE_ECDH_TESTS_H
-int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
+static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
(void)output;
(void)x;
(void)y;
@@ -15,7 +15,7 @@ int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x,
return 0;
}
-int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
+static int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
(void)data;
/* Save x and y as uncompressed public key */
output[0] = 0x04;
@@ -24,9 +24,9 @@ int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, con
return 1;
}
-void test_ecdh_api(void) {
+static void test_ecdh_api(void) {
/* Setup context that just counts errors */
- secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_pubkey point;
unsigned char res[32];
unsigned char s_one[32] = { 0 };
@@ -53,14 +53,14 @@ void test_ecdh_api(void) {
secp256k1_context_destroy(tctx);
}
-void test_ecdh_generator_basepoint(void) {
+static void test_ecdh_generator_basepoint(void) {
unsigned char s_one[32] = { 0 };
secp256k1_pubkey point[2];
int i;
s_one[31] = 1;
/* Check against pubkey creation when the basepoint is the generator */
- for (i = 0; i < 2 * count; ++i) {
+ for (i = 0; i < 2 * COUNT; ++i) {
secp256k1_sha256 sha;
unsigned char s_b32[32];
unsigned char output_ecdh[65];
@@ -72,20 +72,20 @@ void test_ecdh_generator_basepoint(void) {
random_scalar_order(&s);
secp256k1_scalar_get_b32(s_b32, &s);
- CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1);
- CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &point[1], s_b32) == 1);
/* compute using ECDH function with custom hash function */
- CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1);
+ CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1);
/* compute "explicitly" */
- CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1);
/* compare */
CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0);
/* compute using ECDH function with default hash function */
- CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
/* compute "explicitly" */
- CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, point_ser, point_ser_len);
secp256k1_sha256_finalize(&sha, output_ser);
@@ -94,7 +94,7 @@ void test_ecdh_generator_basepoint(void) {
}
}
-void test_bad_scalar(void) {
+static void test_bad_scalar(void) {
unsigned char s_zero[32] = { 0 };
unsigned char s_overflow[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -110,21 +110,21 @@ void test_bad_scalar(void) {
/* Create random point */
random_scalar_order(&rand);
secp256k1_scalar_get_b32(s_rand, &rand);
- CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1);
/* Try to multiply it by bad values */
- CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0);
- CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 0);
/* ...and a good one */
s_overflow[31] -= 1;
- CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 1);
/* Hash function failure results in ecdh failure */
- CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
+ CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
}
/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */
-void test_result_basepoint(void) {
+static void test_result_basepoint(void) {
secp256k1_pubkey point;
secp256k1_scalar rand;
unsigned char s[32];
@@ -136,26 +136,26 @@ void test_result_basepoint(void) {
unsigned char s_one[32] = { 0 };
s_one[31] = 1;
- CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_one) == 1);
- CHECK(secp256k1_ecdh(ctx, out_base, &point, s_one, NULL, NULL) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1);
+ CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1);
- for (i = 0; i < 2 * count; i++) {
+ for (i = 0; i < 2 * COUNT; i++) {
random_scalar_order(&rand);
secp256k1_scalar_get_b32(s, &rand);
secp256k1_scalar_inverse(&rand, &rand);
secp256k1_scalar_get_b32(s_inv, &rand);
- CHECK(secp256k1_ec_pubkey_create(ctx, &point, s) == 1);
- CHECK(secp256k1_ecdh(ctx, out, &point, s_inv, NULL, NULL) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &point, s) == 1);
+ CHECK(secp256k1_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1);
CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0);
- CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_inv) == 1);
- CHECK(secp256k1_ecdh(ctx, out_inv, &point, s, NULL, NULL) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_inv) == 1);
+ CHECK(secp256k1_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1);
CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0);
}
}
-void run_ecdh_tests(void) {
+static void run_ecdh_tests(void) {
test_ecdh_api();
test_ecdh_generator_basepoint();
test_bad_scalar();
diff --git a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h
index d4a2f5bdf4..5ecc90d50f 100644
--- a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h
+++ b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h
@@ -7,8 +7,8 @@
#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
-#include "src/modules/extrakeys/main_impl.h"
#include "../../../include/secp256k1_extrakeys.h"
+#include "main_impl.h"
static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) {
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];
diff --git a/src/secp256k1/src/modules/extrakeys/tests_impl.h b/src/secp256k1/src/modules/extrakeys/tests_impl.h
index c8a99f4466..ae1655923b 100644
--- a/src/secp256k1/src/modules/extrakeys/tests_impl.h
+++ b/src/secp256k1/src/modules/extrakeys/tests_impl.h
@@ -9,14 +9,12 @@
#include "../../../include/secp256k1_extrakeys.h"
-static secp256k1_context* api_test_context(int flags, int *ecount) {
- secp256k1_context *ctx0 = secp256k1_context_create(flags);
+static void set_counting_callbacks(secp256k1_context *ctx0, int *ecount) {
secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount);
secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount);
- return ctx0;
}
-void test_xonly_pubkey(void) {
+static void test_xonly_pubkey(void) {
secp256k1_pubkey pk;
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
secp256k1_ge pk1;
@@ -31,56 +29,53 @@ void test_xonly_pubkey(void) {
int i;
int ecount;
- secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
- secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
- secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
+
+ set_counting_callbacks(CTX, &ecount);
secp256k1_testrand256(sk);
memset(ones32, 0xFF, 32);
secp256k1_testrand256(xy_sk);
- CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
/* Test xonly_pubkey_from_pubkey */
ecount = 0;
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &xonly_pk, &pk_parity, &pk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &xonly_pk, &pk_parity, &pk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_parity, &pk) == 0);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, NULL) == 0);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(ecount == 2);
memset(&pk, 0, sizeof(pk));
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 0);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 0);
CHECK(ecount == 3);
/* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
memset(sk, 0, sizeof(sk));
sk[0] = 1;
- CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0);
CHECK(pk_parity == 0);
/* Choose a secret key such that pubkey and xonly_pubkey are each others
* negation. */
sk[0] = 2;
- CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0);
CHECK(pk_parity == 1);
- secp256k1_pubkey_load(ctx, &pk1, &pk);
- secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk);
+ secp256k1_pubkey_load(CTX, &pk1, &pk);
+ secp256k1_pubkey_load(CTX, &pk2, (secp256k1_pubkey *) &xonly_pk);
CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1);
secp256k1_fe_negate(&y, &pk2.y, 1);
CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1);
/* Test xonly_pubkey_serialize and xonly_pubkey_parse */
ecount = 0;
- CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL) == 0);
CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0);
CHECK(ecount == 2);
{
@@ -88,56 +83,52 @@ void test_xonly_pubkey(void) {
* special casing. */
secp256k1_xonly_pubkey pk_tmp;
memset(&pk_tmp, 0, sizeof(pk_tmp));
- CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &pk_tmp) == 0);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp) == 0);
}
/* pubkey_load called illegal callback */
CHECK(ecount == 3);
- CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1);
ecount = 0;
- CHECK(secp256k1_xonly_pubkey_parse(none, NULL, buf32) == 0);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, NULL, buf32) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, NULL) == 0);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL) == 0);
CHECK(ecount == 2);
/* Serialization and parse roundtrip */
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1);
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk_tmp, buf32) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0);
/* Test parsing invalid field elements */
memset(&xonly_pk, 1, sizeof(xonly_pk));
/* Overflowing field element */
- CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, ones32) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
memset(&xonly_pk, 1, sizeof(xonly_pk));
/* There's no point with x-coordinate 0 on secp256k1 */
- CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, zeros64) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
/* If a random 32-byte string can not be parsed with ec_pubkey_parse
* (because interpreted as X coordinate it does not correspond to a point on
* the curve) then xonly_pubkey_parse should fail as well. */
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
unsigned char rand33[33];
secp256k1_testrand256(&rand33[1]);
rand33[0] = SECP256K1_TAG_PUBKEY_EVEN;
- if (!secp256k1_ec_pubkey_parse(ctx, &pk, rand33, 33)) {
+ if (!secp256k1_ec_pubkey_parse(CTX, &pk, rand33, 33)) {
memset(&xonly_pk, 1, sizeof(xonly_pk));
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 0);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
} else {
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 1);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1);
}
}
CHECK(ecount == 2);
-
- secp256k1_context_destroy(none);
- secp256k1_context_destroy(sign);
- secp256k1_context_destroy(verify);
}
-void test_xonly_pubkey_comparison(void) {
+static void test_xonly_pubkey_comparison(void) {
unsigned char pk1_ser[32] = {
0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11,
0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23
@@ -149,32 +140,31 @@ void test_xonly_pubkey_comparison(void) {
secp256k1_xonly_pubkey pk1;
secp256k1_xonly_pubkey pk2;
int ecount = 0;
- secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
- CHECK(secp256k1_xonly_pubkey_parse(none, &pk1, pk1_ser) == 1);
- CHECK(secp256k1_xonly_pubkey_parse(none, &pk2, pk2_ser) == 1);
+ set_counting_callbacks(CTX, &ecount);
+
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1);
- CHECK(secp256k1_xonly_pubkey_cmp(none, NULL, &pk2) < 0);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0);
CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, NULL) > 0);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0);
CHECK(ecount == 2);
- CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk2) < 0);
- CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk1) > 0);
- CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk1) == 0);
- CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk2) == 0);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0);
CHECK(ecount == 2);
memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */
- CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk2) < 0);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0);
CHECK(ecount == 3);
- CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk1) == 0);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
CHECK(ecount == 5);
- CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk1) > 0);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0);
CHECK(ecount == 6);
-
- secp256k1_context_destroy(none);
}
-void test_xonly_pubkey_tweak(void) {
+static void test_xonly_pubkey_tweak(void) {
unsigned char zeros64[64] = { 0 };
unsigned char overflows[32];
unsigned char sk[32];
@@ -186,50 +176,49 @@ void test_xonly_pubkey_tweak(void) {
int i;
int ecount;
- secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
- secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
- secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
+
+ set_counting_callbacks(CTX, &ecount);
memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak);
secp256k1_testrand256(sk);
- CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
ecount = 0;
- CHECK(secp256k1_xonly_pubkey_tweak_add(none, &output_pk, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &output_pk, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add(verify, NULL, &internal_xonly_pk, tweak) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak) == 0);
CHECK(ecount == 2);
/* NULL internal_xonly_pk zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
- CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, NULL) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL) == 0);
CHECK(ecount == 3);
/* NULL tweak zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
/* Invalid tweak zeroes the output_pk */
- CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
/* A zero tweak is fine */
- CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, zeros64) == 1);
/* Fails if the resulting key was infinity */
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
secp256k1_scalar scalar_tweak;
/* Because sk may be negated before adding, we need to try with tweak =
* sk as well as tweak = -sk. */
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
- CHECK((secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0)
- || (secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0));
+ CHECK((secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, sk) == 0)
+ || (secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0));
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
}
@@ -237,16 +226,12 @@ void test_xonly_pubkey_tweak(void) {
memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
secp256k1_testrand256(tweak);
ecount = 0;
- CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
-
- secp256k1_context_destroy(none);
- secp256k1_context_destroy(sign);
- secp256k1_context_destroy(verify);
}
-void test_xonly_pubkey_tweak_check(void) {
+static void test_xonly_pubkey_tweak_check(void) {
unsigned char zeros64[64] = { 0 };
unsigned char overflows[32];
unsigned char sk[32];
@@ -260,64 +245,59 @@ void test_xonly_pubkey_tweak_check(void) {
unsigned char tweak[32];
int ecount;
- secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
- secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
- secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
+
+ set_counting_callbacks(CTX, &ecount);
memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak);
secp256k1_testrand256(sk);
- CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
ecount = 0;
- CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &output_xonly_pk, &pk_parity, &output_pk) == 1);
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &output_xonly_pk) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(none, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(sign, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
/* invalid pk_parity value */
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, 2, &internal_xonly_pk, tweak) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, NULL, tweak) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
CHECK(ecount == 3);
memset(tweak, 1, sizeof(tweak));
- CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, NULL, &internal_pk) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1);
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk32, &output_xonly_pk) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk32, &output_xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1);
/* Wrong pk_parity */
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0);
/* Wrong public key */
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &internal_xonly_pk) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &internal_xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
/* Overflowing tweak not allowed */
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
- CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
CHECK(ecount == 3);
-
- secp256k1_context_destroy(none);
- secp256k1_context_destroy(sign);
- secp256k1_context_destroy(verify);
}
/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
* additional pubkeys by calling tweak_add. Then verifies every tweak starting
* from the last pubkey. */
#define N_PUBKEYS 32
-void test_xonly_pubkey_tweak_recursive(void) {
+static void test_xonly_pubkey_tweak_recursive(void) {
unsigned char sk[32];
secp256k1_pubkey pk[N_PUBKEYS];
unsigned char pk_serialized[32];
@@ -325,28 +305,28 @@ void test_xonly_pubkey_tweak_recursive(void) {
int i;
secp256k1_testrand256(sk);
- CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pk[0], sk) == 1);
/* Add tweaks */
for (i = 0; i < N_PUBKEYS - 1; i++) {
secp256k1_xonly_pubkey xonly_pk;
memset(tweak[i], i + 1, sizeof(tweak[i]));
- CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i]) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &xonly_pk, tweak[i]) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i]) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &pk[i + 1], &xonly_pk, tweak[i]) == 1);
}
/* Verify tweaks */
for (i = N_PUBKEYS - 1; i > 0; i--) {
secp256k1_xonly_pubkey xonly_pk;
int pk_parity;
- CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk[i]) == 1);
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_serialized, &xonly_pk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i - 1]) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk[i]) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk_serialized, &xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i - 1]) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1);
}
}
#undef N_PUBKEYS
-void test_keypair(void) {
+static void test_keypair(void) {
unsigned char sk[32];
unsigned char sk_tmp[32];
unsigned char zeros96[96] = { 0 };
@@ -356,12 +336,9 @@ void test_keypair(void) {
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
int pk_parity, pk_parity_tmp;
int ecount;
- secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
- secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
- secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
- secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
- secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
+
+ set_counting_callbacks(CTX, &ecount);
+ set_counting_callbacks(STATIC_CTX, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair));
memset(overflows, 0xFF, sizeof(overflows));
@@ -369,107 +346,105 @@ void test_keypair(void) {
/* Test keypair_create */
ecount = 0;
secp256k1_testrand256(sk);
- CHECK(secp256k1_keypair_create(none, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
CHECK(ecount == 0);
- CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
CHECK(ecount == 0);
- CHECK(secp256k1_keypair_create(sign, NULL, sk) == 0);
+ CHECK(secp256k1_keypair_create(CTX, NULL, sk) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_keypair_create(sign, &keypair, NULL) == 0);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, NULL) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(ecount == 2);
- CHECK(secp256k1_keypair_create(sttc, &keypair, sk) == 0);
+ CHECK(secp256k1_keypair_create(STATIC_CTX, &keypair, sk) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(ecount == 3);
/* Invalid secret key */
- CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, zeros96) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
- CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, overflows) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
/* Test keypair_pub */
ecount = 0;
secp256k1_testrand256(sk);
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
- CHECK(secp256k1_keypair_pub(none, NULL, &keypair) == 0);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1);
+ CHECK(secp256k1_keypair_pub(CTX, NULL, &keypair) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_keypair_pub(none, &pk, NULL) == 0);
+ CHECK(secp256k1_keypair_pub(CTX, &pk, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
/* Using an invalid keypair is fine for keypair_pub */
memset(&keypair, 0, sizeof(keypair));
- CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
+ CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
/* keypair holds the same pubkey as pubkey_create */
- CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
- CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_pub(none, &pk_tmp, &keypair) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_pub(CTX, &pk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0);
/** Test keypair_xonly_pub **/
ecount = 0;
secp256k1_testrand256(sk);
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
- CHECK(secp256k1_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1);
- CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
/* Using an invalid keypair will set the xonly_pk to 0 (first reset
* xonly_pk). */
- CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
memset(&keypair, 0, sizeof(keypair));
- CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
CHECK(ecount == 3);
/** keypair holds the same xonly pubkey as pubkey_create **/
- CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
- CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
CHECK(pk_parity == pk_parity_tmp);
/* Test keypair_seckey */
ecount = 0;
secp256k1_testrand256(sk);
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
- CHECK(secp256k1_keypair_sec(none, NULL, &keypair) == 0);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
+ CHECK(secp256k1_keypair_sec(CTX, NULL, &keypair) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_keypair_sec(none, sk_tmp, NULL) == 0);
+ CHECK(secp256k1_keypair_sec(CTX, sk_tmp, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
/* keypair returns the same seckey it got */
- CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0);
/* Using an invalid keypair is fine for keypair_seckey */
memset(&keypair, 0, sizeof(keypair));
- CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
+ CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
- secp256k1_context_destroy(none);
- secp256k1_context_destroy(sign);
- secp256k1_context_destroy(verify);
- secp256k1_context_destroy(sttc);
+ secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
+ secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
}
-void test_keypair_add(void) {
+static void test_keypair_add(void) {
unsigned char sk[32];
secp256k1_keypair keypair;
unsigned char overflows[32];
@@ -477,51 +452,50 @@ void test_keypair_add(void) {
unsigned char tweak[32];
int i;
int ecount = 0;
- secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
- secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
- secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
+
+ set_counting_callbacks(CTX, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair));
secp256k1_testrand256(sk);
secp256k1_testrand256(tweak);
memset(overflows, 0xFF, 32);
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_xonly_tweak_add(none, &keypair, tweak) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_keypair_xonly_tweak_add(sign, &keypair, tweak) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 1);
- CHECK(secp256k1_keypair_xonly_tweak_add(verify, NULL, tweak) == 0);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL) == 0);
CHECK(ecount == 2);
/* This does not set the keypair to zeroes */
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0);
/* Invalid tweak zeroes the keypair */
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, overflows) == 0);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, overflows) == 0);
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
/* A zero tweak is fine */
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, zeros96) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, zeros96) == 1);
/* Fails if the resulting keypair was (sk=0, pk=infinity) */
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
secp256k1_scalar scalar_tweak;
secp256k1_keypair keypair_tmp;
secp256k1_testrand256(sk);
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
memcpy(&keypair_tmp, &keypair, sizeof(keypair));
/* Because sk may be negated before adding, we need to try with tweak =
* sk as well as tweak = -sk. */
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
- CHECK((secp256k1_keypair_xonly_tweak_add(ctx, &keypair, sk) == 0)
- || (secp256k1_keypair_xonly_tweak_add(ctx, &keypair_tmp, tweak) == 0));
+ CHECK((secp256k1_keypair_xonly_tweak_add(CTX, &keypair, sk) == 0)
+ || (secp256k1_keypair_xonly_tweak_add(CTX, &keypair_tmp, tweak) == 0));
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0
|| secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0);
}
@@ -530,23 +504,23 @@ void test_keypair_add(void) {
memset(&keypair, 0, sizeof(keypair));
secp256k1_testrand256(tweak);
ecount = 0;
- CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
/* Only seckey part of keypair invalid */
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
memset(&keypair, 0, 32);
- CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
CHECK(ecount == 2);
/* Only pubkey part of keypair invalid */
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
memset(&keypair.data[32], 0, 64);
- CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
CHECK(ecount == 3);
/* Check that the keypair_tweak_add implementation is correct */
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
- for (i = 0; i < count; i++) {
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ for (i = 0; i < COUNT; i++) {
secp256k1_xonly_pubkey internal_pk;
secp256k1_xonly_pubkey output_pk;
secp256k1_pubkey output_pk_xy;
@@ -556,30 +530,27 @@ void test_keypair_add(void) {
int pk_parity;
secp256k1_testrand256(tweak);
- CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1);
- CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
- CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1);
/* Check that it passes xonly_pubkey_tweak_add_check */
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk32, &output_pk) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk32, pk_parity, &internal_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk32, &output_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk32, pk_parity, &internal_pk, tweak) == 1);
/* Check that the resulting pubkey matches xonly_pubkey_tweak_add */
- CHECK(secp256k1_keypair_pub(ctx, &output_pk_xy, &keypair) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk_expected, &internal_pk, tweak) == 1);
+ CHECK(secp256k1_keypair_pub(CTX, &output_pk_xy, &keypair) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk_expected, &internal_pk, tweak) == 1);
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
/* Check that the secret key in the keypair is tweaked correctly */
- CHECK(secp256k1_keypair_sec(none, sk32, &keypair) == 1);
- CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, sk32) == 1);
+ CHECK(secp256k1_keypair_sec(CTX, sk32, &keypair) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &output_pk_expected, sk32) == 1);
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
}
- secp256k1_context_destroy(none);
- secp256k1_context_destroy(sign);
- secp256k1_context_destroy(verify);
}
-void run_extrakeys_tests(void) {
+static void run_extrakeys_tests(void) {
/* xonly key test cases */
test_xonly_pubkey();
test_xonly_pubkey_tweak();
diff --git a/src/secp256k1/src/modules/recovery/bench_impl.h b/src/secp256k1/src/modules/recovery/bench_impl.h
index 4a9e886910..57108d4524 100644
--- a/src/secp256k1/src/modules/recovery/bench_impl.h
+++ b/src/secp256k1/src/modules/recovery/bench_impl.h
@@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_RECOVERY_BENCH_H
#define SECP256K1_MODULE_RECOVERY_BENCH_H
-#include "../include/secp256k1_recovery.h"
+#include "../../../include/secp256k1_recovery.h"
typedef struct {
secp256k1_context *ctx;
@@ -15,7 +15,7 @@ typedef struct {
unsigned char sig[64];
} bench_recover_data;
-void bench_recover(void* arg, int iters) {
+static void bench_recover(void* arg, int iters) {
int i;
bench_recover_data *data = (bench_recover_data*)arg;
secp256k1_pubkey pubkey;
@@ -36,7 +36,7 @@ void bench_recover(void* arg, int iters) {
}
}
-void bench_recover_setup(void* arg) {
+static void bench_recover_setup(void* arg) {
int i;
bench_recover_data *data = (bench_recover_data*)arg;
@@ -48,11 +48,11 @@ void bench_recover_setup(void* arg) {
}
}
-void run_recovery_bench(int iters, int argc, char** argv) {
+static void run_recovery_bench(int iters, int argc, char** argv) {
bench_recover_data data;
int d = argc == 1;
- data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters);
diff --git a/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h b/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h
index 590a972ed3..6bbc02b9a8 100644
--- a/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h
+++ b/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h
@@ -7,10 +7,10 @@
#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
-#include "src/modules/recovery/main_impl.h"
+#include "main_impl.h"
#include "../../../include/secp256k1_recovery.h"
-void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
+static void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
int i, j, k;
uint64_t iter = 0;
@@ -43,8 +43,7 @@ void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1
(k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER);
/* The recid's second bit is for conveying overflow (R.x value >= group order).
* In the actual secp256k1 this is an astronomically unlikely event, but in the
- * small group used here, it will be the case for all points except the ones where
- * R.x=1 (which the group is specifically selected to have).
+ * small group used here, it will almost certainly be the case for all points.
* Note that this isn't actually useful; full recovery would need to convey
* floor(R.x / group_order), but only one bit is used as that is sufficient
* in the real group. */
@@ -79,7 +78,7 @@ void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1
}
}
-void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) {
+static void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) {
/* This is essentially a copy of test_exhaustive_verify, with recovery added */
int s, r, msg, key;
uint64_t iter = 0;
diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h
index abf62f7f3a..3502c71ffe 100644
--- a/src/secp256k1/src/modules/recovery/tests_impl.h
+++ b/src/secp256k1/src/modules/recovery/tests_impl.h
@@ -28,13 +28,8 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c
return secp256k1_testrand_bits(1);
}
-void test_ecdsa_recovery_api(void) {
+static void test_ecdsa_recovery_api(void) {
/* Setup contexts that just count errors */
- secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
- secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
- secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
- secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
- secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
secp256k1_pubkey pubkey;
secp256k1_pubkey recpubkey;
secp256k1_ecdsa_signature normal_sig;
@@ -50,110 +45,89 @@ void test_ecdsa_recovery_api(void) {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
/* Construct and verify corresponding public key. */
- CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+ CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
/* Check bad contexts and NULLs for signing */
ecount = 0;
- CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_ecdsa_sign_recoverable(sttc, &recsig, message, privkey, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL) == 0);
CHECK(ecount == 4);
/* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
- secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);
+ secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL);
CHECK(ecount == 4);
/* These will all fail, but not in ARG_CHECK way */
- CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);
- CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0);
/* This one will succeed. */
- CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 4);
/* Check signing with a goofy nonce function */
/* Check bad contexts and NULLs for recovery */
ecount = 0;
- CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);
+ CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0);
+ CHECK(secp256k1_ecdsa_recover(CTX, NULL, &recsig, message) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0);
+ CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);
+ CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL) == 0);
CHECK(ecount == 3);
/* Check NULLs for conversion */
- CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1);
ecount = 0;
- CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1);
/* Check NULLs for de/serialization */
- CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
ecount = 0;
- CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid) == 0);
CHECK(ecount == 4);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid) == 0);
CHECK(ecount == 5);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1) == 0);
CHECK(ecount == 6);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5) == 0);
CHECK(ecount == 7);
/* overflow in signature will fail but not affect ecount */
memcpy(sig, over_privkey, 32);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0);
CHECK(ecount == 7);
/* cleanup */
- secp256k1_context_destroy(none);
- secp256k1_context_destroy(sign);
- secp256k1_context_destroy(vrfy);
- secp256k1_context_destroy(both);
- secp256k1_context_destroy(sttc);
+ secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
+ secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
}
-void test_ecdsa_recovery_end_to_end(void) {
+static void test_ecdsa_recovery_end_to_end(void) {
unsigned char extra[32] = {0x00};
unsigned char privkey[32];
unsigned char message[32];
@@ -174,45 +148,45 @@ void test_ecdsa_recovery_end_to_end(void) {
}
/* Construct and verify corresponding public key. */
- CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+ CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
/* Serialize/parse compact and verify/recover. */
extra[0] = 0;
- CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1);
- CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);
- CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1);
- CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[0], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[4], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[1], message, privkey, NULL, extra) == 1);
extra[31] = 1;
- CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[2], message, privkey, NULL, extra) == 1);
extra[31] = 0;
extra[0] = 1;
- CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[3], message, privkey, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1);
CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0);
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1);
memset(&rsignature[4], 0, sizeof(rsignature[4]));
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1);
/* Parse compact (with recovery id) and recover. */
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
- CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1);
+ CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 1);
CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
/* Serialize/destroy/parse signature and verify again. */
- CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1);
sig[secp256k1_testrand_bits(6)] += 1 + secp256k1_testrand_int(255);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 0);
/* Recover again */
- CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 ||
+ CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 0 ||
secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
}
/* Tests several edge cases. */
-void test_ecdsa_recovery_edge_cases(void) {
+static void test_ecdsa_recovery_edge_cases(void) {
const unsigned char msg32[32] = {
'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
@@ -248,14 +222,14 @@ void test_ecdsa_recovery_edge_cases(void) {
secp256k1_ecdsa_signature sig;
int recid;
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0));
- CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1));
- CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2));
- CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3));
- CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 0));
+ CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 1));
+ CHECK(secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 2));
+ CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 3));
+ CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
for (recid = 0; recid < 4; recid++) {
int i;
@@ -300,40 +274,40 @@ void test_ecdsa_recovery_edge_cases(void) {
0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
};
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1);
- CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid) == 1);
+ CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 1);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 1);
for (recid2 = 0; recid2 < 4; recid2++) {
secp256k1_pubkey pubkey2b;
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1);
- CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid2) == 1);
+ CHECK(secp256k1_ecdsa_recover(CTX, &pubkey2b, &rsig, msg32) == 1);
/* Verifying with (order + r,4) should always fail. */
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderlong, sizeof(sigbderlong)) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
}
/* DER parsing tests. */
/* Zero length r/s. */
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
/* Leading zeros. */
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
sigbderalt3[4] = 1;
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
sigbderalt4[7] = 1;
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
/* Damage signature. */
sigbder[7]++;
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
sigbder[7]--;
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, 6) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder) - 1) == 0);
for(i = 0; i < 8; i++) {
int c;
unsigned char orig = sigbder[i];
@@ -343,7 +317,7 @@ void test_ecdsa_recovery_edge_cases(void) {
continue;
}
sigbder[i] = c;
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
}
sigbder[i] = orig;
}
@@ -364,33 +338,33 @@ void test_ecdsa_recovery_edge_cases(void) {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
};
secp256k1_pubkey pubkeyc;
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
- CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1);
+ CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyc, &rsig, msg32) == 1);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 1);
sigcder[4] = 0;
sigc64[31] = 0;
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
- CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1);
+ CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0);
sigcder[4] = 1;
sigcder[7] = 0;
sigc64[31] = 1;
sigc64[63] = 0;
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
- CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1);
+ CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0);
}
}
-void run_recovery_tests(void) {
+static void run_recovery_tests(void) {
int i;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
test_ecdsa_recovery_api();
}
- for (i = 0; i < 64*count; i++) {
+ for (i = 0; i < 64*COUNT; i++) {
test_ecdsa_recovery_end_to_end();
}
test_ecdsa_recovery_edge_cases();
diff --git a/src/secp256k1/src/modules/schnorrsig/bench_impl.h b/src/secp256k1/src/modules/schnorrsig/bench_impl.h
index 41f393c84d..93a878ede3 100644
--- a/src/secp256k1/src/modules/schnorrsig/bench_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/bench_impl.h
@@ -21,7 +21,7 @@ typedef struct {
const unsigned char **msgs;
} bench_schnorrsig_data;
-void bench_schnorrsig_sign(void* arg, int iters) {
+static void bench_schnorrsig_sign(void* arg, int iters) {
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
int i;
unsigned char msg[MSGLEN] = {0};
@@ -34,7 +34,7 @@ void bench_schnorrsig_sign(void* arg, int iters) {
}
}
-void bench_schnorrsig_verify(void* arg, int iters) {
+static void bench_schnorrsig_verify(void* arg, int iters) {
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
int i;
@@ -45,12 +45,12 @@ void bench_schnorrsig_verify(void* arg, int iters) {
}
}
-void run_schnorrsig_bench(int iters, int argc, char** argv) {
+static void run_schnorrsig_bench(int iters, int argc, char** argv) {
int i;
bench_schnorrsig_data data;
int d = argc == 1;
- data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *));
data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
@@ -91,10 +91,12 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) {
free((void *)data.msgs[i]);
free((void *)data.sigs[i]);
}
- free(data.keypairs);
- free(data.pk);
- free(data.msgs);
- free(data.sigs);
+
+ /* Casting to (void *) avoids a stupid warning in MSVC. */
+ free((void *)data.keypairs);
+ free((void *)data.pk);
+ free((void *)data.msgs);
+ free((void *)data.sigs);
secp256k1_context_destroy(data.ctx);
}
diff --git a/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h
index d8df9dd2df..55f9028a63 100644
--- a/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h
@@ -8,7 +8,7 @@
#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
#include "../../../include/secp256k1_schnorrsig.h"
-#include "src/modules/schnorrsig/main_impl.h"
+#include "main_impl.h"
static const unsigned char invalid_pubkey_bytes[][32] = {
/* 0 */
diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
index 25840b8fa7..062005ee63 100644
--- a/src/secp256k1/src/modules/schnorrsig/tests_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
@@ -12,7 +12,7 @@
/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many
* bytes) changes the hash function
*/
-void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) {
+static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) {
unsigned char nonces[2][32];
CHECK(nonce_function_bip340(nonces[0], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1);
secp256k1_testrand_flip(args[n_flip], n_bytes);
@@ -23,7 +23,7 @@ void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n
/* Tests for the equality of two sha256 structs. This function only produces a
* correct result if an integer multiple of 64 many bytes have been written
* into the hash functions. */
-void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
+static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
/* Is buffer fully consumed? */
CHECK((sha1->bytes & 0x3F) == 0);
@@ -31,7 +31,7 @@ void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2)
CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
}
-void run_nonce_function_bip340_tests(void) {
+static void run_nonce_function_bip340_tests(void) {
unsigned char tag[13] = "BIP0340/nonce";
unsigned char aux_tag[11] = "BIP0340/aux";
unsigned char algo[13] = "BIP0340/nonce";
@@ -72,7 +72,7 @@ void run_nonce_function_bip340_tests(void) {
args[2] = pk;
args[3] = algo;
args[4] = aux_rand;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
nonce_function_bip340_bitflip(args, 0, 32, msglen, algolen);
nonce_function_bip340_bitflip(args, 1, 32, msglen, algolen);
nonce_function_bip340_bitflip(args, 2, 32, msglen, algolen);
@@ -90,7 +90,7 @@ void run_nonce_function_bip340_tests(void) {
secp256k1_testrand_bytes_test(algo, algolen);
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1);
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
unsigned char nonce2[32];
uint32_t offset = secp256k1_testrand_int(msglen - 1);
size_t msglen_tmp = (msglen + offset) % msglen;
@@ -114,7 +114,7 @@ void run_nonce_function_bip340_tests(void) {
CHECK(secp256k1_memcmp_var(nonce_z, nonce, 32) == 0);
}
-void test_schnorrsig_api(void) {
+static void test_schnorrsig_api(void) {
unsigned char sk1[32];
unsigned char sk2[32];
unsigned char sk3[32];
@@ -128,108 +128,82 @@ void test_schnorrsig_api(void) {
secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL};
/** setup **/
- secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
- secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
- secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
- secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
- secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
- int ecount;
-
- secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
+ int ecount = 0;
+
+ secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
secp256k1_testrand256(sk1);
secp256k1_testrand256(sk2);
secp256k1_testrand256(sk3);
secp256k1_testrand256(msg);
- CHECK(secp256k1_keypair_create(ctx, &keypairs[0], sk1) == 1);
- CHECK(secp256k1_keypair_create(ctx, &keypairs[1], sk2) == 1);
- CHECK(secp256k1_keypair_create(ctx, &keypairs[2], sk3) == 1);
- CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[0], NULL, &keypairs[0]) == 1);
- CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[1], NULL, &keypairs[1]) == 1);
- CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[2], NULL, &keypairs[2]) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypairs[0], sk1) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypairs[1], sk2) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypairs[2], sk3) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[0], NULL, &keypairs[0]) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[1], NULL, &keypairs[1]) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[2], NULL, &keypairs[2]) == 1);
memset(&zero_pk, 0, sizeof(zero_pk));
/** main test body **/
ecount = 0;
- CHECK(secp256k1_schnorrsig_sign32(none, sig, msg, &keypairs[0], NULL) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign32(vrfy, sig, msg, &keypairs[0], NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign32(sign, NULL, msg, &keypairs[0], NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_schnorrsig_sign32(sign, sig, NULL, &keypairs[0], NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, NULL, NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &invalid_keypair, NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL) == 0);
CHECK(ecount == 4);
- CHECK(secp256k1_schnorrsig_sign32(sttc, sig, msg, &keypairs[0], NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 5);
ecount = 0;
- CHECK(secp256k1_schnorrsig_sign_custom(none, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign_custom(vrfy, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign_custom(sign, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, NULL, 0, &keypairs[0], &extraparams) == 1);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, 0, &keypairs[0], &extraparams) == 1);
CHECK(ecount == 2);
- CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), NULL, &extraparams) == 0);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0);
CHECK(ecount == 4);
- CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1);
CHECK(ecount == 4);
- CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0);
CHECK(ecount == 5);
- CHECK(secp256k1_schnorrsig_sign_custom(sttc, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
+ CHECK(secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 6);
ecount = 0;
- CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
- CHECK(secp256k1_schnorrsig_verify(none, sig, msg, sizeof(msg), &pk[0]) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, sizeof(msg), &pk[0]) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &pk[0]) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk[0]) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, sizeof(msg), &pk[0]) == 0);
+ CHECK(secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, sizeof(msg), &pk[0]) == 0);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, 0, &pk[0]) == 0);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, 0, &pk[0]) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), NULL) == 0);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &zero_pk) == 0);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk) == 0);
CHECK(ecount == 4);
- secp256k1_context_destroy(none);
- secp256k1_context_destroy(sign);
- secp256k1_context_destroy(vrfy);
- secp256k1_context_destroy(both);
- secp256k1_context_destroy(sttc);
+ secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
+ secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
}
/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the
* expected state. */
-void test_schnorrsig_sha256_tagged(void) {
+static void test_schnorrsig_sha256_tagged(void) {
unsigned char tag[17] = "BIP0340/challenge";
secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized;
@@ -241,33 +215,33 @@ void test_schnorrsig_sha256_tagged(void) {
/* Helper function for schnorrsig_bip_vectors
* Signs the message and checks that it's the same as expected_sig. */
-void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) {
+static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) {
unsigned char sig[64];
secp256k1_keypair keypair;
secp256k1_xonly_pubkey pk, pk_expected;
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
- CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg32, &keypair, aux_rand));
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk));
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg32, &keypair, aux_rand));
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized));
- CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized));
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair));
CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0);
- CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg32, 32, &pk));
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
}
/* Helper function for schnorrsig_bip_vectors
* Checks that both verify and verify_batch (TODO) return the same value as expected. */
-void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) {
+static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) {
secp256k1_xonly_pubkey pk;
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk, pk_serialized));
- CHECK(expected == secp256k1_schnorrsig_verify(ctx, sig, msg32, 32, &pk));
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk, pk_serialized));
+ CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
}
/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See
* https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */
-void test_schnorrsig_bip_vectors(void) {
+static void test_schnorrsig_bip_vectors(void) {
{
/* Test vector 0 */
const unsigned char sk[32] = {
@@ -460,7 +434,7 @@ void test_schnorrsig_bip_vectors(void) {
};
secp256k1_xonly_pubkey pk_parsed;
/* No need to check the signature of the test vector as parsing the pubkey already fails */
- CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk));
+ CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk));
}
{
/* Test vector 6 */
@@ -680,7 +654,7 @@ void test_schnorrsig_bip_vectors(void) {
};
secp256k1_xonly_pubkey pk_parsed;
/* No need to check the signature of the test vector as parsing the pubkey already fails */
- CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk));
+ CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk));
}
}
@@ -725,7 +699,7 @@ static int nonce_function_overflowing(unsigned char *nonce32, const unsigned cha
return 1;
}
-void test_schnorrsig_sign(void) {
+static void test_schnorrsig_sign(void) {
unsigned char sk[32];
secp256k1_xonly_pubkey pk;
secp256k1_keypair keypair;
@@ -738,36 +712,36 @@ void test_schnorrsig_sign(void) {
secp256k1_testrand256(sk);
secp256k1_testrand256(aux_rand);
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
- CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
- CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1);
- CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk));
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair));
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk));
/* Check that deprecated alias gives the same result */
- CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign(CTX, sig2, msg, &keypair, NULL) == 1);
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
/* Test different nonce functions */
- CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
- CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk));
memset(sig, 1, sizeof(sig));
extraparams.noncefp = nonce_function_failing;
- CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 0);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0);
CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0);
memset(&sig, 1, sizeof(sig));
extraparams.noncefp = nonce_function_0;
- CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 0);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0);
CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0);
memset(&sig, 1, sizeof(sig));
extraparams.noncefp = nonce_function_overflowing;
- CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
- CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk));
/* When using the default nonce function, schnorrsig_sign_custom produces
* the same result as schnorrsig_sign with aux_rand = extraparams.ndata */
extraparams.noncefp = NULL;
extraparams.ndata = aux_rand;
- CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
- CHECK(secp256k1_schnorrsig_sign32(ctx, sig2, msg, &keypair, extraparams.ndata) == 1);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig2, msg, &keypair, extraparams.ndata) == 1);
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
}
@@ -775,7 +749,7 @@ void test_schnorrsig_sign(void) {
/* Creates N_SIGS valid signatures and verifies them with verify and
* verify_batch (TODO). Then flips some bits and checks that verification now
* fails. */
-void test_schnorrsig_sign_verify(void) {
+static void test_schnorrsig_sign_verify(void) {
unsigned char sk[32];
unsigned char msg[N_SIGS][32];
unsigned char sig[N_SIGS][64];
@@ -785,13 +759,13 @@ void test_schnorrsig_sign_verify(void) {
secp256k1_scalar s;
secp256k1_testrand256(sk);
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
- CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk));
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair));
for (i = 0; i < N_SIGS; i++) {
secp256k1_testrand256(msg[i]);
- CHECK(secp256k1_schnorrsig_sign32(ctx, sig[i], msg[i], &keypair, NULL));
- CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], sizeof(msg[i]), &pk));
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig[i], msg[i], &keypair, NULL));
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig[i], msg[i], sizeof(msg[i]), &pk));
}
{
@@ -801,40 +775,40 @@ void test_schnorrsig_sign_verify(void) {
size_t byte_idx = secp256k1_testrand_bits(5);
unsigned char xorbyte = secp256k1_testrand_int(254)+1;
sig[sig_idx][byte_idx] ^= xorbyte;
- CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
+ CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
sig[sig_idx][byte_idx] ^= xorbyte;
byte_idx = secp256k1_testrand_bits(5);
sig[sig_idx][32+byte_idx] ^= xorbyte;
- CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
+ CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
sig[sig_idx][32+byte_idx] ^= xorbyte;
byte_idx = secp256k1_testrand_bits(5);
msg[sig_idx][byte_idx] ^= xorbyte;
- CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
+ CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
msg[sig_idx][byte_idx] ^= xorbyte;
/* Check that above bitflips have been reversed correctly */
- CHECK(secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
}
/* Test overflowing s */
- CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL));
- CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL));
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk));
memset(&sig[0][32], 0xFF, 32);
- CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
+ CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk));
/* Test negative s */
- CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL));
- CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL));
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk));
secp256k1_scalar_set_b32(&s, &sig[0][32], NULL);
secp256k1_scalar_negate(&s, &s);
secp256k1_scalar_get_b32(&sig[0][32], &s);
- CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
+ CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk));
/* The empty message can be signed & verified */
- CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig[0], NULL, 0, &keypair, NULL) == 1);
- CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], NULL, 0, &pk) == 1);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], NULL, 0, &keypair, NULL) == 1);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], NULL, 0, &pk) == 1);
{
/* Test varying message lengths */
@@ -843,16 +817,16 @@ void test_schnorrsig_sign_verify(void) {
for (i = 0; i < sizeof(msg_large); i += 32) {
secp256k1_testrand256(&msg_large[i]);
}
- CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig[0], msg_large, msglen, &keypair, NULL) == 1);
- CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg_large, msglen, &pk) == 1);
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], msg_large, msglen, &keypair, NULL) == 1);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 1);
/* Verification for a random wrong message length fails */
msglen = (msglen + (sizeof(msg_large) - 1)) % sizeof(msg_large);
- CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg_large, msglen, &pk) == 0);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 0);
}
}
#undef N_SIGS
-void test_schnorrsig_taproot(void) {
+static void test_schnorrsig_taproot(void) {
unsigned char sk[32];
secp256k1_keypair keypair;
secp256k1_xonly_pubkey internal_pk;
@@ -866,36 +840,36 @@ void test_schnorrsig_taproot(void) {
/* Create output key */
secp256k1_testrand256(sk);
- CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
- CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1);
+ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1);
/* In actual taproot the tweak would be hash of internal_pk */
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, tweak, &internal_pk) == 1);
- CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
- CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1);
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, tweak, &internal_pk) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk_bytes, &output_pk) == 1);
/* Key spend */
secp256k1_testrand256(msg);
- CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1);
/* Verify key spend */
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1);
- CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &output_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &output_pk, output_pk_bytes) == 1);
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &output_pk) == 1);
/* Script spend */
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, internal_pk_bytes, &internal_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(CTX, internal_pk_bytes, &internal_pk) == 1);
/* Verify script spend */
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &internal_pk, internal_pk_bytes) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_parse(CTX, &internal_pk, internal_pk_bytes) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1);
}
-void run_schnorrsig_tests(void) {
+static void run_schnorrsig_tests(void) {
int i;
run_nonce_function_bip340_tests();
test_schnorrsig_api();
test_schnorrsig_sha256_tagged();
test_schnorrsig_bip_vectors();
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
test_schnorrsig_sign();
test_schnorrsig_sign_verify();
}
diff --git a/src/secp256k1/src/precompute_ecmult.c b/src/secp256k1/src/precompute_ecmult.c
index 5ccbcb3c57..10aba5b97d 100644
--- a/src/secp256k1/src/precompute_ecmult.c
+++ b/src/secp256k1/src/precompute_ecmult.c
@@ -7,17 +7,14 @@
#include <inttypes.h>
#include <stdio.h>
-/* Autotools creates libsecp256k1-config.h, of which ECMULT_WINDOW_SIZE is needed.
- ifndef guard so downstream users can define their own if they do not use autotools. */
-#if !defined(ECMULT_WINDOW_SIZE)
-#include "libsecp256k1-config.h"
-#endif
-
#include "../include/secp256k1.h"
+
#include "assumptions.h"
#include "util.h"
+
#include "field_impl.h"
#include "group_impl.h"
+#include "int128_impl.h"
#include "ecmult.h"
#include "ecmult_compute_table_impl.h"
@@ -71,9 +68,6 @@ int main(void) {
fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n");
fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n");
fprintf(fp, " */\n");
- fprintf(fp, "#if defined HAVE_CONFIG_H\n");
- fprintf(fp, "# include \"libsecp256k1-config.h\"\n");
- fprintf(fp, "#endif\n");
fprintf(fp, "#include \"../include/secp256k1.h\"\n");
fprintf(fp, "#include \"group.h\"\n");
fprintf(fp, "#include \"ecmult.h\"\n");
diff --git a/src/secp256k1/src/precompute_ecmult_gen.c b/src/secp256k1/src/precompute_ecmult_gen.c
index 7c6359c402..bfe212fdd2 100644
--- a/src/secp256k1/src/precompute_ecmult_gen.c
+++ b/src/secp256k1/src/precompute_ecmult_gen.c
@@ -8,9 +8,12 @@
#include <stdio.h>
#include "../include/secp256k1.h"
+
#include "assumptions.h"
#include "util.h"
+
#include "group.h"
+#include "int128_impl.h"
#include "ecmult_gen.h"
#include "ecmult_gen_compute_table_impl.h"
@@ -30,9 +33,6 @@ int main(int argc, char **argv) {
fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n");
fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n");
- fprintf(fp, "#if defined HAVE_CONFIG_H\n");
- fprintf(fp, "# include \"libsecp256k1-config.h\"\n");
- fprintf(fp, "#endif\n");
fprintf(fp, "#include \"../include/secp256k1.h\"\n");
fprintf(fp, "#include \"group.h\"\n");
fprintf(fp, "#include \"ecmult_gen.h\"\n");
diff --git a/src/secp256k1/src/precomputed_ecmult.c b/src/secp256k1/src/precomputed_ecmult.c
index 3e67f37b74..fbc634ef1b 100644
--- a/src/secp256k1/src/precomputed_ecmult.c
+++ b/src/secp256k1/src/precomputed_ecmult.c
@@ -2,9 +2,6 @@
/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and
* an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.
*/
-#if defined HAVE_CONFIG_H
-# include "libsecp256k1-config.h"
-#endif
#include "../include/secp256k1.h"
#include "group.h"
#include "ecmult.h"
diff --git a/src/secp256k1/src/precomputed_ecmult.h b/src/secp256k1/src/precomputed_ecmult.h
index 949b62c874..a4aa83e4ca 100644
--- a/src/secp256k1/src/precomputed_ecmult.h
+++ b/src/secp256k1/src/precomputed_ecmult.h
@@ -13,7 +13,9 @@ extern "C" {
#include "group.h"
#if defined(EXHAUSTIVE_TEST_ORDER)
-#if EXHAUSTIVE_TEST_ORDER == 13
+# if EXHAUSTIVE_TEST_ORDER == 7
+# define WINDOW_G 3
+# elif EXHAUSTIVE_TEST_ORDER == 13
# define WINDOW_G 4
# elif EXHAUSTIVE_TEST_ORDER == 199
# define WINDOW_G 8
diff --git a/src/secp256k1/src/precomputed_ecmult_gen.c b/src/secp256k1/src/precomputed_ecmult_gen.c
index d67291fcf5..e9d62a1c1b 100644
--- a/src/secp256k1/src/precomputed_ecmult_gen.c
+++ b/src/secp256k1/src/precomputed_ecmult_gen.c
@@ -1,8 +1,5 @@
/* This file was automatically generated by precompute_ecmult_gen. */
/* See ecmult_gen_impl.h for details about the contents of this file. */
-#if defined HAVE_CONFIG_H
-# include "libsecp256k1-config.h"
-#endif
#include "../include/secp256k1.h"
#include "group.h"
#include "ecmult_gen.h"
diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h
index aaaa3d8827..63c0d646a3 100644
--- a/src/secp256k1/src/scalar.h
+++ b/src/secp256k1/src/scalar.h
@@ -9,10 +9,6 @@
#include "util.h"
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
#if defined(EXHAUSTIVE_TEST_ORDER)
#include "scalar_low.h"
#elif defined(SECP256K1_WIDEMUL_INT128)
@@ -92,9 +88,10 @@ static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar
/** Find r1 and r2 such that r1+r2*2^128 = k. */
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k);
-/** Find r1 and r2 such that r1+r2*lambda = k,
- * where r1 and r2 or their negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). */
-static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k);
+/** Find r1 and r2 such that r1+r2*lambda = k, where r1 and r2 or their
+ * negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). It is
+ * required that r1, r2, and k all point to different objects. */
+static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k);
/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index a1def26fca..1b83575b3e 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -7,6 +7,8 @@
#ifndef SECP256K1_SCALAR_REPR_IMPL_H
#define SECP256K1_SCALAR_REPR_IMPL_H
+#include "checkmem.h"
+#include "int128.h"
#include "modinv64_impl.h"
/* Limbs of the secp256k1 order. */
@@ -69,50 +71,61 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal
}
SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) {
- uint128_t t;
+ secp256k1_uint128 t;
VERIFY_CHECK(overflow <= 1);
- t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0;
- r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1;
- r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2;
- r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- t += (uint64_t)r->d[3];
- r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL;
+ secp256k1_u128_from_u64(&t, r->d[0]);
+ secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_0);
+ r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, r->d[1]);
+ secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_1);
+ r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, r->d[2]);
+ secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_2);
+ r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, r->d[3]);
+ r->d[3] = secp256k1_u128_to_u64(&t);
return overflow;
}
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
int overflow;
- uint128_t t = (uint128_t)a->d[0] + b->d[0];
- r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- t += (uint128_t)a->d[1] + b->d[1];
- r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- t += (uint128_t)a->d[2] + b->d[2];
- r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- t += (uint128_t)a->d[3] + b->d[3];
- r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- overflow = t + secp256k1_scalar_check_overflow(r);
+ secp256k1_uint128 t;
+ secp256k1_u128_from_u64(&t, a->d[0]);
+ secp256k1_u128_accum_u64(&t, b->d[0]);
+ r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, a->d[1]);
+ secp256k1_u128_accum_u64(&t, b->d[1]);
+ r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, a->d[2]);
+ secp256k1_u128_accum_u64(&t, b->d[2]);
+ r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, a->d[3]);
+ secp256k1_u128_accum_u64(&t, b->d[3]);
+ r->d[3] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ overflow = secp256k1_u128_to_u64(&t) + secp256k1_scalar_check_overflow(r);
VERIFY_CHECK(overflow == 0 || overflow == 1);
secp256k1_scalar_reduce(r, overflow);
return overflow;
}
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
- uint128_t t;
+ secp256k1_uint128 t;
VERIFY_CHECK(bit < 256);
bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
- t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
- r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));
- r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F));
- r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F));
- r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL;
+ secp256k1_u128_from_u64(&t, r->d[0]);
+ secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
+ r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, r->d[1]);
+ secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));
+ r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, r->d[2]);
+ secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F));
+ r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, r->d[3]);
+ secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F));
+ r->d[3] = secp256k1_u128_to_u64(&t);
#ifdef VERIFY
- VERIFY_CHECK((t >> 64) == 0);
- VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
+ VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0);
#endif
}
@@ -141,14 +154,19 @@ SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a)
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0);
- uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1;
- r->d[0] = t & nonzero; t >>= 64;
- t += (uint128_t)(~a->d[1]) + SECP256K1_N_1;
- r->d[1] = t & nonzero; t >>= 64;
- t += (uint128_t)(~a->d[2]) + SECP256K1_N_2;
- r->d[2] = t & nonzero; t >>= 64;
- t += (uint128_t)(~a->d[3]) + SECP256K1_N_3;
- r->d[3] = t & nonzero;
+ secp256k1_uint128 t;
+ secp256k1_u128_from_u64(&t, ~a->d[0]);
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1);
+ r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, ~a->d[1]);
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_1);
+ r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, ~a->d[2]);
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_2);
+ r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, ~a->d[3]);
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_3);
+ r->d[3] = secp256k1_u128_to_u64(&t) & nonzero;
}
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
@@ -172,14 +190,19 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
* if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
uint64_t mask = !flag - 1;
uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;
- uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
- r->d[0] = t & nonzero; t >>= 64;
- t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask);
- r->d[1] = t & nonzero; t >>= 64;
- t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask);
- r->d[2] = t & nonzero; t >>= 64;
- t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask);
- r->d[3] = t & nonzero;
+ secp256k1_uint128 t;
+ secp256k1_u128_from_u64(&t, r->d[0] ^ mask);
+ secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask);
+ r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, r->d[1] ^ mask);
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_1 & mask);
+ r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, r->d[2] ^ mask);
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_2 & mask);
+ r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, r->d[3] ^ mask);
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask);
+ r->d[3] = secp256k1_u128_to_u64(&t) & nonzero;
return 2 * (mask == 0) - 1;
}
@@ -189,9 +212,10 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
#define muladd(a,b) { \
uint64_t tl, th; \
{ \
- uint128_t t = (uint128_t)a * b; \
- th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
- tl = t; \
+ secp256k1_uint128 t; \
+ secp256k1_u128_mul(&t, a, b); \
+ th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \
+ tl = secp256k1_u128_to_u64(&t); \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
@@ -204,9 +228,10 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
#define muladd_fast(a,b) { \
uint64_t tl, th; \
{ \
- uint128_t t = (uint128_t)a * b; \
- th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
- tl = t; \
+ secp256k1_uint128 t; \
+ secp256k1_u128_mul(&t, a, b); \
+ th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \
+ tl = secp256k1_u128_to_u64(&t); \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
@@ -484,8 +509,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
: "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "cc", "memory");
#else
- uint128_t c;
- uint64_t c0, c1, c2;
+ secp256k1_uint128 c128;
+ uint64_t c, c0, c1, c2;
uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7];
uint64_t m0, m1, m2, m3, m4, m5;
uint32_t m6;
@@ -542,14 +567,18 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
/* Reduce 258 bits into 256. */
/* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */
- c = p0 + (uint128_t)SECP256K1_N_C_0 * p4;
- r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
- c += p1 + (uint128_t)SECP256K1_N_C_1 * p4;
- r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
- c += p2 + (uint128_t)p4;
- r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
- c += p3;
- r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
+ secp256k1_u128_from_u64(&c128, p0);
+ secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_0, p4);
+ r->d[0] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64);
+ secp256k1_u128_accum_u64(&c128, p1);
+ secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_1, p4);
+ r->d[1] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64);
+ secp256k1_u128_accum_u64(&c128, p2);
+ secp256k1_u128_accum_u64(&c128, p4);
+ r->d[2] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64);
+ secp256k1_u128_accum_u64(&c128, p3);
+ r->d[3] = secp256k1_u128_to_u64(&c128);
+ c = secp256k1_u128_hi_u64(&c128);
#endif
/* Final reduction of r. */
@@ -782,7 +811,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint64_t mask0, mask1;
- VG_CHECK_VERIFY(r->d, sizeof(r->d));
+ SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0;
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index 62c7ae7156..c433adce75 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -7,6 +7,7 @@
#ifndef SECP256K1_SCALAR_REPR_IMPL_H
#define SECP256K1_SCALAR_REPR_IMPL_H
+#include "checkmem.h"
#include "modinv32_impl.h"
/* Limbs of the secp256k1 order. */
@@ -631,7 +632,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1;
- VG_CHECK_VERIFY(r->d, sizeof(r->d));
+ SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0;
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index 1b690e3944..bed7f95fcb 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -14,10 +14,6 @@
#include "scalar.h"
#include "util.h"
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
#if defined(EXHAUSTIVE_TEST_ORDER)
#include "scalar_low_impl.h"
#elif defined(SECP256K1_WIDEMUL_INT128)
@@ -37,15 +33,18 @@ static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned c
return (!overflow) & (!secp256k1_scalar_is_zero(r));
}
-/* These parameters are generated using sage/gen_exhaustive_groups.sage. */
#if defined(EXHAUSTIVE_TEST_ORDER)
-# if EXHAUSTIVE_TEST_ORDER == 13
+/* Begin of section generated by sage/gen_exhaustive_groups.sage. */
+# if EXHAUSTIVE_TEST_ORDER == 7
+# define EXHAUSTIVE_TEST_LAMBDA 2
+# elif EXHAUSTIVE_TEST_ORDER == 13
# define EXHAUSTIVE_TEST_LAMBDA 9
# elif EXHAUSTIVE_TEST_ORDER == 199
# define EXHAUSTIVE_TEST_LAMBDA 92
# else
# error No known lambda for the specified exhaustive test group order.
# endif
+/* End of section generated by sage/gen_exhaustive_groups.sage. */
/**
* Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n; unlike in the
@@ -53,7 +52,10 @@ static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned c
* nontrivial to get full test coverage for the exhaustive tests. We therefore
* (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n).
*/
-static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
+static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) {
+ VERIFY_CHECK(r1 != k);
+ VERIFY_CHECK(r2 != k);
+ VERIFY_CHECK(r1 != r2);
*r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER;
*r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;
}
@@ -120,7 +122,7 @@ static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, con
*
* See proof below.
*/
-static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
+static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) {
secp256k1_scalar c1, c2;
static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST(
0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL,
@@ -140,6 +142,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
);
VERIFY_CHECK(r1 != k);
VERIFY_CHECK(r2 != k);
+ VERIFY_CHECK(r1 != r2);
/* these _var calls are constant time since the shift amount is constant */
secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384);
secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384);
diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h
index 7176f0b2ca..e780083339 100644
--- a/src/secp256k1/src/scalar_low_impl.h
+++ b/src/secp256k1/src/scalar_low_impl.h
@@ -7,6 +7,7 @@
#ifndef SECP256K1_SCALAR_REPR_IMPL_H
#define SECP256K1_SCALAR_REPR_IMPL_H
+#include "checkmem.h"
#include "scalar.h"
#include <string.h>
@@ -115,7 +116,7 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1;
- VG_CHECK_VERIFY(r, sizeof(*r));
+ SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r));
mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0;
*r = (*r & mask0) | (*a & mask1);
diff --git a/src/secp256k1/src/scratch_impl.h b/src/secp256k1/src/scratch_impl.h
index 688e18eb66..f71a20b963 100644
--- a/src/secp256k1/src/scratch_impl.h
+++ b/src/secp256k1/src/scratch_impl.h
@@ -25,11 +25,11 @@ static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* err
static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) {
if (scratch != NULL) {
- VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */
if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return;
}
+ VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */
memset(scratch->magic, 0, sizeof(scratch->magic));
free(scratch);
}
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 8f34c35283..7af333ca90 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -4,13 +4,26 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
+/* This is a C project. It should not be compiled with a C++ compiler,
+ * and we error out if we detect one.
+ *
+ * We still want to be able to test the project with a C++ compiler
+ * because it is still good to know if this will lead to real trouble, so
+ * there is a possibility to override the check. But be warned that
+ * compiling with a C++ compiler is not supported. */
+#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE)
+#error Trying to compile a C project with a C++ compiler.
+#endif
+
#define SECP256K1_BUILD
#include "../include/secp256k1.h"
#include "../include/secp256k1_preallocated.h"
#include "assumptions.h"
+#include "checkmem.h"
#include "util.h"
+
#include "field_impl.h"
#include "scalar_impl.h"
#include "group_impl.h"
@@ -20,6 +33,7 @@
#include "ecdsa_impl.h"
#include "eckey_impl.h"
#include "hash_impl.h"
+#include "int128_impl.h"
#include "scratch_impl.h"
#include "selftest.h"
@@ -27,10 +41,6 @@
# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c"
#endif
-#if defined(VALGRIND)
-# include <valgrind/memcheck.h>
-#endif
-
#define ARG_CHECK(cond) do { \
if (EXPECT(!(cond), 0)) { \
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
@@ -38,12 +48,15 @@
} \
} while(0)
-#define ARG_CHECK_NO_RETURN(cond) do { \
+#define ARG_CHECK_VOID(cond) do { \
if (EXPECT(!(cond), 0)) { \
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
+ return; \
} \
} while(0)
+/* Note that whenever you change the context struct, you must also change the
+ * context_eq function. */
struct secp256k1_context_struct {
secp256k1_ecmult_gen_context ecmult_gen_ctx;
secp256k1_callback illegal_callback;
@@ -51,13 +64,29 @@ struct secp256k1_context_struct {
int declassify;
};
-static const secp256k1_context secp256k1_context_no_precomp_ = {
+static const secp256k1_context secp256k1_context_static_ = {
{ 0 },
{ secp256k1_default_illegal_callback_fn, 0 },
{ secp256k1_default_error_callback_fn, 0 },
0
};
-const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
+const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_;
+const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_;
+
+/* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof.
+ *
+ * This is intended for "context" functions such as secp256k1_context_clone. Function which need specific
+ * features of a context should still check for these features directly. For example, a function that needs
+ * ecmult_gen should directly check for the existence of the ecmult_gen context. */
+static int secp256k1_context_is_proper(const secp256k1_context* ctx) {
+ return secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx);
+}
+
+void secp256k1_selftest(void) {
+ if (!secp256k1_selftest_passes()) {
+ secp256k1_callback_call(&default_error_callback, "self test failed");
+ }
+}
size_t secp256k1_context_preallocated_size(unsigned int flags) {
size_t ret = sizeof(secp256k1_context);
@@ -70,22 +99,26 @@ size_t secp256k1_context_preallocated_size(unsigned int flags) {
return 0;
}
+ if (EXPECT(!SECP256K1_CHECKMEM_RUNNING() && (flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY), 0)) {
+ secp256k1_callback_call(&default_illegal_callback,
+ "Declassify flag requires running with memory checking");
+ return 0;
+ }
+
return ret;
}
size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) {
- size_t ret = sizeof(secp256k1_context);
VERIFY_CHECK(ctx != NULL);
- return ret;
+ ARG_CHECK(secp256k1_context_is_proper(ctx));
+ return sizeof(secp256k1_context);
}
secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) {
size_t prealloc_size;
secp256k1_context* ret;
- if (!secp256k1_selftest()) {
- secp256k1_callback_call(&default_error_callback, "self test failed");
- }
+ secp256k1_selftest();
prealloc_size = secp256k1_context_preallocated_size(flags);
if (prealloc_size == 0) {
@@ -119,6 +152,7 @@ secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context*
secp256k1_context* ret;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(prealloc != NULL);
+ ARG_CHECK(secp256k1_context_is_proper(ctx));
ret = (secp256k1_context*)prealloc;
*ret = *ctx;
@@ -130,6 +164,8 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
size_t prealloc_size;
VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_context_is_proper(ctx));
+
prealloc_size = secp256k1_context_preallocated_clone_size(ctx);
ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size);
ret = secp256k1_context_preallocated_clone(ctx, ret);
@@ -137,21 +173,33 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
}
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
- ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
- if (ctx != NULL) {
- secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
+ ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
+
+ /* Defined as noop */
+ if (ctx == NULL) {
+ return;
}
+
+ secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
}
void secp256k1_context_destroy(secp256k1_context* ctx) {
- if (ctx != NULL) {
- secp256k1_context_preallocated_destroy(ctx);
- free(ctx);
+ ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
+
+ /* Defined as noop */
+ if (ctx == NULL) {
+ return;
}
+
+ secp256k1_context_preallocated_destroy(ctx);
+ free(ctx);
}
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
- ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
+ /* We compare pointers instead of checking secp256k1_context_is_proper() here
+ because setting callbacks is allowed on *copies* of the static context:
+ it's harmless and makes testing easier. */
+ ARG_CHECK_VOID(ctx != secp256k1_context_static);
if (fun == NULL) {
fun = secp256k1_default_illegal_callback_fn;
}
@@ -160,7 +208,10 @@ void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(
}
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
- ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
+ /* We compare pointers instead of checking secp256k1_context_is_proper() here
+ because setting callbacks is allowed on *copies* of the static context:
+ it's harmless and makes testing easier. */
+ ARG_CHECK_VOID(ctx != secp256k1_context_static);
if (fun == NULL) {
fun = secp256k1_default_error_callback_fn;
}
@@ -179,17 +230,10 @@ void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scr
}
/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour
- * of the software. This is setup for use with valgrind but could be substituted with
- * the appropriate instrumentation for other analysis tools.
+ * of the software.
*/
static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) {
-#if defined(VALGRIND)
- if (EXPECT(ctx->declassify,0)) VALGRIND_MAKE_MEM_DEFINED(p, len);
-#else
- (void)ctx;
- (void)p;
- (void)len;
-#endif
+ if (EXPECT(ctx->declassify, 0)) SECP256K1_CHECKMEM_DEFINE(p, len);
}
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
@@ -705,6 +749,8 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey
int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_context_is_proper(ctx));
+
if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
}
diff --git a/src/secp256k1/src/selftest.h b/src/secp256k1/src/selftest.h
index 52f1b8442e..d083ac9524 100644
--- a/src/secp256k1/src/selftest.h
+++ b/src/secp256k1/src/selftest.h
@@ -25,7 +25,7 @@ static int secp256k1_selftest_sha256(void) {
return secp256k1_memcmp_var(out, output32, 32) == 0;
}
-static int secp256k1_selftest(void) {
+static int secp256k1_selftest_passes(void) {
return secp256k1_selftest_sha256();
}
diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h
index bd149bb1b4..d109bb9f8b 100644
--- a/src/secp256k1/src/testrand.h
+++ b/src/secp256k1/src/testrand.h
@@ -7,10 +7,6 @@
#ifndef SECP256K1_TESTRAND_H
#define SECP256K1_TESTRAND_H
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
/* A non-cryptographic RNG used only for test infrastructure. */
/** Seed the pseudorandom number generator for testing. */
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index dd53173930..1c0d797349 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -4,10 +4,6 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -18,6 +14,7 @@
#include "../include/secp256k1.h"
#include "../include/secp256k1_preallocated.h"
#include "testrand_impl.h"
+#include "checkmem.h"
#include "util.h"
#include "../contrib/lax_der_parsing.c"
@@ -26,18 +23,52 @@
#include "modinv32_impl.h"
#ifdef SECP256K1_WIDEMUL_INT128
#include "modinv64_impl.h"
+#include "int128_impl.h"
#endif
-#define CONDITIONAL_TEST(cnt, nam) if (count < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else
+#define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else
-static int count = 64;
-static secp256k1_context *ctx = NULL;
+static int COUNT = 64;
+static secp256k1_context *CTX = NULL;
+static secp256k1_context *STATIC_CTX = NULL;
+
+static int all_bytes_equal(const void* s, unsigned char value, size_t n) {
+ const unsigned char *p = s;
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ if (p[i] != value) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* TODO Use CHECK_ILLEGAL(_VOID) everywhere and get rid of the uncounting callback */
+/* CHECK that expr_or_stmt calls the illegal callback of ctx exactly once
+ *
+ * For checking functions that use ARG_CHECK_VOID */
+#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) do { \
+ int32_t _calls_to_illegal_callback = 0; \
+ secp256k1_callback _saved_illegal_cb = ctx->illegal_callback; \
+ secp256k1_context_set_illegal_callback(ctx, \
+ counting_illegal_callback_fn, &_calls_to_illegal_callback); \
+ { expr_or_stmt; } \
+ ctx->illegal_callback = _saved_illegal_cb; \
+ CHECK(_calls_to_illegal_callback == 1); \
+} while(0);
+
+/* CHECK that expr calls the illegal callback of ctx exactly once and that expr == 0
+ *
+ * For checking functions that use ARG_CHECK */
+#define CHECK_ILLEGAL(ctx, expr) CHECK_ILLEGAL_VOID(ctx, CHECK((expr) == 0))
static void counting_illegal_callback_fn(const char* str, void* data) {
/* Dummy callback function that just counts. */
int32_t *p;
(void)str;
p = data;
+ CHECK(*p != INT32_MAX);
(*p)++;
}
@@ -46,10 +77,11 @@ static void uncounting_illegal_callback_fn(const char* str, void* data) {
int32_t *p;
(void)str;
p = data;
+ CHECK(*p != INT32_MIN);
(*p)--;
}
-void random_field_element_test(secp256k1_fe *fe) {
+static void random_field_element_test(secp256k1_fe *fe) {
do {
unsigned char b32[32];
secp256k1_testrand256_test(b32);
@@ -59,7 +91,7 @@ void random_field_element_test(secp256k1_fe *fe) {
} while(1);
}
-void random_field_element_magnitude(secp256k1_fe *fe) {
+static void random_field_element_magnitude(secp256k1_fe *fe) {
secp256k1_fe zero;
int n = secp256k1_testrand_int(9);
secp256k1_fe_normalize(fe);
@@ -75,7 +107,7 @@ void random_field_element_magnitude(secp256k1_fe *fe) {
#endif
}
-void random_group_element_test(secp256k1_ge *ge) {
+static void random_group_element_test(secp256k1_ge *ge) {
secp256k1_fe fe;
do {
random_field_element_test(&fe);
@@ -87,7 +119,7 @@ void random_group_element_test(secp256k1_ge *ge) {
ge->infinity = 0;
}
-void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) {
+static void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) {
secp256k1_fe z2, z3;
do {
random_field_element_test(&gej->z);
@@ -102,13 +134,13 @@ void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *
gej->infinity = ge->infinity;
}
-void random_gej_test(secp256k1_gej *gej) {
+static void random_gej_test(secp256k1_gej *gej) {
secp256k1_ge ge;
random_group_element_test(&ge);
random_group_element_jacobian_test(gej, &ge);
}
-void random_scalar_order_test(secp256k1_scalar *num) {
+static void random_scalar_order_test(secp256k1_scalar *num) {
do {
unsigned char b32[32];
int overflow = 0;
@@ -121,7 +153,7 @@ void random_scalar_order_test(secp256k1_scalar *num) {
} while(1);
}
-void random_scalar_order(secp256k1_scalar *num) {
+static void random_scalar_order(secp256k1_scalar *num) {
do {
unsigned char b32[32];
int overflow = 0;
@@ -134,76 +166,179 @@ void random_scalar_order(secp256k1_scalar *num) {
} while(1);
}
-void random_scalar_order_b32(unsigned char *b32) {
+static void random_scalar_order_b32(unsigned char *b32) {
secp256k1_scalar num;
random_scalar_order(&num);
secp256k1_scalar_get_b32(b32, &num);
}
-void run_context_tests(int use_prealloc) {
+static void run_selftest_tests(void) {
+ /* Test public API */
+ secp256k1_selftest();
+}
+
+static int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const secp256k1_ecmult_gen_context *b) {
+ return a->built == b->built
+ && secp256k1_scalar_eq(&a->blind, &b->blind)
+ && secp256k1_gej_eq_var(&a->initial, &b->initial);
+}
+
+static int context_eq(const secp256k1_context *a, const secp256k1_context *b) {
+ return a->declassify == b->declassify
+ && ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx)
+ && a->illegal_callback.fn == b->illegal_callback.fn
+ && a->illegal_callback.data == b->illegal_callback.data
+ && a->error_callback.fn == b->error_callback.fn
+ && a->error_callback.data == b->error_callback.data;
+}
+
+static void run_deprecated_context_flags_test(void) {
+ /* Check that a context created with any of the flags in the flags array is
+ * identical to the NONE context. */
+ unsigned int flags[] = { SECP256K1_CONTEXT_SIGN,
+ SECP256K1_CONTEXT_VERIFY,
+ SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY };
+ secp256k1_context *none_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+ int i;
+ for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) {
+ secp256k1_context *tmp_ctx;
+ CHECK(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE) == secp256k1_context_preallocated_size(flags[i]));
+ tmp_ctx = secp256k1_context_create(flags[i]);
+ CHECK(context_eq(none_ctx, tmp_ctx));
+ secp256k1_context_destroy(tmp_ctx);
+ }
+ secp256k1_context_destroy(none_ctx);
+}
+
+static void run_ec_illegal_argument_tests(void) {
+ int ecount = 0;
+ int ecount2 = 10;
secp256k1_pubkey pubkey;
secp256k1_pubkey zero_pubkey;
secp256k1_ecdsa_signature sig;
unsigned char ctmp[32];
- int32_t ecount;
- int32_t ecount2;
- secp256k1_context *none;
- secp256k1_context *sign;
- secp256k1_context *vrfy;
- secp256k1_context *both;
- secp256k1_context *sttc;
- void *none_prealloc = NULL;
- void *sign_prealloc = NULL;
- void *vrfy_prealloc = NULL;
- void *both_prealloc = NULL;
- void *sttc_prealloc = NULL;
+
+ /* Setup */
+ secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount2);
+ memset(ctmp, 1, 32);
+ memset(&zero_pubkey, 0, sizeof(zero_pubkey));
+
+ /* Verify context-type checking illegal-argument errors. */
+ CHECK(secp256k1_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp) == 0);
+ CHECK(ecount == 1);
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL) == 0);
+ CHECK(ecount == 2);
+ SECP256K1_CHECKMEM_UNDEFINE(&sig, sizeof(sig));
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, ctmp, ctmp, NULL, NULL) == 1);
+ SECP256K1_CHECKMEM_CHECK(&sig, sizeof(sig));
+ CHECK(ecount2 == 10);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, ctmp, &pubkey) == 1);
+ CHECK(ecount2 == 10);
+ CHECK(secp256k1_ecdsa_verify(STATIC_CTX, &sig, ctmp, &pubkey) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp) == 1);
+ CHECK(ecount2 == 10);
+ CHECK(secp256k1_ec_pubkey_tweak_add(STATIC_CTX, &pubkey, ctmp) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp) == 1);
+ CHECK(ecount2 == 10);
+ CHECK(secp256k1_ec_pubkey_negate(STATIC_CTX, &pubkey) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ec_pubkey_negate(STATIC_CTX, &zero_pubkey) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ec_pubkey_negate(CTX, NULL) == 0);
+ CHECK(ecount2 == 11);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(STATIC_CTX, &pubkey, ctmp) == 1);
+ CHECK(ecount == 3);
+
+ /* Clean up */
+ secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
+ secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
+}
+
+static void run_static_context_tests(int use_prealloc) {
+ /* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */
+ CHECK(secp256k1_context_no_precomp == secp256k1_context_static);
+
+ {
+ unsigned char seed[32] = {0x17};
+
+ /* Randomizing secp256k1_context_static is not supported. */
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, seed));
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, NULL));
+
+ /* Destroying or cloning secp256k1_context_static is not supported. */
+ if (use_prealloc) {
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone_size(STATIC_CTX));
+ {
+ secp256k1_context *my_static_ctx = malloc(sizeof(*STATIC_CTX));
+ CHECK(my_static_ctx != NULL);
+ memset(my_static_ctx, 0x2a, sizeof(*my_static_ctx));
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone(STATIC_CTX, my_static_ctx));
+ CHECK(all_bytes_equal(my_static_ctx, 0x2a, sizeof(*my_static_ctx)));
+ free(my_static_ctx);
+ }
+ CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_preallocated_destroy(STATIC_CTX));
+ } else {
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_clone(STATIC_CTX));
+ CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_destroy(STATIC_CTX));
+ }
+ }
+
+ {
+ /* Verify that setting and resetting illegal callback works */
+ int32_t dummy = 0;
+ secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &dummy);
+ CHECK(STATIC_CTX->illegal_callback.fn == counting_illegal_callback_fn);
+ CHECK(STATIC_CTX->illegal_callback.data == &dummy);
+ secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
+ CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
+ CHECK(STATIC_CTX->illegal_callback.data == NULL);
+ }
+}
+
+static void run_proper_context_tests(int use_prealloc) {
+ int32_t dummy = 0;
+ secp256k1_context *my_ctx, *my_ctx_fresh;
+ void *my_ctx_prealloc = NULL;
+ unsigned char seed[32] = {0x17};
secp256k1_gej pubj;
secp256k1_ge pub;
secp256k1_scalar msg, key, nonce;
secp256k1_scalar sigr, sigs;
+ /* Fresh reference context for comparison */
+ my_ctx_fresh = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+
if (use_prealloc) {
- none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
- sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN));
- vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY));
- both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY));
- sttc_prealloc = malloc(secp256k1_context_preallocated_clone_size(secp256k1_context_no_precomp));
- CHECK(none_prealloc != NULL);
- CHECK(sign_prealloc != NULL);
- CHECK(vrfy_prealloc != NULL);
- CHECK(both_prealloc != NULL);
- CHECK(sttc_prealloc != NULL);
- none = secp256k1_context_preallocated_create(none_prealloc, SECP256K1_CONTEXT_NONE);
- sign = secp256k1_context_preallocated_create(sign_prealloc, SECP256K1_CONTEXT_SIGN);
- vrfy = secp256k1_context_preallocated_create(vrfy_prealloc, SECP256K1_CONTEXT_VERIFY);
- both = secp256k1_context_preallocated_create(both_prealloc, SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
- sttc = secp256k1_context_preallocated_clone(secp256k1_context_no_precomp, sttc_prealloc);
+ my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
+ CHECK(my_ctx_prealloc != NULL);
+ my_ctx = secp256k1_context_preallocated_create(my_ctx_prealloc, SECP256K1_CONTEXT_NONE);
} else {
- none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
- sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
- vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
- both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
- sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
+ my_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
}
- memset(&zero_pubkey, 0, sizeof(zero_pubkey));
+ /* Randomize and reset randomization */
+ CHECK(context_eq(my_ctx, my_ctx_fresh));
+ CHECK(secp256k1_context_randomize(my_ctx, seed) == 1);
+ CHECK(!context_eq(my_ctx, my_ctx_fresh));
+ CHECK(secp256k1_context_randomize(my_ctx, NULL) == 1);
+ CHECK(context_eq(my_ctx, my_ctx_fresh));
- ecount = 0;
- ecount2 = 10;
- secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2);
/* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */
- secp256k1_context_set_error_callback(sign, secp256k1_default_illegal_callback_fn, NULL);
- CHECK(sign->error_callback.fn != vrfy->error_callback.fn);
- CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn);
+ secp256k1_context_set_error_callback(my_ctx, secp256k1_default_illegal_callback_fn, NULL);
+ CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn);
+ CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn);
/* check if sizes for cloning are consistent */
- CHECK(secp256k1_context_preallocated_clone_size(none) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
- CHECK(secp256k1_context_preallocated_clone_size(sign) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN));
- CHECK(secp256k1_context_preallocated_clone_size(vrfy) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY));
- CHECK(secp256k1_context_preallocated_clone_size(both) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY));
- CHECK(secp256k1_context_preallocated_clone_size(sttc) >= sizeof(secp256k1_context));
+ CHECK(secp256k1_context_preallocated_clone_size(my_ctx) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
/*** clone and destroy all of them to make sure cloning was complete ***/
{
@@ -211,226 +346,170 @@ void run_context_tests(int use_prealloc) {
if (use_prealloc) {
/* clone into a non-preallocated context and then again into a new preallocated one. */
- ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp);
- free(none_prealloc); none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(none_prealloc != NULL);
- ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, none_prealloc); secp256k1_context_destroy(ctx_tmp);
-
- ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp);
- free(sign_prealloc); sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(sign_prealloc != NULL);
- ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, sign_prealloc); secp256k1_context_destroy(ctx_tmp);
-
- ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp);
- free(vrfy_prealloc); vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(vrfy_prealloc != NULL);
- ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, vrfy_prealloc); secp256k1_context_destroy(ctx_tmp);
-
- ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp);
- free(both_prealloc); both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(both_prealloc != NULL);
- ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, both_prealloc); secp256k1_context_destroy(ctx_tmp);
+ ctx_tmp = my_ctx;
+ my_ctx = secp256k1_context_clone(my_ctx);
+ CHECK(context_eq(ctx_tmp, my_ctx));
+ secp256k1_context_preallocated_destroy(ctx_tmp);
+
+ free(my_ctx_prealloc);
+ my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
+ CHECK(my_ctx_prealloc != NULL);
+ ctx_tmp = my_ctx;
+ my_ctx = secp256k1_context_preallocated_clone(my_ctx, my_ctx_prealloc);
+ CHECK(context_eq(ctx_tmp, my_ctx));
+ secp256k1_context_destroy(ctx_tmp);
} else {
/* clone into a preallocated context and then again into a new non-preallocated one. */
void *prealloc_tmp;
- prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL);
- ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
- ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp);
- free(prealloc_tmp);
-
- prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(prealloc_tmp != NULL);
- ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
- ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp);
- free(prealloc_tmp);
-
- prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL);
- ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
- ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp);
- free(prealloc_tmp);
-
- prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL);
- ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
- ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp);
+ prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
+ CHECK(prealloc_tmp != NULL);
+ ctx_tmp = my_ctx;
+ my_ctx = secp256k1_context_preallocated_clone(my_ctx, prealloc_tmp);
+ CHECK(context_eq(ctx_tmp, my_ctx));
+ secp256k1_context_destroy(ctx_tmp);
+
+ ctx_tmp = my_ctx;
+ my_ctx = secp256k1_context_clone(my_ctx);
+ CHECK(context_eq(ctx_tmp, my_ctx));
+ secp256k1_context_preallocated_destroy(ctx_tmp);
free(prealloc_tmp);
}
}
/* Verify that the error callback makes it across the clone. */
- CHECK(sign->error_callback.fn != vrfy->error_callback.fn);
- CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn);
+ CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn);
+ CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn);
/* And that it resets back to default. */
- secp256k1_context_set_error_callback(sign, NULL, NULL);
- CHECK(vrfy->error_callback.fn == sign->error_callback.fn);
+ secp256k1_context_set_error_callback(my_ctx, NULL, NULL);
+ CHECK(my_ctx->error_callback.fn == secp256k1_default_error_callback_fn);
+ CHECK(context_eq(my_ctx, my_ctx_fresh));
+
+ /* Verify that setting and resetting illegal callback works */
+ secp256k1_context_set_illegal_callback(my_ctx, counting_illegal_callback_fn, &dummy);
+ CHECK(my_ctx->illegal_callback.fn == counting_illegal_callback_fn);
+ CHECK(my_ctx->illegal_callback.data == &dummy);
+ secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL);
+ CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
+ CHECK(my_ctx->illegal_callback.data == NULL);
+ CHECK(context_eq(my_ctx, my_ctx_fresh));
/*** attempt to use them ***/
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
- secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key);
+ secp256k1_ecmult_gen(&my_ctx->ecmult_gen_ctx, &pubj, &key);
secp256k1_ge_set_gej(&pub, &pubj);
- /* Verify context-type checking illegal-argument errors. */
- memset(ctmp, 1, 32);
- CHECK(secp256k1_ec_pubkey_create(sttc, &pubkey, ctmp) == 0);
- CHECK(ecount == 1);
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1);
- VG_CHECK(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ecdsa_sign(sttc, &sig, ctmp, ctmp, NULL, NULL) == 0);
- CHECK(ecount == 2);
- VG_UNDEF(&sig, sizeof(sig));
- CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1);
- VG_CHECK(&sig, sizeof(sig));
- CHECK(ecount2 == 10);
- CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 1);
- CHECK(ecount2 == 10);
- CHECK(secp256k1_ecdsa_verify(sttc, &sig, ctmp, &pubkey) == 1);
- CHECK(ecount == 2);
- CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 1);
- CHECK(ecount2 == 10);
- CHECK(secp256k1_ec_pubkey_tweak_add(sttc, &pubkey, ctmp) == 1);
- CHECK(ecount == 2);
- CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 1);
- CHECK(ecount2 == 10);
- CHECK(secp256k1_ec_pubkey_negate(sttc, &pubkey) == 1);
- CHECK(ecount == 2);
- CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1);
- CHECK(ecount == 2);
- CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0);
- CHECK(ecount2 == 11);
- CHECK(secp256k1_ec_pubkey_negate(sttc, &zero_pubkey) == 0);
- CHECK(ecount == 3);
- CHECK(secp256k1_ec_pubkey_tweak_mul(sttc, &pubkey, ctmp) == 1);
- CHECK(ecount == 3);
- CHECK(secp256k1_context_randomize(sttc, ctmp) == 1);
- CHECK(ecount == 3);
- CHECK(secp256k1_context_randomize(sttc, NULL) == 1);
- CHECK(ecount == 3);
- CHECK(secp256k1_context_randomize(sign, ctmp) == 1);
- CHECK(ecount2 == 11);
- CHECK(secp256k1_context_randomize(sign, NULL) == 1);
- CHECK(ecount2 == 11);
- secp256k1_context_set_illegal_callback(sttc, NULL, NULL);
- secp256k1_context_set_illegal_callback(sign, NULL, NULL);
-
/* obtain a working nonce */
do {
random_scalar_order_test(&nonce);
- } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
+ } while(!secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
/* try signing */
- CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
- CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
+ CHECK(secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
/* try verifying */
CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg));
- CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg));
/* cleanup */
if (use_prealloc) {
- secp256k1_context_preallocated_destroy(none);
- secp256k1_context_preallocated_destroy(sign);
- secp256k1_context_preallocated_destroy(vrfy);
- secp256k1_context_preallocated_destroy(both);
- secp256k1_context_preallocated_destroy(sttc);
- free(none_prealloc);
- free(sign_prealloc);
- free(vrfy_prealloc);
- free(both_prealloc);
- free(sttc_prealloc);
+ secp256k1_context_preallocated_destroy(my_ctx);
+ free(my_ctx_prealloc);
} else {
- secp256k1_context_destroy(none);
- secp256k1_context_destroy(sign);
- secp256k1_context_destroy(vrfy);
- secp256k1_context_destroy(both);
- secp256k1_context_destroy(sttc);
+ secp256k1_context_destroy(my_ctx);
}
+ secp256k1_context_destroy(my_ctx_fresh);
+
/* Defined as no-op. */
secp256k1_context_destroy(NULL);
secp256k1_context_preallocated_destroy(NULL);
-
}
-void run_scratch_tests(void) {
+static void run_scratch_tests(void) {
const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
int32_t ecount = 0;
size_t checkpoint;
size_t checkpoint_2;
- secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_scratch_space *scratch;
secp256k1_scratch_space local_scratch;
- /* Test public API */
- secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
- scratch = secp256k1_scratch_space_create(none, 1000);
+ /* Test public API */
+ scratch = secp256k1_scratch_space_create(CTX, 1000);
CHECK(scratch != NULL);
CHECK(ecount == 0);
/* Test internal API */
- CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000);
- CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1));
+ CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000);
+ CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1));
CHECK(scratch->alloc_size == 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
/* Allocating 500 bytes succeeds */
- checkpoint = secp256k1_scratch_checkpoint(&none->error_callback, scratch);
- CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL);
- CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc);
- CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
+ checkpoint = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch);
+ CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL);
+ CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc);
+ CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
CHECK(scratch->alloc_size != 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
/* Allocating another 501 bytes fails */
- CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 501) == NULL);
- CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc);
- CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
+ CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 501) == NULL);
+ CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc);
+ CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
CHECK(scratch->alloc_size != 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
/* ...but it succeeds once we apply the checkpoint to undo it */
- secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint);
+ secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint);
CHECK(scratch->alloc_size == 0);
- CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000);
- CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL);
+ CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000);
+ CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL);
CHECK(scratch->alloc_size != 0);
/* try to apply a bad checkpoint */
- checkpoint_2 = secp256k1_scratch_checkpoint(&none->error_callback, scratch);
- secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint);
+ checkpoint_2 = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch);
+ secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint);
CHECK(ecount == 0);
- secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */
+ secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */
CHECK(ecount == 1);
- secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */
+ secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */
CHECK(ecount == 2);
/* try to use badly initialized scratch space */
- secp256k1_scratch_space_destroy(none, scratch);
+ secp256k1_scratch_space_destroy(CTX, scratch);
memset(&local_scratch, 0, sizeof(local_scratch));
scratch = &local_scratch;
- CHECK(!secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0));
+ CHECK(!secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0));
CHECK(ecount == 3);
- CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
+ CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) == NULL);
CHECK(ecount == 4);
- secp256k1_scratch_space_destroy(none, scratch);
+ secp256k1_scratch_space_destroy(CTX, scratch);
CHECK(ecount == 5);
/* Test that large integers do not wrap around in a bad way */
- scratch = secp256k1_scratch_space_create(none, 1000);
+ scratch = secp256k1_scratch_space_create(CTX, 1000);
/* Try max allocation with a large number of objects. Only makes sense if
* ALIGNMENT is greater than 1 because otherwise the objects take no extra
* space. */
- CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&none->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1));
+ CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1));
/* Try allocating SIZE_MAX to test wrap around which only happens if
* ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch
* space is too small. */
- CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, SIZE_MAX) == NULL);
- secp256k1_scratch_space_destroy(none, scratch);
+ CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, SIZE_MAX) == NULL);
+ secp256k1_scratch_space_destroy(CTX, scratch);
/* cleanup */
- secp256k1_scratch_space_destroy(none, NULL); /* no-op */
- secp256k1_context_destroy(none);
+ secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */
+
+ secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
+ secp256k1_context_set_error_callback(CTX, NULL, NULL);
}
-void run_ctz_tests(void) {
+static void run_ctz_tests(void) {
static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129};
static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef};
int shift;
@@ -451,7 +530,7 @@ void run_ctz_tests(void) {
/***** HASH TESTS *****/
-void run_sha256_known_output_tests(void) {
+static void run_sha256_known_output_tests(void) {
static const char *inputs[] = {
"", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
@@ -552,7 +631,7 @@ for x in digests:
print(x + ',')
```
*/
-void run_sha256_counter_tests(void) {
+static void run_sha256_counter_tests(void) {
static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno";
static const secp256k1_sha256 midstates[] = {
{{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda},
@@ -610,7 +689,7 @@ void run_sha256_counter_tests(void) {
}
}
-void run_hmac_sha256_tests(void) {
+static void run_hmac_sha256_tests(void) {
static const char *keys[6] = {
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
"\x4a\x65\x66\x65",
@@ -654,7 +733,7 @@ void run_hmac_sha256_tests(void) {
}
}
-void run_rfc6979_hmac_sha256_tests(void) {
+static void run_rfc6979_hmac_sha256_tests(void) {
static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0};
static const unsigned char out1[3][32] = {
{0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb},
@@ -695,9 +774,8 @@ void run_rfc6979_hmac_sha256_tests(void) {
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
}
-void run_tagged_sha256_tests(void) {
+static void run_tagged_sha256_tests(void) {
int ecount = 0;
- secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
unsigned char tag[32] = { 0 };
unsigned char msg[32] = { 0 };
unsigned char hash32[32];
@@ -708,28 +786,27 @@ void run_tagged_sha256_tests(void) {
0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3
};
- secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
/* API test */
- CHECK(secp256k1_tagged_sha256(none, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1);
- CHECK(secp256k1_tagged_sha256(none, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0);
+ CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1);
+ CHECK(secp256k1_tagged_sha256(CTX, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_tagged_sha256(none, hash32, NULL, 0, msg, sizeof(msg)) == 0);
+ CHECK(secp256k1_tagged_sha256(CTX, hash32, NULL, 0, msg, sizeof(msg)) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_tagged_sha256(none, hash32, tag, sizeof(tag), NULL, 0) == 0);
+ CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), NULL, 0) == 0);
CHECK(ecount == 3);
/* Static test vector */
memcpy(tag, "tag", 3);
memcpy(msg, "msg", 3);
- CHECK(secp256k1_tagged_sha256(none, hash32, tag, 3, msg, 3) == 1);
+ CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, 3, msg, 3) == 1);
CHECK(secp256k1_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0);
- secp256k1_context_destroy(none);
}
/***** RANDOM TESTS *****/
-void test_rand_bits(int rand32, int bits) {
+static void test_rand_bits(int rand32, int bits) {
/* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to
* get a false negative chance below once in a billion */
static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316};
@@ -764,7 +841,7 @@ void test_rand_bits(int rand32, int bits) {
}
/* Subrange must be a whole divisor of range, and at most 64 */
-void test_rand_int(uint32_t range, uint32_t subrange) {
+static void test_rand_int(uint32_t range, uint32_t subrange) {
/* (1-1/subrange)^rounds < 1/10^9 */
int rounds = (subrange * 2073) / 100;
int i;
@@ -780,7 +857,7 @@ void test_rand_int(uint32_t range, uint32_t subrange) {
CHECK(((~x) << (64 - subrange)) == 0);
}
-void run_rand_bits(void) {
+static void run_rand_bits(void) {
size_t b;
test_rand_bits(1, 32);
for (b = 1; b <= 32; b++) {
@@ -788,7 +865,7 @@ void run_rand_bits(void) {
}
}
-void run_rand_int(void) {
+static void run_rand_int(void) {
static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432};
static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64};
unsigned int m, s;
@@ -802,7 +879,7 @@ void run_rand_int(void) {
/***** MODINV TESTS *****/
/* Compute the modular inverse of (odd) x mod 2^64. */
-uint64_t modinv2p64(uint64_t x) {
+static uint64_t modinv2p64(uint64_t x) {
/* If w = 1/x mod 2^(2^L), then w*(2 - w*x) = 1/x mod 2^(2^(L+1)). See
* Hacker's Delight second edition, Henry S. Warren, Jr., pages 245-247 for
* why. Start with L=0, for which it is true for every odd x that
@@ -814,11 +891,12 @@ uint64_t modinv2p64(uint64_t x) {
return w;
}
-/* compute out = (a*b) mod m; if b=NULL, treat b=1.
+
+/* compute out = (a*b) mod m; if b=NULL, treat b=1; if m=NULL, treat m=infinity.
*
* Out is a 512-bit number (represented as 32 uint16_t's in LE order). The other
* arguments are 256-bit numbers (represented as 16 uint16_t's in LE order). */
-void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16_t* m) {
+static void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16_t* m) {
uint16_t mul[32];
uint64_t c = 0;
int i, j;
@@ -856,51 +934,53 @@ void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16
}
}
- /* Compute the highest set bit in m. */
- for (i = 255; i >= 0; --i) {
- if ((m[i >> 4] >> (i & 15)) & 1) {
- m_bitlen = i;
- break;
+ if (m) {
+ /* Compute the highest set bit in m. */
+ for (i = 255; i >= 0; --i) {
+ if ((m[i >> 4] >> (i & 15)) & 1) {
+ m_bitlen = i;
+ break;
+ }
}
- }
- /* Try do mul -= m<<i, for i going down to 0, whenever the result is not negative */
- for (i = mul_bitlen - m_bitlen; i >= 0; --i) {
- uint16_t mul2[32];
- int64_t cs;
-
- /* Compute mul2 = mul - m<<i. */
- cs = 0; /* accumulator */
- for (j = 0; j < 32; ++j) { /* j loops over the output limbs in mul2. */
- /* Compute sub: the 16 bits in m that will be subtracted from mul2[j]. */
- uint16_t sub = 0;
- int p;
- for (p = 0; p < 16; ++p) { /* p loops over the bit positions in mul2[j]. */
- int bitpos = j * 16 - i + p; /* bitpos is the correspond bit position in m. */
- if (bitpos >= 0 && bitpos < 256) {
- sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p;
+ /* Try do mul -= m<<i, for i going down to 0, whenever the result is not negative */
+ for (i = mul_bitlen - m_bitlen; i >= 0; --i) {
+ uint16_t mul2[32];
+ int64_t cs;
+
+ /* Compute mul2 = mul - m<<i. */
+ cs = 0; /* accumulator */
+ for (j = 0; j < 32; ++j) { /* j loops over the output limbs in mul2. */
+ /* Compute sub: the 16 bits in m that will be subtracted from mul2[j]. */
+ uint16_t sub = 0;
+ int p;
+ for (p = 0; p < 16; ++p) { /* p loops over the bit positions in mul2[j]. */
+ int bitpos = j * 16 - i + p; /* bitpos is the correspond bit position in m. */
+ if (bitpos >= 0 && bitpos < 256) {
+ sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p;
+ }
}
+ /* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */
+ cs += mul[j];
+ cs -= sub;
+ mul2[j] = (cs & 0xFFFF);
+ cs >>= 16;
+ }
+ /* If remainder of subtraction is 0, set mul = mul2. */
+ if (cs == 0) {
+ memcpy(mul, mul2, sizeof(mul));
}
- /* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */
- cs += mul[j];
- cs -= sub;
- mul2[j] = (cs & 0xFFFF);
- cs >>= 16;
}
- /* If remainder of subtraction is 0, set mul = mul2. */
- if (cs == 0) {
- memcpy(mul, mul2, sizeof(mul));
+ /* Sanity check: test that all limbs higher than m's highest are zero */
+ for (i = (m_bitlen >> 4) + 1; i < 32; ++i) {
+ CHECK(mul[i] == 0);
}
}
- /* Sanity check: test that all limbs higher than m's highest are zero */
- for (i = (m_bitlen >> 4) + 1; i < 32; ++i) {
- CHECK(mul[i] == 0);
- }
memcpy(out, mul, 32);
}
/* Convert a 256-bit number represented as 16 uint16_t's to signed30 notation. */
-void uint16_to_signed30(secp256k1_modinv32_signed30* out, const uint16_t* in) {
+static void uint16_to_signed30(secp256k1_modinv32_signed30* out, const uint16_t* in) {
int i;
memset(out->v, 0, sizeof(out->v));
for (i = 0; i < 256; ++i) {
@@ -909,7 +989,7 @@ void uint16_to_signed30(secp256k1_modinv32_signed30* out, const uint16_t* in) {
}
/* Convert a 256-bit number in signed30 notation to a representation as 16 uint16_t's. */
-void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) {
+static void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) {
int i;
memset(out, 0, 32);
for (i = 0; i < 256; ++i) {
@@ -918,7 +998,7 @@ void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) {
}
/* Randomly mutate the sign of limbs in signed30 representation, without changing the value. */
-void mutate_sign_signed30(secp256k1_modinv32_signed30* x) {
+static void mutate_sign_signed30(secp256k1_modinv32_signed30* x) {
int i;
for (i = 0; i < 16; ++i) {
int pos = secp256k1_testrand_bits(3);
@@ -933,7 +1013,7 @@ void mutate_sign_signed30(secp256k1_modinv32_signed30* x) {
}
/* Test secp256k1_modinv32{_var}, using inputs in 16-bit limb format, and returning inverse. */
-void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) {
+static void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) {
uint16_t tmp[16];
secp256k1_modinv32_signed30 x;
secp256k1_modinv32_modinfo m;
@@ -942,12 +1022,32 @@ void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod
uint16_to_signed30(&x, in);
nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4] | x.v[5] | x.v[6] | x.v[7] | x.v[8]) != 0;
uint16_to_signed30(&m.modulus, mod);
- mutate_sign_signed30(&m.modulus);
/* compute 1/modulus mod 2^30 */
m.modulus_inv30 = modinv2p64(m.modulus.v[0]) & 0x3fffffff;
CHECK(((m.modulus_inv30 * m.modulus.v[0]) & 0x3fffffff) == 1);
+ /* Test secp256k1_jacobi32_maybe_var. */
+ if (nonzero) {
+ int jac;
+ uint16_t sqr[16], negone[16];
+ mulmod256(sqr, in, in, mod);
+ uint16_to_signed30(&x, sqr);
+ /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */
+ jac = secp256k1_jacobi32_maybe_var(&x, &m);
+ CHECK(jac == 0 || jac == 1);
+ /* Then compute the jacobi symbol of -(in^2). x and -x have opposite
+ * jacobi symbols if and only if (mod % 4) == 3. */
+ negone[0] = mod[0] - 1;
+ for (i = 1; i < 16; ++i) negone[i] = mod[i];
+ mulmod256(sqr, sqr, negone, mod);
+ uint16_to_signed30(&x, sqr);
+ jac = secp256k1_jacobi32_maybe_var(&x, &m);
+ CHECK(jac == 0 || jac == 1 - (mod[0] & 2));
+ }
+
+ uint16_to_signed30(&x, in);
+ mutate_sign_signed30(&m.modulus);
for (vartime = 0; vartime < 2; ++vartime) {
/* compute inverse */
(vartime ? secp256k1_modinv32_var : secp256k1_modinv32)(&x, &m);
@@ -971,7 +1071,7 @@ void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod
#ifdef SECP256K1_WIDEMUL_INT128
/* Convert a 256-bit number represented as 16 uint16_t's to signed62 notation. */
-void uint16_to_signed62(secp256k1_modinv64_signed62* out, const uint16_t* in) {
+static void uint16_to_signed62(secp256k1_modinv64_signed62* out, const uint16_t* in) {
int i;
memset(out->v, 0, sizeof(out->v));
for (i = 0; i < 256; ++i) {
@@ -980,7 +1080,7 @@ void uint16_to_signed62(secp256k1_modinv64_signed62* out, const uint16_t* in) {
}
/* Convert a 256-bit number in signed62 notation to a representation as 16 uint16_t's. */
-void signed62_to_uint16(uint16_t* out, const secp256k1_modinv64_signed62* in) {
+static void signed62_to_uint16(uint16_t* out, const secp256k1_modinv64_signed62* in) {
int i;
memset(out, 0, 32);
for (i = 0; i < 256; ++i) {
@@ -989,7 +1089,7 @@ void signed62_to_uint16(uint16_t* out, const secp256k1_modinv64_signed62* in) {
}
/* Randomly mutate the sign of limbs in signed62 representation, without changing the value. */
-void mutate_sign_signed62(secp256k1_modinv64_signed62* x) {
+static void mutate_sign_signed62(secp256k1_modinv64_signed62* x) {
static const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
int i;
for (i = 0; i < 8; ++i) {
@@ -1005,7 +1105,7 @@ void mutate_sign_signed62(secp256k1_modinv64_signed62* x) {
}
/* Test secp256k1_modinv64{_var}, using inputs in 16-bit limb format, and returning inverse. */
-void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) {
+static void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) {
static const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
uint16_t tmp[16];
secp256k1_modinv64_signed62 x;
@@ -1015,12 +1115,32 @@ void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod
uint16_to_signed62(&x, in);
nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4]) != 0;
uint16_to_signed62(&m.modulus, mod);
- mutate_sign_signed62(&m.modulus);
/* compute 1/modulus mod 2^62 */
m.modulus_inv62 = modinv2p64(m.modulus.v[0]) & M62;
CHECK(((m.modulus_inv62 * m.modulus.v[0]) & M62) == 1);
+ /* Test secp256k1_jacobi64_maybe_var. */
+ if (nonzero) {
+ int jac;
+ uint16_t sqr[16], negone[16];
+ mulmod256(sqr, in, in, mod);
+ uint16_to_signed62(&x, sqr);
+ /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */
+ jac = secp256k1_jacobi64_maybe_var(&x, &m);
+ CHECK(jac == 0 || jac == 1);
+ /* Then compute the jacobi symbol of -(in^2). x and -x have opposite
+ * jacobi symbols if and only if (mod % 4) == 3. */
+ negone[0] = mod[0] - 1;
+ for (i = 1; i < 16; ++i) negone[i] = mod[i];
+ mulmod256(sqr, sqr, negone, mod);
+ uint16_to_signed62(&x, sqr);
+ jac = secp256k1_jacobi64_maybe_var(&x, &m);
+ CHECK(jac == 0 || jac == 1 - (mod[0] & 2));
+ }
+
+ uint16_to_signed62(&x, in);
+ mutate_sign_signed62(&m.modulus);
for (vartime = 0; vartime < 2; ++vartime) {
/* compute inverse */
(vartime ? secp256k1_modinv64_var : secp256k1_modinv64)(&x, &m);
@@ -1044,7 +1164,7 @@ void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod
#endif
/* test if a and b are coprime */
-int coprime(const uint16_t* a, const uint16_t* b) {
+static int coprime(const uint16_t* a, const uint16_t* b) {
uint16_t x[16], y[16], t[16];
int i;
int iszero;
@@ -1074,7 +1194,7 @@ int coprime(const uint16_t* a, const uint16_t* b) {
return 1;
}
-void run_modinv_tests(void) {
+static void run_modinv_tests(void) {
/* Fixed test cases. Each tuple is (input, modulus, output), each as 16x16 bits in LE order. */
static const uint16_t CASES[][3][16] = {
/* Test cases triggering edge cases in divsteps */
@@ -1676,7 +1796,7 @@ void run_modinv_tests(void) {
#endif
}
- for (i = 0; i < 100 * count; ++i) {
+ for (i = 0; i < 100 * COUNT; ++i) {
/* 256-bit numbers in 16-uint16_t's notation */
static const uint16_t ZERO[16] = {0};
uint16_t xd[16]; /* the number (in range [0,2^256)) to be inverted */
@@ -1701,7 +1821,7 @@ void run_modinv_tests(void) {
#endif
/* In a few cases, also test with input=0 */
- if (i < count) {
+ if (i < COUNT) {
test_modinv32_uint16(id, ZERO, md);
#ifdef SECP256K1_WIDEMUL_INT128
test_modinv64_uint16(id, ZERO, md);
@@ -1710,10 +1830,335 @@ void run_modinv_tests(void) {
}
}
-/***** SCALAR TESTS *****/
+/***** INT128 TESTS *****/
+
+#ifdef SECP256K1_WIDEMUL_INT128
+/* Add two 256-bit numbers (represented as 16 uint16_t's in LE order) together mod 2^256. */
+static void add256(uint16_t* out, const uint16_t* a, const uint16_t* b) {
+ int i;
+ uint32_t carry = 0;
+ for (i = 0; i < 16; ++i) {
+ carry += a[i];
+ carry += b[i];
+ out[i] = carry;
+ carry >>= 16;
+ }
+}
+
+/* Negate a 256-bit number (represented as 16 uint16_t's in LE order) mod 2^256. */
+static void neg256(uint16_t* out, const uint16_t* a) {
+ int i;
+ uint32_t carry = 1;
+ for (i = 0; i < 16; ++i) {
+ carry += (uint16_t)~a[i];
+ out[i] = carry;
+ carry >>= 16;
+ }
+}
+
+/* Right-shift a 256-bit number (represented as 16 uint16_t's in LE order). */
+static void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) {
+ uint16_t sign = sign_extend && (a[15] >> 15);
+ int i, j;
+ for (i = 15; i >= 0; --i) {
+ uint16_t v = 0;
+ for (j = 0; j < 16; ++j) {
+ int frompos = i*16 + j + n;
+ if (frompos >= 256) {
+ v |= sign << j;
+ } else {
+ v |= ((uint16_t)((a[frompos >> 4] >> (frompos & 15)) & 1)) << j;
+ }
+ }
+ out[i] = v;
+ }
+}
+
+/* Load a 64-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */
+static void load256u64(uint16_t* out, uint64_t v, int is_signed) {
+ int i;
+ uint64_t sign = is_signed && (v >> 63) ? UINT64_MAX : 0;
+ for (i = 0; i < 4; ++i) {
+ out[i] = v >> (16 * i);
+ }
+ for (i = 4; i < 16; ++i) {
+ out[i] = sign;
+ }
+}
+
+/* Load a 128-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */
+static void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) {
+ int i;
+ uint64_t sign = is_signed && (hi >> 63) ? UINT64_MAX : 0;
+ for (i = 0; i < 4; ++i) {
+ out[i] = lo >> (16 * i);
+ }
+ for (i = 4; i < 8; ++i) {
+ out[i] = hi >> (16 * (i - 4));
+ }
+ for (i = 8; i < 16; ++i) {
+ out[i] = sign;
+ }
+}
+
+/* Check whether the 256-bit value represented by array of 16-bit values is in range -2^127 < v < 2^127. */
+static int int256is127(const uint16_t* v) {
+ int all_0 = ((v[7] & 0x8000) == 0), all_1 = ((v[7] & 0x8000) == 0x8000);
+ int i;
+ for (i = 8; i < 16; ++i) {
+ if (v[i] != 0) all_0 = 0;
+ if (v[i] != 0xffff) all_1 = 0;
+ }
+ return all_0 || all_1;
+}
+
+static void load256u128(uint16_t* out, const secp256k1_uint128* v) {
+ uint64_t lo = secp256k1_u128_to_u64(v), hi = secp256k1_u128_hi_u64(v);
+ load256two64(out, hi, lo, 0);
+}
+
+static void load256i128(uint16_t* out, const secp256k1_int128* v) {
+ uint64_t lo;
+ int64_t hi;
+ secp256k1_int128 c = *v;
+ lo = secp256k1_i128_to_u64(&c);
+ secp256k1_i128_rshift(&c, 64);
+ hi = secp256k1_i128_to_i64(&c);
+ load256two64(out, hi, lo, 1);
+}
+
+static void run_int128_test_case(void) {
+ unsigned char buf[32];
+ uint64_t v[4];
+ secp256k1_int128 swa, swz;
+ secp256k1_uint128 uwa, uwz;
+ uint64_t ub, uc;
+ int64_t sb, sc;
+ uint16_t rswa[16], rswz[32], rswr[32], ruwa[16], ruwz[32], ruwr[32];
+ uint16_t rub[16], ruc[16], rsb[16], rsc[16];
+ int i;
+
+ /* Generate 32-byte random value. */
+ secp256k1_testrand256_test(buf);
+ /* Convert into 4 64-bit integers. */
+ for (i = 0; i < 4; ++i) {
+ uint64_t vi = 0;
+ int j;
+ for (j = 0; j < 8; ++j) vi = (vi << 8) + buf[8*i + j];
+ v[i] = vi;
+ }
+ /* Convert those into a 128-bit value and two 64-bit values (signed and unsigned). */
+ secp256k1_u128_load(&uwa, v[1], v[0]);
+ secp256k1_i128_load(&swa, v[1], v[0]);
+ ub = v[2];
+ sb = v[2];
+ uc = v[3];
+ sc = v[3];
+ /* Load those also into 16-bit array representations. */
+ load256u128(ruwa, &uwa);
+ load256i128(rswa, &swa);
+ load256u64(rub, ub, 0);
+ load256u64(rsb, sb, 1);
+ load256u64(ruc, uc, 0);
+ load256u64(rsc, sc, 1);
+ /* test secp256k1_u128_mul */
+ mulmod256(ruwr, rub, ruc, NULL);
+ secp256k1_u128_mul(&uwz, ub, uc);
+ load256u128(ruwz, &uwz);
+ CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0);
+ /* test secp256k1_u128_accum_mul */
+ mulmod256(ruwr, rub, ruc, NULL);
+ add256(ruwr, ruwr, ruwa);
+ uwz = uwa;
+ secp256k1_u128_accum_mul(&uwz, ub, uc);
+ load256u128(ruwz, &uwz);
+ CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0);
+ /* test secp256k1_u128_accum_u64 */
+ add256(ruwr, rub, ruwa);
+ uwz = uwa;
+ secp256k1_u128_accum_u64(&uwz, ub);
+ load256u128(ruwz, &uwz);
+ CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0);
+ /* test secp256k1_u128_rshift */
+ rshift256(ruwr, ruwa, uc % 128, 0);
+ uwz = uwa;
+ secp256k1_u128_rshift(&uwz, uc % 128);
+ load256u128(ruwz, &uwz);
+ CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0);
+ /* test secp256k1_u128_to_u64 */
+ CHECK(secp256k1_u128_to_u64(&uwa) == v[0]);
+ /* test secp256k1_u128_hi_u64 */
+ CHECK(secp256k1_u128_hi_u64(&uwa) == v[1]);
+ /* test secp256k1_u128_from_u64 */
+ secp256k1_u128_from_u64(&uwz, ub);
+ load256u128(ruwz, &uwz);
+ CHECK(secp256k1_memcmp_var(rub, ruwz, 16) == 0);
+ /* test secp256k1_u128_check_bits */
+ {
+ int uwa_bits = 0;
+ int j;
+ for (j = 0; j < 128; ++j) {
+ if (ruwa[j / 16] >> (j % 16)) uwa_bits = 1 + j;
+ }
+ for (j = 0; j < 128; ++j) {
+ CHECK(secp256k1_u128_check_bits(&uwa, j) == (uwa_bits <= j));
+ }
+ }
+ /* test secp256k1_i128_mul */
+ mulmod256(rswr, rsb, rsc, NULL);
+ secp256k1_i128_mul(&swz, sb, sc);
+ load256i128(rswz, &swz);
+ CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0);
+ /* test secp256k1_i128_accum_mul */
+ mulmod256(rswr, rsb, rsc, NULL);
+ add256(rswr, rswr, rswa);
+ if (int256is127(rswr)) {
+ swz = swa;
+ secp256k1_i128_accum_mul(&swz, sb, sc);
+ load256i128(rswz, &swz);
+ CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0);
+ }
+ /* test secp256k1_i128_det */
+ {
+ uint16_t rsd[16], rse[16], rst[32];
+ int64_t sd = v[0], se = v[1];
+ load256u64(rsd, sd, 1);
+ load256u64(rse, se, 1);
+ mulmod256(rst, rsc, rsd, NULL);
+ neg256(rst, rst);
+ mulmod256(rswr, rsb, rse, NULL);
+ add256(rswr, rswr, rst);
+ secp256k1_i128_det(&swz, sb, sc, sd, se);
+ load256i128(rswz, &swz);
+ CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0);
+ }
+ /* test secp256k1_i128_rshift */
+ rshift256(rswr, rswa, uc % 127, 1);
+ swz = swa;
+ secp256k1_i128_rshift(&swz, uc % 127);
+ load256i128(rswz, &swz);
+ CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0);
+ /* test secp256k1_i128_to_u64 */
+ CHECK(secp256k1_i128_to_u64(&swa) == v[0]);
+ /* test secp256k1_i128_from_i64 */
+ secp256k1_i128_from_i64(&swz, sb);
+ load256i128(rswz, &swz);
+ CHECK(secp256k1_memcmp_var(rsb, rswz, 16) == 0);
+ /* test secp256k1_i128_to_i64 */
+ CHECK(secp256k1_i128_to_i64(&swz) == sb);
+ /* test secp256k1_i128_eq_var */
+ {
+ int expect = (uc & 1);
+ swz = swa;
+ if (!expect) {
+ /* Make sure swz != swa */
+ uint64_t v0c = v[0], v1c = v[1];
+ if (ub & 64) {
+ v1c ^= (((uint64_t)1) << (ub & 63));
+ } else {
+ v0c ^= (((uint64_t)1) << (ub & 63));
+ }
+ secp256k1_i128_load(&swz, v1c, v0c);
+ }
+ CHECK(secp256k1_i128_eq_var(&swa, &swz) == expect);
+ }
+ /* test secp256k1_i128_check_pow2 (sign == 1) */
+ {
+ int expect = (uc & 1);
+ int pos = ub % 127;
+ if (expect) {
+ /* If expect==1, set swz to exactly 2^pos. */
+ uint64_t hi = 0;
+ uint64_t lo = 0;
+ if (pos >= 64) {
+ hi = (((uint64_t)1) << (pos & 63));
+ } else {
+ lo = (((uint64_t)1) << (pos & 63));
+ }
+ secp256k1_i128_load(&swz, hi, lo);
+ } else {
+ /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal 2^pos. */
+ if (pos >= 64) {
+ if ((v[1] == (((uint64_t)1) << (pos & 63))) && v[0] == 0) expect = 1;
+ } else {
+ if ((v[0] == (((uint64_t)1) << (pos & 63))) && v[1] == 0) expect = 1;
+ }
+ swz = swa;
+ }
+ CHECK(secp256k1_i128_check_pow2(&swz, pos, 1) == expect);
+ }
+ /* test secp256k1_i128_check_pow2 (sign == -1) */
+ {
+ int expect = (uc & 1);
+ int pos = ub % 127;
+ if (expect) {
+ /* If expect==1, set swz to exactly -2^pos. */
+ uint64_t hi = ~(uint64_t)0;
+ uint64_t lo = ~(uint64_t)0;
+ if (pos >= 64) {
+ hi <<= (pos & 63);
+ lo = 0;
+ } else {
+ lo <<= (pos & 63);
+ }
+ secp256k1_i128_load(&swz, hi, lo);
+ } else {
+ /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal -2^pos. */
+ if (pos >= 64) {
+ if ((v[1] == ((~(uint64_t)0) << (pos & 63))) && v[0] == 0) expect = 1;
+ } else {
+ if ((v[0] == ((~(uint64_t)0) << (pos & 63))) && v[1] == ~(uint64_t)0) expect = 1;
+ }
+ swz = swa;
+ }
+ CHECK(secp256k1_i128_check_pow2(&swz, pos, -1) == expect);
+ }
+}
+
+static void run_int128_tests(void) {
+ { /* secp256k1_u128_accum_mul */
+ secp256k1_uint128 res;
+
+ /* Check secp256k1_u128_accum_mul overflow */
+ secp256k1_u128_mul(&res, UINT64_MAX, UINT64_MAX);
+ secp256k1_u128_accum_mul(&res, UINT64_MAX, UINT64_MAX);
+ CHECK(secp256k1_u128_to_u64(&res) == 2);
+ CHECK(secp256k1_u128_hi_u64(&res) == 18446744073709551612U);
+ }
+ { /* secp256k1_u128_accum_mul */
+ secp256k1_int128 res;
+
+ /* Compute INT128_MAX = 2^127 - 1 with secp256k1_i128_accum_mul */
+ secp256k1_i128_mul(&res, INT64_MAX, INT64_MAX);
+ secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MAX);
+ CHECK(secp256k1_i128_to_u64(&res) == 2);
+ secp256k1_i128_accum_mul(&res, 4, 9223372036854775807);
+ secp256k1_i128_accum_mul(&res, 1, 1);
+ CHECK(secp256k1_i128_to_u64(&res) == UINT64_MAX);
+ secp256k1_i128_rshift(&res, 64);
+ CHECK(secp256k1_i128_to_i64(&res) == INT64_MAX);
+
+ /* Compute INT128_MIN = - 2^127 with secp256k1_i128_accum_mul */
+ secp256k1_i128_mul(&res, INT64_MAX, INT64_MIN);
+ CHECK(secp256k1_i128_to_u64(&res) == (uint64_t)INT64_MIN);
+ secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MIN);
+ CHECK(secp256k1_i128_to_u64(&res) == 0);
+ secp256k1_i128_accum_mul(&res, 2, INT64_MIN);
+ CHECK(secp256k1_i128_to_u64(&res) == 0);
+ secp256k1_i128_rshift(&res, 64);
+ CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN);
+ }
+ {
+ /* Randomized tests. */
+ int i;
+ for (i = 0; i < 256 * COUNT; ++i) run_int128_test_case();
+ }
+}
+#endif
+/***** SCALAR TESTS *****/
-void scalar_test(void) {
+static void scalar_test(void) {
secp256k1_scalar s;
secp256k1_scalar s1;
secp256k1_scalar s2;
@@ -1878,7 +2323,7 @@ void scalar_test(void) {
}
-void run_scalar_set_b32_seckey_tests(void) {
+static void run_scalar_set_b32_seckey_tests(void) {
unsigned char b32[32];
secp256k1_scalar s1;
secp256k1_scalar s2;
@@ -1895,12 +2340,12 @@ void run_scalar_set_b32_seckey_tests(void) {
CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0);
}
-void run_scalar_tests(void) {
+static void run_scalar_tests(void) {
int i;
- for (i = 0; i < 128 * count; i++) {
+ for (i = 0; i < 128 * COUNT; i++) {
scalar_test();
}
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
run_scalar_set_b32_seckey_tests();
}
@@ -2503,7 +2948,7 @@ void run_scalar_tests(void) {
/***** FIELD TESTS *****/
-void random_fe(secp256k1_fe *x) {
+static void random_fe(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_testrand256(bin);
@@ -2513,7 +2958,7 @@ void random_fe(secp256k1_fe *x) {
} while(1);
}
-void random_fe_test(secp256k1_fe *x) {
+static void random_fe_test(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_testrand256_test(bin);
@@ -2523,7 +2968,7 @@ void random_fe_test(secp256k1_fe *x) {
} while(1);
}
-void random_fe_non_zero(secp256k1_fe *nz) {
+static void random_fe_non_zero(secp256k1_fe *nz) {
int tries = 10;
while (--tries >= 0) {
random_fe(nz);
@@ -2536,7 +2981,7 @@ void random_fe_non_zero(secp256k1_fe *nz) {
CHECK(tries >= 0);
}
-void random_fe_non_square(secp256k1_fe *ns) {
+static void random_fe_non_square(secp256k1_fe *ns) {
secp256k1_fe r;
random_fe_non_zero(ns);
if (secp256k1_fe_sqrt(&r, ns)) {
@@ -2544,7 +2989,7 @@ void random_fe_non_square(secp256k1_fe *ns) {
}
}
-int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
+static int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe an = *a;
secp256k1_fe bn = *b;
secp256k1_fe_normalize_weak(&an);
@@ -2552,7 +2997,7 @@ int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
return secp256k1_fe_equal_var(&an, &bn);
}
-void run_field_convert(void) {
+static void run_field_convert(void) {
static const unsigned char b32[32] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
@@ -2583,7 +3028,7 @@ void run_field_convert(void) {
}
/* Returns true if two field elements have the same representation. */
-int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) {
+static int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) {
int ret = 1;
#ifdef VERIFY
ret &= (a->magnitude == b->magnitude);
@@ -2594,7 +3039,7 @@ int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) {
return ret;
}
-void run_field_half(void) {
+static void run_field_half(void) {
secp256k1_fe t, u;
int m;
@@ -2643,14 +3088,15 @@ void run_field_half(void) {
}
}
-void run_field_misc(void) {
+static void run_field_misc(void) {
secp256k1_fe x;
secp256k1_fe y;
secp256k1_fe z;
secp256k1_fe q;
+ int v;
secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5);
int i, j;
- for (i = 0; i < 1000 * count; i++) {
+ for (i = 0; i < 1000 * COUNT; i++) {
secp256k1_fe_storage xs, ys, zs;
if (i & 1) {
random_fe(&x);
@@ -2658,6 +3104,14 @@ void run_field_misc(void) {
random_fe_test(&x);
}
random_fe_non_zero(&y);
+ v = secp256k1_testrand_bits(15);
+ /* Test that fe_add_int is equivalent to fe_set_int + fe_add. */
+ secp256k1_fe_set_int(&q, v); /* q = v */
+ z = x; /* z = x */
+ secp256k1_fe_add(&z, &q); /* z = x+v */
+ q = x; /* q = x */
+ secp256k1_fe_add_int(&q, v); /* q = x+v */
+ CHECK(check_fe_equal(&q, &z));
/* Test the fe equality and comparison operations. */
CHECK(secp256k1_fe_cmp_var(&x, &x) == 0);
CHECK(secp256k1_fe_equal_var(&x, &x));
@@ -2735,7 +3189,7 @@ void run_field_misc(void) {
}
}
-void test_fe_mul(const secp256k1_fe* a, const secp256k1_fe* b, int use_sqr)
+static void test_fe_mul(const secp256k1_fe* a, const secp256k1_fe* b, int use_sqr)
{
secp256k1_fe c, an, bn;
/* Variables in BE 32-byte format. */
@@ -2778,9 +3232,9 @@ void test_fe_mul(const secp256k1_fe* a, const secp256k1_fe* b, int use_sqr)
CHECK(secp256k1_memcmp_var(t16, c16, 32) == 0);
}
-void run_fe_mul(void) {
+static void run_fe_mul(void) {
int i;
- for (i = 0; i < 100 * count; ++i) {
+ for (i = 0; i < 100 * COUNT; ++i) {
secp256k1_fe a, b, c, d;
random_fe(&a);
random_field_element_magnitude(&a);
@@ -2799,7 +3253,7 @@ void run_fe_mul(void) {
}
}
-void run_sqr(void) {
+static void run_sqr(void) {
secp256k1_fe x, s;
{
@@ -2815,7 +3269,7 @@ void run_sqr(void) {
}
}
-void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) {
+static void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) {
secp256k1_fe r1, r2;
int v = secp256k1_fe_sqrt(&r1, a);
CHECK((v == 0) == (k == NULL));
@@ -2829,7 +3283,7 @@ void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) {
}
}
-void run_sqrt(void) {
+static void run_sqrt(void) {
secp256k1_fe ns, x, s, t;
int i;
@@ -2851,11 +3305,13 @@ void run_sqrt(void) {
for (i = 0; i < 10; i++) {
int j;
random_fe_non_square(&ns);
- for (j = 0; j < count; j++) {
+ for (j = 0; j < COUNT; j++) {
random_fe(&x);
secp256k1_fe_sqr(&s, &x);
+ CHECK(secp256k1_fe_is_square_var(&s));
test_sqrt(&s, &x);
secp256k1_fe_negate(&t, &s, 1);
+ CHECK(!secp256k1_fe_is_square_var(&t));
test_sqrt(&t, NULL);
secp256k1_fe_mul(&t, &s, &ns);
test_sqrt(&t, NULL);
@@ -2882,7 +3338,7 @@ static const secp256k1_fe fe_minus_one = SECP256K1_FE_CONST(
* for x!=0 and x!=1: 1/(1/x - 1) + 1 == -1/(x-1)
*/
-void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int var)
+static void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int var)
{
secp256k1_scalar l, r, t;
@@ -2904,7 +3360,7 @@ void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int v
CHECK(secp256k1_scalar_is_zero(&l)); /* l == 0 */
}
-void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var)
+static void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var)
{
secp256k1_fe l, r, t;
@@ -2924,12 +3380,12 @@ void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var)
(var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&r, &r); /* r = 1/(x-1) */
secp256k1_fe_add(&l, &fe_minus_one); /* l = 1/x-1 */
(var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, &l); /* l = 1/(1/x-1) */
- secp256k1_fe_add(&l, &secp256k1_fe_one); /* l = 1/(1/x-1)+1 */
+ secp256k1_fe_add_int(&l, 1); /* l = 1/(1/x-1)+1 */
secp256k1_fe_add(&l, &r); /* l = 1/(1/x-1)+1 + 1/(x-1) */
CHECK(secp256k1_fe_normalizes_to_zero_var(&l)); /* l == 0 */
}
-void run_inverse_tests(void)
+static void run_inverse_tests(void)
{
/* Fixed test cases for field inverses: pairs of (x, 1/x) mod p. */
static const secp256k1_fe fe_cases[][2] = {
@@ -3163,7 +3619,7 @@ void run_inverse_tests(void)
}
/* test 128*count random inputs; half with testrand256_test, half with testrand256 */
for (testrand = 0; testrand <= 1; ++testrand) {
- for (i = 0; i < 64 * count; ++i) {
+ for (i = 0; i < 64 * COUNT; ++i) {
(testrand ? secp256k1_testrand256_test : secp256k1_testrand256)(b32);
secp256k1_scalar_set_b32(&x_scalar, b32, NULL);
secp256k1_fe_set_b32(&x_fe, b32);
@@ -3177,7 +3633,7 @@ void run_inverse_tests(void)
/***** GROUP TESTS *****/
-void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
+static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
CHECK(a->infinity == b->infinity);
if (a->infinity) {
return;
@@ -3187,7 +3643,7 @@ void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
}
/* This compares jacobian points including their Z, not just their geometric meaning. */
-int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) {
+static int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) {
secp256k1_gej a2;
secp256k1_gej b2;
int ret = 1;
@@ -3208,7 +3664,7 @@ int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) {
return ret;
}
-void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
+static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
secp256k1_fe z2s;
secp256k1_fe u1, u2, s1, s2;
CHECK(a->infinity == b->infinity);
@@ -3225,7 +3681,7 @@ void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
CHECK(secp256k1_fe_equal_var(&s1, &s2));
}
-void test_ge(void) {
+static void test_ge(void) {
int i, i1;
int runs = 6;
/* 25 points are used:
@@ -3234,8 +3690,8 @@ void test_ge(void) {
* negation, and then those two again but with randomized Z coordinate.
* - The same is then done for lambda*p1 and lambda^2*p1.
*/
- secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
- secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
+ secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
+ secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
secp256k1_fe zf;
secp256k1_fe zfi2, zfi3;
@@ -3358,7 +3814,7 @@ void test_ge(void) {
/* Test adding all points together in random order equals infinity. */
{
secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY;
- secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej));
+ secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej));
for (i = 0; i < 4 * runs + 1; i++) {
gej_shuffled[i] = gej[i];
}
@@ -3379,7 +3835,7 @@ void test_ge(void) {
/* Test batch gej -> ge conversion without known z ratios. */
{
- secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
+ secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1);
for (i = 0; i < 4 * runs + 1; i++) {
secp256k1_fe s;
@@ -3424,8 +3880,7 @@ void test_ge(void) {
free(gej);
}
-
-void test_intialized_inf(void) {
+static void test_intialized_inf(void) {
secp256k1_ge p;
secp256k1_gej pj, npj, infj1, infj2, infj3;
secp256k1_fe zinv;
@@ -3457,7 +3912,7 @@ void test_intialized_inf(void) {
}
-void test_add_neg_y_diff_x(void) {
+static void test_add_neg_y_diff_x(void) {
/* The point of this test is to check that we can add two points
* whose y-coordinates are negatives of each other but whose x
* coordinates differ. If the x-coordinates were the same, these
@@ -3524,16 +3979,16 @@ void test_add_neg_y_diff_x(void) {
ge_equals_gej(&res, &sumj);
}
-void run_ge(void) {
+static void run_ge(void) {
int i;
- for (i = 0; i < count * 32; i++) {
+ for (i = 0; i < COUNT * 32; i++) {
test_ge();
}
test_add_neg_y_diff_x();
test_intialized_inf();
}
-void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) {
+static void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) {
secp256k1_gej t = *a;
secp256k1_gej_cmov(&t, b, 0);
CHECK(gej_xyz_equals_gej(&t, a));
@@ -3541,12 +3996,12 @@ void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) {
CHECK(gej_xyz_equals_gej(&t, b));
}
-void run_gej(void) {
+static void run_gej(void) {
int i;
secp256k1_gej a, b;
/* Tests for secp256k1_gej_cmov */
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
secp256k1_gej_set_infinity(&a);
secp256k1_gej_set_infinity(&b);
test_gej_cmov(&a, &b);
@@ -3562,9 +4017,25 @@ void run_gej(void) {
test_gej_cmov(&a, &b);
test_gej_cmov(&b, &a);
}
+
+ /* Tests for secp256k1_gej_eq_var */
+ for (i = 0; i < COUNT; i++) {
+ secp256k1_fe fe;
+ random_gej_test(&a);
+ random_gej_test(&b);
+ CHECK(!secp256k1_gej_eq_var(&a, &b));
+
+ b = a;
+ random_field_element_test(&fe);
+ if (secp256k1_fe_is_zero(&fe)) {
+ continue;
+ }
+ secp256k1_gej_rescale(&a, &fe);
+ CHECK(secp256k1_gej_eq_var(&a, &b));
+ }
}
-void test_ec_combine(void) {
+static void test_ec_combine(void) {
secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
secp256k1_pubkey data[6];
const secp256k1_pubkey* d[6];
@@ -3577,26 +4048,26 @@ void test_ec_combine(void) {
secp256k1_scalar s;
random_scalar_order_test(&s);
secp256k1_scalar_add(&sum, &sum, &s);
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &s);
secp256k1_ge_set_gej(&Q, &Qj);
secp256k1_pubkey_save(&data[i - 1], &Q);
d[i - 1] = &data[i - 1];
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &sum);
secp256k1_ge_set_gej(&Q, &Qj);
secp256k1_pubkey_save(&sd, &Q);
- CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1);
+ CHECK(secp256k1_ec_pubkey_combine(CTX, &sd2, d, i) == 1);
CHECK(secp256k1_memcmp_var(&sd, &sd2, sizeof(sd)) == 0);
}
}
-void run_ec_combine(void) {
+static void run_ec_combine(void) {
int i;
- for (i = 0; i < count * 8; i++) {
+ for (i = 0; i < COUNT * 8; i++) {
test_ec_combine();
}
}
-void test_group_decompress(const secp256k1_fe* x) {
+static void test_group_decompress(const secp256k1_fe* x) {
/* The input itself, normalized. */
secp256k1_fe fex = *x;
/* Results of set_xo_var(..., 0), set_xo_var(..., 1). */
@@ -3631,9 +4102,9 @@ void test_group_decompress(const secp256k1_fe* x) {
}
}
-void run_group_decompress(void) {
+static void run_group_decompress(void) {
int i;
- for (i = 0; i < count * 4; i++) {
+ for (i = 0; i < COUNT * 4; i++) {
secp256k1_fe fe;
random_fe_test(&fe);
test_group_decompress(&fe);
@@ -3642,7 +4113,7 @@ void run_group_decompress(void) {
/***** ECMULT TESTS *****/
-void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) {
+static void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) {
/* Tests the pre_g / pre_g_128 tables for consistency.
* For independent verification we take a "geometric" approach to verification.
* We check that every entry is on-curve.
@@ -3692,7 +4163,7 @@ void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) {
}
}
-void run_ecmult_pre_g(void) {
+static void run_ecmult_pre_g(void) {
secp256k1_ge_storage gs;
secp256k1_gej gj;
secp256k1_ge g;
@@ -3716,7 +4187,7 @@ void run_ecmult_pre_g(void) {
CHECK(secp256k1_memcmp_var(&gs, &secp256k1_pre_g_128[0], sizeof(gs)) == 0);
}
-void run_ecmult_chain(void) {
+static void run_ecmult_chain(void) {
/* random starting point A (on the curve) */
secp256k1_gej a = SECP256K1_GEJ_CONST(
0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3,
@@ -3746,7 +4217,7 @@ void run_ecmult_chain(void) {
/* the point being computed */
x = a;
- for (i = 0; i < 200*count; i++) {
+ for (i = 0; i < 200*COUNT; i++) {
/* in each iteration, compute X = xn*X + gn*G; */
secp256k1_ecmult(&x, &x, &xn, &gn);
/* also compute ae and ge: the actual accumulated factors for A and G */
@@ -3767,20 +4238,15 @@ void run_ecmult_chain(void) {
0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D,
0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88
);
-
- secp256k1_gej_neg(&rp, &rp);
- secp256k1_gej_add_var(&rp, &rp, &x, NULL);
- CHECK(secp256k1_gej_is_infinity(&rp));
+ CHECK(secp256k1_gej_eq_var(&rp, &x));
}
}
/* redo the computation, but directly with the resulting ae and ge coefficients: */
secp256k1_ecmult(&x2, &a, &ae, &ge);
- secp256k1_gej_neg(&x2, &x2);
- secp256k1_gej_add_var(&x2, &x2, &x, NULL);
- CHECK(secp256k1_gej_is_infinity(&x2));
+ CHECK(secp256k1_gej_eq_var(&x, &x2));
}
-void test_point_times_order(const secp256k1_gej *point) {
+static void test_point_times_order(const secp256k1_gej *point) {
/* X * (point + G) + (order-X) * (pointer + G) = 0 */
secp256k1_scalar x;
secp256k1_scalar nx;
@@ -3844,7 +4310,7 @@ static const secp256k1_scalar scalars_near_split_bounds[20] = {
SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a45)
};
-void test_ecmult_target(const secp256k1_scalar* target, int mode) {
+static void test_ecmult_target(const secp256k1_scalar* target, int mode) {
/* Mode: 0=ecmult_gen, 1=ecmult, 2=ecmult_const */
secp256k1_scalar n1, n2;
secp256k1_ge p;
@@ -3864,9 +4330,9 @@ void test_ecmult_target(const secp256k1_scalar* target, int mode) {
/* EC multiplications */
if (mode == 0) {
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &p1j, &n1);
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &p2j, &n2);
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &ptj, target);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p1j, &n1);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p2j, &n2);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &ptj, target);
} else if (mode == 1) {
secp256k1_ecmult(&p1j, &pj, &n1, &zero);
secp256k1_ecmult(&p2j, &pj, &n2, &zero);
@@ -3883,10 +4349,10 @@ void test_ecmult_target(const secp256k1_scalar* target, int mode) {
CHECK(secp256k1_gej_is_infinity(&ptj));
}
-void run_ecmult_near_split_bound(void) {
+static void run_ecmult_near_split_bound(void) {
int i;
unsigned j;
- for (i = 0; i < 4*count; ++i) {
+ for (i = 0; i < 4*COUNT; ++i) {
for (j = 0; j < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++j) {
test_ecmult_target(&scalars_near_split_bounds[j], 0);
test_ecmult_target(&scalars_near_split_bounds[j], 1);
@@ -3895,7 +4361,7 @@ void run_ecmult_near_split_bound(void) {
}
}
-void run_point_times_order(void) {
+static void run_point_times_order(void) {
int i;
secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2);
static const secp256k1_fe xr = SECP256K1_FE_CONST(
@@ -3916,7 +4382,7 @@ void run_point_times_order(void) {
CHECK(secp256k1_fe_equal_var(&x, &xr));
}
-void ecmult_const_random_mult(void) {
+static void ecmult_const_random_mult(void) {
/* random starting point A (on the curve) */
secp256k1_ge a = SECP256K1_GE_CONST(
0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b,
@@ -3943,7 +4409,7 @@ void ecmult_const_random_mult(void) {
ge_equals_gej(&expected_b, &b);
}
-void ecmult_const_commutativity(void) {
+static void ecmult_const_commutativity(void) {
secp256k1_scalar a;
secp256k1_scalar b;
secp256k1_gej res1;
@@ -3964,7 +4430,7 @@ void ecmult_const_commutativity(void) {
ge_equals_ge(&mid1, &mid2);
}
-void ecmult_const_mult_zero_one(void) {
+static void ecmult_const_mult_zero_one(void) {
secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
secp256k1_scalar negone;
@@ -3986,7 +4452,7 @@ void ecmult_const_mult_zero_one(void) {
ge_equals_ge(&res2, &point);
}
-void ecmult_const_chain_multiply(void) {
+static void ecmult_const_chain_multiply(void) {
/* Check known result (randomly generated test problem from sage) */
const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST(
0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d,
@@ -4012,7 +4478,7 @@ void ecmult_const_chain_multiply(void) {
ge_equals_gej(&res, &expected_point);
}
-void run_ecmult_const_tests(void) {
+static void run_ecmult_const_tests(void) {
ecmult_const_mult_zero_one();
ecmult_const_random_mult();
ecmult_const_commutativity();
@@ -4039,7 +4505,7 @@ static int ecmult_multi_false_callback(secp256k1_scalar *sc, secp256k1_ge *pt, s
return 0;
}
-void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) {
+static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) {
int ncount;
secp256k1_scalar szero;
secp256k1_scalar sc[32];
@@ -4053,10 +4519,10 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_scalar_set_int(&szero, 0);
/* No points to multiply */
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, NULL, ecmult_multi_callback, &data, 0));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, NULL, ecmult_multi_callback, &data, 0));
/* Check 1- and 2-point multiplies against ecmult */
- for (ncount = 0; ncount < count; ncount++) {
+ for (ncount = 0; ncount < COUNT; ncount++) {
secp256k1_ge ptg;
secp256k1_gej ptgj;
random_scalar_order(&sc[0]);
@@ -4069,38 +4535,30 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
/* only G scalar */
secp256k1_ecmult(&r2, &ptgj, &szero, &sc[0]);
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0));
- secp256k1_gej_neg(&r2, &r2);
- secp256k1_gej_add_var(&r, &r, &r2, NULL);
- CHECK(secp256k1_gej_is_infinity(&r));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0));
+ CHECK(secp256k1_gej_eq_var(&r, &r2));
/* 1-point */
secp256k1_ecmult(&r2, &ptgj, &sc[0], &szero);
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 1));
- secp256k1_gej_neg(&r2, &r2);
- secp256k1_gej_add_var(&r, &r, &r2, NULL);
- CHECK(secp256k1_gej_is_infinity(&r));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 1));
+ CHECK(secp256k1_gej_eq_var(&r, &r2));
/* Try to multiply 1 point, but callback returns false */
- CHECK(!ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
+ CHECK(!ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
/* 2-point */
secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]);
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 2));
- secp256k1_gej_neg(&r2, &r2);
- secp256k1_gej_add_var(&r, &r, &r2, NULL);
- CHECK(secp256k1_gej_is_infinity(&r));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 2));
+ CHECK(secp256k1_gej_eq_var(&r, &r2));
/* 2-point with G scalar */
secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]);
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1));
- secp256k1_gej_neg(&r2, &r2);
- secp256k1_gej_add_var(&r, &r, &r2, NULL);
- CHECK(secp256k1_gej_is_infinity(&r));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1));
+ CHECK(secp256k1_gej_eq_var(&r, &r2));
}
/* Check infinite outputs of various forms */
- for (ncount = 0; ncount < count; ncount++) {
+ for (ncount = 0; ncount < COUNT; ncount++) {
secp256k1_ge ptg;
size_t i, j;
size_t sizes[] = { 2, 10, 32 };
@@ -4110,7 +4568,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
random_scalar_order(&sc[i]);
secp256k1_ge_set_infinity(&pt[i]);
}
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4120,7 +4578,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
pt[i] = ptg;
secp256k1_scalar_set_int(&sc[i], 0);
}
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4133,7 +4591,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
pt[2 * i + 1] = ptg;
}
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
random_scalar_order(&sc[0]);
@@ -4146,7 +4604,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]);
}
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4161,12 +4619,12 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_scalar_negate(&sc[i], &sc[i]);
}
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 32));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 32));
CHECK(secp256k1_gej_is_infinity(&r));
}
/* Check random points, constant scalar */
- for (ncount = 0; ncount < count; ncount++) {
+ for (ncount = 0; ncount < COUNT; ncount++) {
size_t i;
secp256k1_gej_set_infinity(&r);
@@ -4180,14 +4638,12 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
}
secp256k1_ecmult(&r2, &r, &sc[0], &szero);
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
- secp256k1_gej_neg(&r2, &r2);
- secp256k1_gej_add_var(&r, &r, &r2, NULL);
- CHECK(secp256k1_gej_is_infinity(&r));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ CHECK(secp256k1_gej_eq_var(&r, &r2));
}
/* Check random scalars, constant point */
- for (ncount = 0; ncount < count; ncount++) {
+ for (ncount = 0; ncount < COUNT; ncount++) {
size_t i;
secp256k1_ge ptg;
secp256k1_gej p0j;
@@ -4203,10 +4659,8 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_gej_set_ge(&p0j, &pt[0]);
secp256k1_ecmult(&r2, &p0j, &rs, &szero);
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
- secp256k1_gej_neg(&r2, &r2);
- secp256k1_gej_add_var(&r, &r, &r2, NULL);
- CHECK(secp256k1_gej_is_infinity(&r));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ CHECK(secp256k1_gej_eq_var(&r, &r2));
}
/* Sanity check that zero scalars don't cause problems */
@@ -4216,13 +4670,13 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
}
secp256k1_scalar_clear(&sc[0]);
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
secp256k1_scalar_clear(&sc[1]);
secp256k1_scalar_clear(&sc[2]);
secp256k1_scalar_clear(&sc[3]);
secp256k1_scalar_clear(&sc[4]);
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 6));
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 5));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 6));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 5));
CHECK(secp256k1_gej_is_infinity(&r));
/* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */
@@ -4267,10 +4721,8 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_scalar_add(&tmp1, &tmp1, &tmp2);
secp256k1_ecmult(&expected, &ptgj, &tmp1, &szero);
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &actual, &szero, ecmult_multi_callback, &data, 2));
- secp256k1_gej_neg(&expected, &expected);
- secp256k1_gej_add_var(&actual, &actual, &expected, NULL);
- CHECK(secp256k1_gej_is_infinity(&actual));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &actual, &szero, ecmult_multi_callback, &data, 2));
+ CHECK(secp256k1_gej_eq_var(&actual, &expected));
}
}
}
@@ -4278,7 +4730,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
}
}
-int test_ecmult_multi_random(secp256k1_scratch *scratch) {
+static int test_ecmult_multi_random(secp256k1_scratch *scratch) {
/* Large random test for ecmult_multi_* functions which exercises:
* - Few or many inputs (0 up to 128, roughly exponentially distributed).
* - Few or many 0*P or a*INF inputs (roughly uniformly distributed).
@@ -4345,7 +4797,7 @@ int test_ecmult_multi_random(secp256k1_scratch *scratch) {
secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar);
secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp);
secp256k1_scalar_negate(&sc_tmp, &sc_tmp);
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &gejs[filled], &sc_tmp);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &gejs[filled], &sc_tmp);
++filled;
++mults;
}
@@ -4437,16 +4889,14 @@ int test_ecmult_multi_random(secp256k1_scratch *scratch) {
/* Invoke ecmult_multi code. */
data.sc = scalars;
data.pt = ges;
- CHECK(ecmult_multi(&ctx->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled));
mults += num_nonzero + g_nonzero;
/* Compare with expected result. */
- secp256k1_gej_neg(&computed, &computed);
- secp256k1_gej_add_var(&computed, &computed, &expected, NULL);
- CHECK(secp256k1_gej_is_infinity(&computed));
+ CHECK(secp256k1_gej_eq_var(&computed, &expected));
return mults;
}
-void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
+static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
secp256k1_scalar szero;
secp256k1_scalar sc;
secp256k1_ge pt;
@@ -4461,12 +4911,12 @@ void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
secp256k1_scalar_set_int(&szero, 0);
/* Try to multiply 1 point, but scratch space is empty.*/
- scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0);
- CHECK(!ecmult_multi(&ctx->error_callback, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
- secp256k1_scratch_destroy(&ctx->error_callback, scratch_empty);
+ scratch_empty = secp256k1_scratch_create(&CTX->error_callback, 0);
+ CHECK(!ecmult_multi(&CTX->error_callback, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
+ secp256k1_scratch_destroy(&CTX->error_callback, scratch_empty);
}
-void test_secp256k1_pippenger_bucket_window_inv(void) {
+static void test_secp256k1_pippenger_bucket_window_inv(void) {
int i;
CHECK(secp256k1_pippenger_bucket_window_inv(0) == 0);
@@ -4486,7 +4936,7 @@ void test_secp256k1_pippenger_bucket_window_inv(void) {
* Probabilistically test the function returning the maximum number of possible points
* for a given scratch space.
*/
-void test_ecmult_multi_pippenger_max_points(void) {
+static void test_ecmult_multi_pippenger_max_points(void) {
size_t scratch_size = secp256k1_testrand_bits(8);
size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12);
secp256k1_scratch *scratch;
@@ -4497,29 +4947,29 @@ void test_ecmult_multi_pippenger_max_points(void) {
size_t i;
size_t total_alloc;
size_t checkpoint;
- scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size);
+ scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size);
CHECK(scratch != NULL);
- checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
- n_points_supported = secp256k1_pippenger_max_points(&ctx->error_callback, scratch);
+ checkpoint = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch);
+ n_points_supported = secp256k1_pippenger_max_points(&CTX->error_callback, scratch);
if (n_points_supported == 0) {
- secp256k1_scratch_destroy(&ctx->error_callback, scratch);
+ secp256k1_scratch_destroy(&CTX->error_callback, scratch);
continue;
}
bucket_window = secp256k1_pippenger_bucket_window(n_points_supported);
/* allocate `total_alloc` bytes over `PIPPENGER_SCRATCH_OBJECTS` many allocations */
total_alloc = secp256k1_pippenger_scratch_size(n_points_supported, bucket_window);
for (i = 0; i < PIPPENGER_SCRATCH_OBJECTS - 1; i++) {
- CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 1));
+ CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 1));
total_alloc--;
}
- CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, total_alloc));
- secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint);
- secp256k1_scratch_destroy(&ctx->error_callback, scratch);
+ CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, total_alloc));
+ secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint);
+ secp256k1_scratch_destroy(&CTX->error_callback, scratch);
}
CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW);
}
-void test_ecmult_multi_batch_size_helper(void) {
+static void test_ecmult_multi_batch_size_helper(void) {
size_t n_batches, n_batch_points, max_n_batch_points, n;
max_n_batch_points = 0;
@@ -4567,12 +5017,12 @@ void test_ecmult_multi_batch_size_helper(void) {
* Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to
* 1 <= i <= num points.
*/
-void test_ecmult_multi_batching(void) {
+static void test_ecmult_multi_batching(void) {
static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD;
secp256k1_scalar scG;
secp256k1_scalar szero;
- secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_scalar) * n_points);
- secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * n_points);
+ secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_scalar) * n_points);
+ secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * n_points);
secp256k1_gej r;
secp256k1_gej r2;
ecmult_multi_data data;
@@ -4601,46 +5051,46 @@ void test_ecmult_multi_batching(void) {
/* Test with empty scratch space. It should compute the correct result using
* ecmult_mult_simple algorithm which doesn't require a scratch space. */
- scratch = secp256k1_scratch_create(&ctx->error_callback, 0);
- CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
+ scratch = secp256k1_scratch_create(&CTX->error_callback, 0);
+ CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
- secp256k1_scratch_destroy(&ctx->error_callback, scratch);
+ secp256k1_scratch_destroy(&CTX->error_callback, scratch);
/* Test with space for 1 point in pippenger. That's not enough because
* ecmult_multi selects strauss which requires more memory. It should
* therefore select the simple algorithm. */
- scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
- CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
+ scratch = secp256k1_scratch_create(&CTX->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
+ CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
- secp256k1_scratch_destroy(&ctx->error_callback, scratch);
+ secp256k1_scratch_destroy(&CTX->error_callback, scratch);
for(i = 1; i <= n_points; i++) {
if (i > ECMULT_PIPPENGER_THRESHOLD) {
int bucket_window = secp256k1_pippenger_bucket_window(i);
size_t scratch_size = secp256k1_pippenger_scratch_size(i, bucket_window);
- scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
+ scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
} else {
size_t scratch_size = secp256k1_strauss_scratch_size(i);
- scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
+ scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
}
- CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
+ CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
- secp256k1_scratch_destroy(&ctx->error_callback, scratch);
+ secp256k1_scratch_destroy(&CTX->error_callback, scratch);
}
free(sc);
free(pt);
}
-void run_ecmult_multi_tests(void) {
+static void run_ecmult_multi_tests(void) {
secp256k1_scratch *scratch;
- int64_t todo = (int64_t)320 * count;
+ int64_t todo = (int64_t)320 * COUNT;
test_secp256k1_pippenger_bucket_window_inv();
test_ecmult_multi_pippenger_max_points();
- scratch = secp256k1_scratch_create(&ctx->error_callback, 819200);
+ scratch = secp256k1_scratch_create(&CTX->error_callback, 819200);
test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
test_ecmult_multi(NULL, secp256k1_ecmult_multi_var);
test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single);
@@ -4650,18 +5100,18 @@ void run_ecmult_multi_tests(void) {
while (todo > 0) {
todo -= test_ecmult_multi_random(scratch);
}
- secp256k1_scratch_destroy(&ctx->error_callback, scratch);
+ secp256k1_scratch_destroy(&CTX->error_callback, scratch);
/* Run test_ecmult_multi with space for exactly one point */
- scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
+ scratch = secp256k1_scratch_create(&CTX->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
- secp256k1_scratch_destroy(&ctx->error_callback, scratch);
+ secp256k1_scratch_destroy(&CTX->error_callback, scratch);
test_ecmult_multi_batch_size_helper();
test_ecmult_multi_batching();
}
-void test_wnaf(const secp256k1_scalar *number, int w) {
+static void test_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar x, two, t;
int wnaf[256];
int zeroes = -1;
@@ -4695,7 +5145,7 @@ void test_wnaf(const secp256k1_scalar *number, int w) {
CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */
}
-void test_constant_wnaf_negate(const secp256k1_scalar *number) {
+static void test_constant_wnaf_negate(const secp256k1_scalar *number) {
secp256k1_scalar neg1 = *number;
secp256k1_scalar neg2 = *number;
int sign1 = 1;
@@ -4710,7 +5160,7 @@ void test_constant_wnaf_negate(const secp256k1_scalar *number) {
CHECK(secp256k1_scalar_eq(&neg1, &neg2));
}
-void test_constant_wnaf(const secp256k1_scalar *number, int w) {
+static void test_constant_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar x, shift;
int wnaf[256] = {0};
int i;
@@ -4750,7 +5200,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
CHECK(secp256k1_scalar_eq(&x, &num));
}
-void test_fixed_wnaf(const secp256k1_scalar *number, int w) {
+static void test_fixed_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar x, shift;
int wnaf[256] = {0};
int i;
@@ -4787,7 +5237,7 @@ void test_fixed_wnaf(const secp256k1_scalar *number, int w) {
/* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the
* rest is 0.*/
-void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) {
+static void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) {
int i;
for (i = WNAF_SIZE(w)-1; i >= 8; --i) {
CHECK(wnaf[i] == 0);
@@ -4797,7 +5247,7 @@ void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) {
}
}
-void test_fixed_wnaf_small(void) {
+static void test_fixed_wnaf_small(void) {
int w = 4;
int wnaf[256] = {0};
int i;
@@ -4851,7 +5301,7 @@ void test_fixed_wnaf_small(void) {
}
}
-void run_wnaf(void) {
+static void run_wnaf(void) {
int i;
secp256k1_scalar n = {{0}};
@@ -4883,7 +5333,7 @@ void run_wnaf(void) {
/* Test 0 for fixed wnaf */
test_fixed_wnaf_small();
/* Random tests */
- for (i = 0; i < count; i++) {
+ for (i = 0; i < COUNT; i++) {
random_scalar_order(&n);
test_wnaf(&n, 4+(i%10));
test_constant_wnaf_negate(&n);
@@ -4905,7 +5355,7 @@ static int test_ecmult_accumulate_cb(secp256k1_scalar* sc, secp256k1_ge* pt, siz
return 1;
}
-void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, secp256k1_scratch* scratch) {
+static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, secp256k1_scratch* scratch) {
/* Compute x*G in 6 different ways, serialize it uncompressed, and feed it into acc. */
secp256k1_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj;
secp256k1_ge r;
@@ -4914,7 +5364,7 @@ void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, se
size_t size = 65;
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
secp256k1_gej_set_infinity(&infj);
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj1, x);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj1, x);
secp256k1_ecmult(&rj2, &gj, x, &zero);
secp256k1_ecmult(&rj3, &infj, &zero, x);
secp256k1_ecmult_multi_var(NULL, scratch, &rj4, x, NULL, NULL, 0);
@@ -4938,7 +5388,7 @@ void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, se
}
}
-void test_ecmult_constants_2bit(void) {
+static void test_ecmult_constants_2bit(void) {
/* Using test_ecmult_accumulate, test ecmult for:
* - For i in 0..36:
* - Key i
@@ -4951,7 +5401,7 @@ void test_ecmult_constants_2bit(void) {
secp256k1_sha256 acc;
unsigned char b32[32];
int i, j;
- secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 65536);
+ secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536);
/* Expected hash of all the computed points; created with an independent
* implementation. */
@@ -4979,10 +5429,10 @@ void test_ecmult_constants_2bit(void) {
secp256k1_sha256_finalize(&acc, b32);
CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0);
- secp256k1_scratch_space_destroy(ctx, scratch);
+ secp256k1_scratch_space_destroy(CTX, scratch);
}
-void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) {
+static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) {
/* Using test_ecmult_accumulate, test ecmult for:
* - Key 0
* - Key 1
@@ -4995,7 +5445,7 @@ void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char
unsigned char b32[32];
unsigned char inp[6];
size_t i;
- secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 65536);
+ secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536);
inp[0] = prefix & 0xFF;
inp[1] = (prefix >> 8) & 0xFF;
@@ -5022,10 +5472,10 @@ void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char
secp256k1_sha256_finalize(&acc, b32);
CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0);
- secp256k1_scratch_space_destroy(ctx, scratch);
+ secp256k1_scratch_space_destroy(CTX, scratch);
}
-void run_ecmult_constants(void) {
+static void run_ecmult_constants(void) {
/* Expected hashes of all points in the tests below. Computed using an
* independent implementation. */
static const unsigned char expected32_6bit20[32] = {
@@ -5059,7 +5509,7 @@ void run_ecmult_constants(void) {
}
}
-void test_ecmult_gen_blind(void) {
+static void test_ecmult_gen_blind(void) {
/* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */
secp256k1_scalar key;
secp256k1_scalar b;
@@ -5069,32 +5519,32 @@ void test_ecmult_gen_blind(void) {
secp256k1_gej i;
secp256k1_ge pge;
random_scalar_order_test(&key);
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej, &key);
secp256k1_testrand256(seed32);
- b = ctx->ecmult_gen_ctx.blind;
- i = ctx->ecmult_gen_ctx.initial;
- secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
- CHECK(!secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind));
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key);
+ b = CTX->ecmult_gen_ctx.blind;
+ i = CTX->ecmult_gen_ctx.initial;
+ secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, seed32);
+ CHECK(!secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.blind));
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej2, &key);
CHECK(!gej_xyz_equals_gej(&pgej, &pgej2));
- CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial));
+ CHECK(!gej_xyz_equals_gej(&i, &CTX->ecmult_gen_ctx.initial));
secp256k1_ge_set_gej(&pge, &pgej);
ge_equals_gej(&pge, &pgej2);
}
-void test_ecmult_gen_blind_reset(void) {
+static void test_ecmult_gen_blind_reset(void) {
/* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */
secp256k1_scalar b;
secp256k1_gej initial;
- secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0);
- b = ctx->ecmult_gen_ctx.blind;
- initial = ctx->ecmult_gen_ctx.initial;
- secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0);
- CHECK(secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind));
- CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial));
+ secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0);
+ b = CTX->ecmult_gen_ctx.blind;
+ initial = CTX->ecmult_gen_ctx.initial;
+ secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0);
+ CHECK(secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.blind));
+ CHECK(gej_xyz_equals_gej(&initial, &CTX->ecmult_gen_ctx.initial));
}
-void run_ecmult_gen_blind(void) {
+static void run_ecmult_gen_blind(void) {
int i;
test_ecmult_gen_blind_reset();
for (i = 0; i < 10; i++) {
@@ -5103,7 +5553,7 @@ void run_ecmult_gen_blind(void) {
}
/***** ENDOMORPHISH TESTS *****/
-void test_scalar_split(const secp256k1_scalar* full) {
+static void test_scalar_split(const secp256k1_scalar* full) {
secp256k1_scalar s, s1, slam;
const unsigned char zero[32] = {0};
unsigned char tmp[32];
@@ -5130,7 +5580,7 @@ void test_scalar_split(const secp256k1_scalar* full) {
}
-void run_endomorphism_tests(void) {
+static void run_endomorphism_tests(void) {
unsigned i;
static secp256k1_scalar s;
test_scalar_split(&secp256k1_scalar_zero);
@@ -5141,7 +5591,7 @@ void run_endomorphism_tests(void) {
secp256k1_scalar_add(&s, &secp256k1_const_lambda, &secp256k1_scalar_one);
test_scalar_split(&s);
- for (i = 0; i < 100U * count; ++i) {
+ for (i = 0; i < 100U * COUNT; ++i) {
secp256k1_scalar full;
random_scalar_order_test(&full);
test_scalar_split(&full);
@@ -5151,19 +5601,19 @@ void run_endomorphism_tests(void) {
}
}
-void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) {
+static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) {
unsigned char pubkeyc[65];
secp256k1_pubkey pubkey;
secp256k1_ge ge;
size_t pubkeyclen;
int32_t ecount;
ecount = 0;
- secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) {
/* Smaller sizes are tested exhaustively elsewhere. */
int32_t i;
memcpy(&pubkeyc[1], input, 64);
- VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen);
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[pubkeyclen], 65 - pubkeyclen);
for (i = 0; i < 256; i++) {
/* Try all type bytes. */
int xpass;
@@ -5182,29 +5632,29 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali
unsigned char pubkeyo[65];
size_t outl;
memset(&pubkey, 0, sizeof(pubkey));
- VG_UNDEF(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
ecount = 0;
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
outl = 65;
- VG_UNDEF(pubkeyo, 65);
- CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
- VG_CHECK(pubkeyo, outl);
+ SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
+ SECP256K1_CHECKMEM_CHECK(pubkeyo, outl);
CHECK(outl == 33);
CHECK(secp256k1_memcmp_var(&pubkeyo[1], &pubkeyc[1], 32) == 0);
CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0]));
if (ypass) {
/* This test isn't always done because we decode with alternative signs, so the y won't match. */
CHECK(pubkeyo[0] == ysign);
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1);
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1);
memset(&pubkey, 0, sizeof(pubkey));
- VG_UNDEF(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
secp256k1_pubkey_save(&pubkey, &ge);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
outl = 65;
- VG_UNDEF(pubkeyo, 65);
- CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);
- VG_CHECK(pubkeyo, outl);
+ SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);
+ SECP256K1_CHECKMEM_CHECK(pubkeyo, outl);
CHECK(outl == 65);
CHECK(pubkeyo[0] == 4);
CHECK(secp256k1_memcmp_var(&pubkeyo[1], input, 64) == 0);
@@ -5214,19 +5664,19 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali
/* These cases must fail to parse. */
memset(&pubkey, 0xfe, sizeof(pubkey));
ecount = 0;
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
CHECK(ecount == 1);
}
}
}
- secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
+ secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
}
-void run_ec_pubkey_parse_test(void) {
+static void run_ec_pubkey_parse_test(void) {
#define SECP256K1_EC_PARSE_TEST_NVALID (12)
const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = {
{
@@ -5415,29 +5865,29 @@ void run_ec_pubkey_parse_test(void) {
int32_t ecount2;
ecount = 0;
/* Nothing should be reading this far into pubkeyc. */
- VG_UNDEF(&pubkeyc[65], 1);
- secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[65], 1);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
/* Zero length claimed, fail, zeroize, no illegal arg error. */
memset(&pubkey, 0xfe, sizeof(pubkey));
ecount = 0;
- VG_UNDEF(shortkey, 2);
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(shortkey, 2);
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 0) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
CHECK(ecount == 1);
/* Length one claimed, fail, zeroize, no illegal arg error. */
for (i = 0; i < 256 ; i++) {
memset(&pubkey, 0xfe, sizeof(pubkey));
ecount = 0;
shortkey[0] = i;
- VG_UNDEF(&shortkey[1], 1);
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&shortkey[1], 1);
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 1) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
CHECK(ecount == 1);
}
/* Length two claimed, fail, zeroize, no illegal arg error. */
@@ -5446,102 +5896,102 @@ void run_ec_pubkey_parse_test(void) {
ecount = 0;
shortkey[0] = i & 255;
shortkey[1] = i >> 8;
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 2) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
CHECK(ecount == 1);
}
memset(&pubkey, 0xfe, sizeof(pubkey));
ecount = 0;
- VG_UNDEF(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
/* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 33) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
CHECK(ecount == 1);
/* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */
- CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0);
+ CHECK(secp256k1_ec_pubkey_parse(CTX, NULL, pubkeyc, 65) == 0);
CHECK(ecount == 2);
/* NULL input string. Illegal arg and zeroize output. */
memset(&pubkey, 0xfe, sizeof(pubkey));
ecount = 0;
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, NULL, 65) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 1);
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
CHECK(ecount == 2);
/* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */
memset(&pubkey, 0xfe, sizeof(pubkey));
ecount = 0;
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 64) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
CHECK(ecount == 1);
/* 66 bytes claimed, fail, zeroize output, no illegal arg error. */
memset(&pubkey, 0xfe, sizeof(pubkey));
ecount = 0;
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 66) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
CHECK(ecount == 1);
/* Valid parse. */
memset(&pubkey, 0, sizeof(pubkey));
ecount = 0;
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1);
- CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_no_precomp, &pubkey, pubkeyc, 65) == 1);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 65) == 1);
+ CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, pubkeyc, 65) == 1);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
- VG_UNDEF(&ge, sizeof(ge));
- CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1);
- VG_CHECK(&ge.x, sizeof(ge.x));
- VG_CHECK(&ge.y, sizeof(ge.y));
- VG_CHECK(&ge.infinity, sizeof(ge.infinity));
+ SECP256K1_CHECKMEM_UNDEFINE(&ge, sizeof(ge));
+ CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1);
+ SECP256K1_CHECKMEM_CHECK(&ge.x, sizeof(ge.x));
+ SECP256K1_CHECKMEM_CHECK(&ge.y, sizeof(ge.y));
+ SECP256K1_CHECKMEM_CHECK(&ge.infinity, sizeof(ge.infinity));
ge_equals_ge(&secp256k1_ge_const_g, &ge);
CHECK(ecount == 0);
/* secp256k1_ec_pubkey_serialize illegal args. */
ecount = 0;
len = 65;
- CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);
CHECK(ecount == 1);
CHECK(len == 0);
- CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);
CHECK(ecount == 2);
len = 65;
- VG_UNDEF(sout, 65);
- CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0);
- VG_CHECK(sout, 65);
+ SECP256K1_CHECKMEM_UNDEFINE(sout, 65);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0);
+ SECP256K1_CHECKMEM_CHECK(sout, 65);
CHECK(ecount == 3);
CHECK(len == 0);
len = 65;
- CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, ~0) == 0);
CHECK(ecount == 4);
CHECK(len == 0);
len = 65;
- VG_UNDEF(sout, 65);
- CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);
- VG_CHECK(sout, 65);
+ SECP256K1_CHECKMEM_UNDEFINE(sout, 65);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);
+ SECP256K1_CHECKMEM_CHECK(sout, 65);
CHECK(ecount == 4);
CHECK(len == 65);
/* Multiple illegal args. Should still set arg error only once. */
ecount = 0;
ecount2 = 11;
- CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0);
+ CHECK(secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65) == 0);
CHECK(ecount == 1);
/* Does the illegal arg callback actually change the behavior? */
- secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2);
- CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0);
+ secp256k1_context_set_illegal_callback(CTX, uncounting_illegal_callback_fn, &ecount2);
+ CHECK(secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65) == 0);
CHECK(ecount == 1);
CHECK(ecount2 == 10);
- secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
+ secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
/* Try a bunch of prefabbed points with all possible encodings. */
for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) {
ec_pubkey_parse_pointtest(valid[i], 1, 1);
@@ -5554,7 +6004,7 @@ void run_ec_pubkey_parse_test(void) {
}
}
-void run_eckey_edge_case_test(void) {
+static void run_eckey_edge_case_test(void) {
const unsigned char orderc[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
@@ -5572,65 +6022,65 @@ void run_eckey_edge_case_test(void) {
size_t len;
int32_t ecount;
/* Group order is too large, reject. */
- CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0);
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_seckey_verify(CTX, orderc) == 0);
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, orderc) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
/* Maximum value is too large, reject. */
memset(ctmp, 255, 32);
- CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+ CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0);
memset(&pubkey, 1, sizeof(pubkey));
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
/* Zero is too small, reject. */
memset(ctmp, 0, 32);
- CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+ CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0);
memset(&pubkey, 1, sizeof(pubkey));
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
/* One must be accepted. */
ctmp[31] = 0x01;
- CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);
+ CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1);
memset(&pubkey, 0, sizeof(pubkey));
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
pubkey_one = pubkey;
/* Group order + 1 is too large, reject. */
memcpy(ctmp, orderc, 32);
ctmp[31] = 0x42;
- CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+ CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0);
memset(&pubkey, 1, sizeof(pubkey));
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
/* -1 must be accepted. */
ctmp[31] = 0x40;
- CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);
+ CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1);
memset(&pubkey, 0, sizeof(pubkey));
- VG_UNDEF(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1);
- VG_CHECK(&pubkey, sizeof(pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
pubkey_negone = pubkey;
/* Tweak of zero leaves the value unchanged. */
memset(ctmp2, 0, 32);
- CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 1);
+ CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 1);
CHECK(secp256k1_memcmp_var(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40);
memcpy(&pubkey2, &pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
+ CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1);
CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
/* Multiply tweak of zero zeroizes the output. */
- CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0);
CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0);
- CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp2) == 0);
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0);
memcpy(&pubkey, &pubkey2, sizeof(pubkey));
/* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing
@@ -5638,31 +6088,31 @@ void run_eckey_edge_case_test(void) {
memcpy(ctmp, orderc, 32);
memset(ctmp2, 0, 32);
ctmp2[31] = 0x01;
- CHECK(secp256k1_ec_seckey_verify(ctx, ctmp2) == 1);
- CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
- CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 0);
+ CHECK(secp256k1_ec_seckey_verify(CTX, ctmp2) == 1);
+ CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 0);
CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0);
memcpy(ctmp, orderc, 32);
- CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0);
CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0);
/* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing
tweak, the seckey is zeroized. */
memcpy(ctmp, orderc, 32);
ctmp[31] = 0x40;
- CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, orderc) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, orderc) == 0);
CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0);
memcpy(ctmp, orderc, 32);
ctmp[31] = 0x40;
- CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, orderc) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, orderc) == 0);
CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0);
memcpy(ctmp, orderc, 32);
ctmp[31] = 0x40;
/* If pubkey_tweak_add or pubkey_tweak_mul are called with an overflowing
tweak, the pubkey is zeroized. */
- CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, orderc) == 0);
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0);
memcpy(&pubkey, &pubkey2, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, orderc) == 0);
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0);
memcpy(&pubkey, &pubkey2, sizeof(pubkey));
/* If the resulting key in secp256k1_ec_seckey_tweak_add and
@@ -5672,145 +6122,145 @@ void run_eckey_edge_case_test(void) {
ctmp[31] = 0x40;
memset(ctmp2, 0, 32);
ctmp2[31] = 1;
- CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 0);
CHECK(secp256k1_memcmp_var(zeros, ctmp2, 32) == 0);
ctmp2[31] = 1;
- CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 0);
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0);
memcpy(&pubkey, &pubkey2, sizeof(pubkey));
/* Tweak computation wraps and results in a key of 1. */
ctmp2[31] = 2;
- CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 1);
+ CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 1);
CHECK(secp256k1_memcmp_var(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1);
ctmp2[31] = 2;
- CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
+ CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1);
ctmp2[31] = 1;
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, ctmp2) == 1);
CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
/* Tweak mul * 2 = 1+1. */
- CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
+ CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1);
ctmp2[31] = 2;
- CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 1);
CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
/* Test argument errors. */
ecount = 0;
- secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
CHECK(ecount == 0);
/* Zeroize pubkey on parse error. */
memset(&pubkey, 0, 32);
- CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0);
memcpy(&pubkey, &pubkey2, sizeof(pubkey));
memset(&pubkey2, 0, 32);
- CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(&pubkey2, zeros, sizeof(pubkey2)) == 0);
/* Plain argument errors. */
ecount = 0;
- CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);
+ CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0);
+ CHECK(secp256k1_ec_seckey_verify(CTX, NULL) == 0);
CHECK(ecount == 1);
ecount = 0;
memset(ctmp2, 0, 32);
ctmp2[31] = 4;
- CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_add(CTX, NULL, ctmp2) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, NULL) == 0);
CHECK(ecount == 2);
ecount = 0;
memset(ctmp2, 0, 32);
ctmp2[31] = 4;
- CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, NULL, ctmp2) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, NULL) == 0);
CHECK(ecount == 2);
ecount = 0;
memset(ctmp2, 0, 32);
- CHECK(secp256k1_ec_seckey_tweak_add(ctx, NULL, ctmp2) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_add(CTX, NULL, ctmp2) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, NULL) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, NULL) == 0);
CHECK(ecount == 2);
ecount = 0;
memset(ctmp2, 0, 32);
ctmp2[31] = 1;
- CHECK(secp256k1_ec_seckey_tweak_mul(ctx, NULL, ctmp2) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_mul(CTX, NULL, ctmp2) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, NULL) == 0);
+ CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, NULL) == 0);
CHECK(ecount == 2);
ecount = 0;
- CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0);
+ CHECK(secp256k1_ec_pubkey_create(CTX, NULL, ctmp) == 0);
CHECK(ecount == 1);
memset(&pubkey, 1, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
/* secp256k1_ec_pubkey_combine tests. */
ecount = 0;
pubkeys[0] = &pubkey_one;
- VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *));
- VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *));
- VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[0], sizeof(secp256k1_pubkey *));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[1], sizeof(secp256k1_pubkey *));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[2], sizeof(secp256k1_pubkey *));
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
- VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
- CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0);
- VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0);
+ CHECK(secp256k1_ec_pubkey_combine(CTX, NULL, pubkeys, 1) == 0);
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
CHECK(ecount == 2);
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
- VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
- CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0);
- VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, NULL, 1) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
CHECK(ecount == 3);
pubkeys[0] = &pubkey_negone;
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
- VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
- CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1);
- VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 1) == 1);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
CHECK(ecount == 3);
len = 33;
- CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
- CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1);
CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0);
/* Result is infinity. */
pubkeys[0] = &pubkey_one;
pubkeys[1] = &pubkey_negone;
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
- VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
- CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0);
- VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 0);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
CHECK(ecount == 3);
/* Passes through infinity but comes out one. */
pubkeys[2] = &pubkey_one;
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
- VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
- CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1);
- VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
CHECK(ecount == 3);
len = 33;
- CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
- CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1);
CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0);
/* Adds to two. */
pubkeys[1] = &pubkey_one;
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
- VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
- CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1);
- VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 1);
+ SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
CHECK(ecount == 3);
- secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
+ secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
}
-void run_eckey_negate_test(void) {
+static void run_eckey_negate_test(void) {
unsigned char seckey[32];
unsigned char seckey_tmp[32];
@@ -5818,20 +6268,20 @@ void run_eckey_negate_test(void) {
memcpy(seckey_tmp, seckey, 32);
/* Verify negation changes the key and changes it back */
- CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1);
+ CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1);
CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) != 0);
- CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1);
+ CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1);
CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0);
/* Check that privkey alias gives same result */
- CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1);
- CHECK(secp256k1_ec_privkey_negate(ctx, seckey_tmp) == 1);
+ CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1);
+ CHECK(secp256k1_ec_privkey_negate(CTX, seckey_tmp) == 1);
CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0);
/* Negating all 0s fails */
memset(seckey, 0, 32);
memset(seckey_tmp, 0, 32);
- CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 0);
+ CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 0);
/* Check that seckey is not modified */
CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0);
@@ -5841,18 +6291,18 @@ void run_eckey_negate_test(void) {
random_scalar_order_b32(seckey);
memset(seckey, 0xFF, 16);
memset(seckey_tmp, 0, 32);
- CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 0);
+ CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 0);
CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0);
}
-void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {
+static void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {
secp256k1_scalar nonce;
do {
random_scalar_order_test(&nonce);
- } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid));
+ } while(!secp256k1_ecdsa_sig_sign(&CTX->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid));
}
-void test_ecdsa_sign_verify(void) {
+static void test_ecdsa_sign_verify(void) {
secp256k1_gej pubj;
secp256k1_ge pub;
secp256k1_scalar one;
@@ -5862,7 +6312,7 @@ void test_ecdsa_sign_verify(void) {
int recid;
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubj, &key);
secp256k1_ge_set_gej(&pub, &pubj);
getrec = secp256k1_testrand_bits(1);
/* The specific way in which this conditional is written sidesteps a potential bug in clang.
@@ -5879,9 +6329,9 @@ void test_ecdsa_sign_verify(void) {
CHECK(!secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg));
}
-void run_ecdsa_sign_verify(void) {
+static void run_ecdsa_sign_verify(void) {
int i;
- for (i = 0; i < 10*count; i++) {
+ for (i = 0; i < 10*COUNT; i++) {
test_ecdsa_sign_verify();
}
}
@@ -5933,12 +6383,12 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char
return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5);
}
-int is_empty_signature(const secp256k1_ecdsa_signature *sig) {
+static int is_empty_signature(const secp256k1_ecdsa_signature *sig) {
static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0};
return secp256k1_memcmp_var(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0;
}
-void test_ecdsa_end_to_end(void) {
+static void test_ecdsa_end_to_end(void) {
unsigned char extra[32] = {0x00};
unsigned char privkey[32];
unsigned char message[32];
@@ -5964,24 +6414,24 @@ void test_ecdsa_end_to_end(void) {
}
/* Construct and verify corresponding public key. */
- CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+ CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
/* Verify exporting and importing public key. */
- CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED));
+ CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyc, &pubkeyclen, &pubkey, secp256k1_testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED));
memset(&pubkey, 0, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1);
/* Verify negation changes the key and changes it back */
memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);
+ CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey_tmp) == 1);
CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0);
- CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);
+ CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey_tmp) == 1);
CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0);
/* Verify private key import and export. */
- CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_testrand_bits(1) == 1));
- CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);
+ CHECK(ec_privkey_export_der(CTX, seckey, &seckeylen, privkey, secp256k1_testrand_bits(1) == 1));
+ CHECK(ec_privkey_import_der(CTX, privkey2, seckey, seckeylen) == 1);
CHECK(secp256k1_memcmp_var(privkey, privkey2, 32) == 0);
/* Optionally tweak the keys using addition. */
@@ -5994,17 +6444,17 @@ void test_ecdsa_end_to_end(void) {
secp256k1_pubkey pubkey2;
secp256k1_testrand256_test(rnd);
memcpy(privkey_tmp, privkey, 32);
- ret1 = secp256k1_ec_seckey_tweak_add(ctx, privkey, rnd);
- ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd);
+ ret1 = secp256k1_ec_seckey_tweak_add(CTX, privkey, rnd);
+ ret2 = secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, rnd);
/* Check that privkey alias gives same result */
- ret3 = secp256k1_ec_privkey_tweak_add(ctx, privkey_tmp, rnd);
+ ret3 = secp256k1_ec_privkey_tweak_add(CTX, privkey_tmp, rnd);
CHECK(ret1 == ret2);
CHECK(ret2 == ret3);
if (ret1 == 0) {
return;
}
CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0);
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1);
CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
}
@@ -6018,29 +6468,29 @@ void test_ecdsa_end_to_end(void) {
secp256k1_pubkey pubkey2;
secp256k1_testrand256_test(rnd);
memcpy(privkey_tmp, privkey, 32);
- ret1 = secp256k1_ec_seckey_tweak_mul(ctx, privkey, rnd);
- ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd);
+ ret1 = secp256k1_ec_seckey_tweak_mul(CTX, privkey, rnd);
+ ret2 = secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, rnd);
/* Check that privkey alias gives same result */
- ret3 = secp256k1_ec_privkey_tweak_mul(ctx, privkey_tmp, rnd);
+ ret3 = secp256k1_ec_privkey_tweak_mul(CTX, privkey_tmp, rnd);
CHECK(ret1 == ret2);
CHECK(ret2 == ret3);
if (ret1 == 0) {
return;
}
CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0);
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1);
CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
}
/* Sign. */
- CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);
- CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1);
- CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &signature[4], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &signature[1], message, privkey, NULL, extra) == 1);
extra[31] = 1;
- CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &signature[2], message, privkey, NULL, extra) == 1);
extra[31] = 0;
extra[0] = 1;
- CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &signature[3], message, privkey, NULL, extra) == 1);
CHECK(secp256k1_memcmp_var(&signature[0], &signature[4], sizeof(signature[0])) == 0);
CHECK(secp256k1_memcmp_var(&signature[0], &signature[1], sizeof(signature[0])) != 0);
CHECK(secp256k1_memcmp_var(&signature[0], &signature[2], sizeof(signature[0])) != 0);
@@ -6049,41 +6499,41 @@ void test_ecdsa_end_to_end(void) {
CHECK(secp256k1_memcmp_var(&signature[1], &signature[3], sizeof(signature[0])) != 0);
CHECK(secp256k1_memcmp_var(&signature[2], &signature[3], sizeof(signature[0])) != 0);
/* Verify. */
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[1], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[2], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[3], message, &pubkey) == 1);
/* Test lower-S form, malleate, verify and fail, test again, malleate again */
- CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0]));
- secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]);
+ CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[0]));
+ secp256k1_ecdsa_signature_load(CTX, &r, &s, &signature[0]);
secp256k1_scalar_negate(&s, &s);
secp256k1_ecdsa_signature_save(&signature[5], &r, &s);
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0);
- CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));
- CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5]));
- CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));
- CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5]));
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 0);
+ CHECK(secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5]));
+ CHECK(secp256k1_ecdsa_signature_normalize(CTX, &signature[5], &signature[5]));
+ CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5]));
+ CHECK(!secp256k1_ecdsa_signature_normalize(CTX, &signature[5], &signature[5]));
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1);
secp256k1_scalar_negate(&s, &s);
secp256k1_ecdsa_signature_save(&signature[5], &r, &s);
- CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1);
+ CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5]));
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1);
CHECK(secp256k1_memcmp_var(&signature[5], &signature[0], 64) == 0);
/* Serialize/parse DER and verify again */
- CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1);
memset(&signature[0], 0, sizeof(signature[0]));
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1);
/* Serialize/destroy/parse DER and verify again. */
siglen = 74;
- CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1);
sig[secp256k1_testrand_int(siglen)] += 1 + secp256k1_testrand_int(255);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 ||
- secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 0 ||
+ secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 0);
}
-void test_random_pubkeys(void) {
+static void test_random_pubkeys(void) {
secp256k1_ge elem;
secp256k1_ge elem2;
unsigned char in[65];
@@ -6143,7 +6593,7 @@ void test_random_pubkeys(void) {
}
}
-void run_pubkey_comparison(void) {
+static void run_pubkey_comparison(void) {
unsigned char pk1_ser[33] = {
0x02,
0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11,
@@ -6158,55 +6608,55 @@ void run_pubkey_comparison(void) {
secp256k1_pubkey pk2;
int32_t ecount = 0;
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pk1, pk1_ser, sizeof(pk1_ser)) == 1);
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pk2, pk2_ser, sizeof(pk2_ser)) == 1);
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pk1, pk1_ser, sizeof(pk1_ser)) == 1);
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk2_ser, sizeof(pk2_ser)) == 1);
- secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, NULL, &pk2) < 0);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, NULL, &pk2) < 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk1, NULL) > 0);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, NULL) > 0);
CHECK(ecount == 2);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk1, &pk2) < 0);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk2, &pk1) > 0);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk1, &pk1) == 0);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk2, &pk2) == 0);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk1) == 0);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk2) == 0);
CHECK(ecount == 2);
{
secp256k1_pubkey pk_tmp;
memset(&pk_tmp, 0, sizeof(pk_tmp)); /* illegal pubkey */
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk_tmp, &pk2) < 0);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk2) < 0);
CHECK(ecount == 3);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk_tmp, &pk_tmp) == 0);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk_tmp) == 0);
CHECK(ecount == 5);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk2, &pk_tmp) > 0);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk_tmp) > 0);
CHECK(ecount == 6);
}
- secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
+ secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
/* Make pk2 the same as pk1 but with 3 rather than 2. Note that in
* an uncompressed encoding, these would have the opposite ordering */
pk1_ser[0] = 3;
- CHECK(secp256k1_ec_pubkey_parse(ctx, &pk2, pk1_ser, sizeof(pk1_ser)) == 1);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk1, &pk2) < 0);
- CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk2, &pk1) > 0);
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk1_ser, sizeof(pk1_ser)) == 1);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0);
}
-void run_random_pubkeys(void) {
+static void run_random_pubkeys(void) {
int i;
- for (i = 0; i < 10*count; i++) {
+ for (i = 0; i < 10*COUNT; i++) {
test_random_pubkeys();
}
}
-void run_ecdsa_end_to_end(void) {
+static void run_ecdsa_end_to_end(void) {
int i;
- for (i = 0; i < 64*count; i++) {
+ for (i = 0; i < 64*COUNT; i++) {
test_ecdsa_end_to_end();
}
}
-int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) {
+static int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) {
static const unsigned char zeroes[32] = {0};
int ret = 0;
@@ -6223,23 +6673,23 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_
size_t len_der_lax = 2048;
int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0;
- parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen);
+ parsed_der = secp256k1_ecdsa_signature_parse_der(CTX, &sig_der, sig, siglen);
if (parsed_der) {
- ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0;
+ ret |= (!secp256k1_ecdsa_signature_serialize_compact(CTX, compact_der, &sig_der)) << 0;
valid_der = (secp256k1_memcmp_var(compact_der, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der + 32, zeroes, 32) != 0);
}
if (valid_der) {
- ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1;
+ ret |= (!secp256k1_ecdsa_signature_serialize_der(CTX, roundtrip_der, &len_der, &sig_der)) << 1;
roundtrips_der = (len_der == siglen) && secp256k1_memcmp_var(roundtrip_der, sig, siglen) == 0;
}
- parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen);
+ parsed_der_lax = ecdsa_signature_parse_der_lax(CTX, &sig_der_lax, sig, siglen);
if (parsed_der_lax) {
- ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10;
+ ret |= (!secp256k1_ecdsa_signature_serialize_compact(CTX, compact_der_lax, &sig_der_lax)) << 10;
valid_der_lax = (secp256k1_memcmp_var(compact_der_lax, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der_lax + 32, zeroes, 32) != 0);
}
if (valid_der_lax) {
- ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11;
+ ret |= (!secp256k1_ecdsa_signature_serialize_der(CTX, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11;
roundtrips_der_lax = (len_der_lax == siglen) && secp256k1_memcmp_var(roundtrip_der_lax, sig, siglen) == 0;
}
@@ -6451,9 +6901,9 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
CHECK(tlen == *len);
}
-void run_ecdsa_der_parse(void) {
+static void run_ecdsa_der_parse(void) {
int i,j;
- for (i = 0; i < 200 * count; i++) {
+ for (i = 0; i < 200 * COUNT; i++) {
unsigned char buffer[2048];
size_t buflen = 0;
int certainly_der = 0;
@@ -6483,7 +6933,7 @@ void run_ecdsa_der_parse(void) {
}
/* Tests several edge cases. */
-void test_ecdsa_edge_cases(void) {
+static void test_ecdsa_edge_cases(void) {
int t;
secp256k1_ecdsa_signature sig;
@@ -6497,7 +6947,7 @@ void test_ecdsa_edge_cases(void) {
secp256k1_scalar_negate(&ss, &ss);
secp256k1_scalar_inverse(&ss, &ss);
secp256k1_scalar_set_int(&sr, 1);
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr);
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &keyj, &sr);
secp256k1_ge_set_gej(&key, &keyj);
msg = ss;
CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0);
@@ -6680,71 +7130,71 @@ void test_ecdsa_edge_cases(void) {
0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9,
};
ecount = 0;
- secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0);
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0);
+ secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 0);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 0);
msg[31] = 0xaa;
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0);
+ CHECK(secp256k1_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1);
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, key) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, NULL, msg, &pubkey) == 0);
CHECK(ecount == 4);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, NULL, &pubkey) == 0);
CHECK(ecount == 5);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, NULL) == 0);
CHECK(ecount == 6);
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 1);
CHECK(ecount == 6);
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, NULL) == 0);
CHECK(ecount == 7);
/* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */
- CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0);
+ CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 0);
CHECK(ecount == 8);
siglen = 72;
- CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig) == 0);
CHECK(ecount == 9);
- CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig) == 0);
CHECK(ecount == 10);
- CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL) == 0);
CHECK(ecount == 11);
- CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 1);
CHECK(ecount == 11);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, NULL, signature, siglen) == 0);
CHECK(ecount == 12);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen) == 0);
CHECK(ecount == 13);
- CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1);
+ CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, signature, siglen) == 1);
CHECK(ecount == 13);
siglen = 10;
/* Too little room for a signature does not fail via ARGCHECK. */
- CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 0);
CHECK(ecount == 13);
ecount = 0;
- CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdsa_signature_normalize(CTX, NULL, NULL) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0);
+ CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, NULL, &sig) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0);
+ CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, NULL) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1);
+ CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, &sig) == 1);
CHECK(ecount == 3);
- CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, NULL, signature) == 0);
CHECK(ecount == 4);
- CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, NULL) == 0);
CHECK(ecount == 5);
- CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1);
+ CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 1);
CHECK(ecount == 5);
memset(signature, 255, 64);
- CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 0);
CHECK(ecount == 5);
- secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
+ secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
}
/* Nonce function corner cases. */
@@ -6761,33 +7211,33 @@ void test_ecdsa_edge_cases(void) {
msg[31] = 1;
/* High key results in signature failure. */
memset(key, 0xFF, 32);
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0);
CHECK(is_empty_signature(&sig));
/* Zero key results in signature failure. */
memset(key, 0, 32);
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0);
CHECK(is_empty_signature(&sig));
/* Nonce function failure results in signature failure. */
key[31] = 1;
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_fail, extra) == 0);
CHECK(is_empty_signature(&sig));
/* The retry loop successfully makes its way to the first good value. */
- CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_retry, extra) == 1);
CHECK(!is_empty_signature(&sig));
- CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, nonce_function_rfc6979, extra) == 1);
CHECK(!is_empty_signature(&sig2));
CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0);
/* The default nonce function is deterministic. */
- CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1);
CHECK(!is_empty_signature(&sig2));
CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0);
/* The default nonce function changes output with different messages. */
for(i = 0; i < 256; i++) {
int j;
msg[0] = i;
- CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1);
CHECK(!is_empty_signature(&sig2));
- secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
+ secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2);
for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
}
@@ -6798,9 +7248,9 @@ void test_ecdsa_edge_cases(void) {
for(i = 256; i < 512; i++) {
int j;
key[0] = i - 256;
- CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1);
CHECK(!is_empty_signature(&sig2));
- secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
+ secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2);
for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
}
@@ -6815,18 +7265,18 @@ void test_ecdsa_edge_cases(void) {
unsigned char nonce2[32];
unsigned char nonce3[32];
unsigned char nonce4[32];
- VG_UNDEF(nonce,32);
- VG_UNDEF(nonce2,32);
- VG_UNDEF(nonce3,32);
- VG_UNDEF(nonce4,32);
+ SECP256K1_CHECKMEM_UNDEFINE(nonce,32);
+ SECP256K1_CHECKMEM_UNDEFINE(nonce2,32);
+ SECP256K1_CHECKMEM_UNDEFINE(nonce3,32);
+ SECP256K1_CHECKMEM_UNDEFINE(nonce4,32);
CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1);
- VG_CHECK(nonce,32);
+ SECP256K1_CHECKMEM_CHECK(nonce,32);
CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1);
- VG_CHECK(nonce2,32);
+ SECP256K1_CHECKMEM_CHECK(nonce2,32);
CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1);
- VG_CHECK(nonce3,32);
+ SECP256K1_CHECKMEM_CHECK(nonce3,32);
CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1);
- VG_CHECK(nonce4,32);
+ SECP256K1_CHECKMEM_CHECK(nonce4,32);
CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0);
CHECK(secp256k1_memcmp_var(nonce, nonce3, 32) != 0);
CHECK(secp256k1_memcmp_var(nonce, nonce4, 32) != 0);
@@ -6846,13 +7296,13 @@ void test_ecdsa_edge_cases(void) {
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
};
size_t outlen = 300;
- CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0));
+ CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 0));
outlen = 300;
- CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1));
+ CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 1));
}
}
-void run_ecdsa_edge_cases(void) {
+static void run_ecdsa_edge_cases(void) {
test_ecdsa_edge_cases();
}
@@ -6872,7 +7322,7 @@ void run_ecdsa_edge_cases(void) {
# include "modules/schnorrsig/tests_impl.h"
#endif
-void run_secp256k1_memczero_test(void) {
+static void run_secp256k1_memczero_test(void) {
unsigned char buf1[6] = {1, 2, 3, 4, 5, 6};
unsigned char buf2[sizeof(buf1)];
@@ -6887,7 +7337,7 @@ void run_secp256k1_memczero_test(void) {
CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0);
}
-void run_secp256k1_byteorder_tests(void) {
+static void run_secp256k1_byteorder_tests(void) {
const uint32_t x = 0xFF03AB45;
const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45};
unsigned char buf[4];
@@ -6900,7 +7350,7 @@ void run_secp256k1_byteorder_tests(void) {
CHECK(x == x_);
}
-void int_cmov_test(void) {
+static void int_cmov_test(void) {
int r = INT_MAX;
int a = 0;
@@ -6925,7 +7375,7 @@ void int_cmov_test(void) {
}
-void fe_cmov_test(void) {
+static void fe_cmov_test(void) {
static const secp256k1_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0);
static const secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
static const secp256k1_fe max = SECP256K1_FE_CONST(
@@ -6955,7 +7405,7 @@ void fe_cmov_test(void) {
CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0);
}
-void fe_storage_cmov_test(void) {
+static void fe_storage_cmov_test(void) {
static const secp256k1_fe_storage zero = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0);
static const secp256k1_fe_storage one = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
static const secp256k1_fe_storage max = SECP256K1_FE_STORAGE_CONST(
@@ -6985,7 +7435,7 @@ void fe_storage_cmov_test(void) {
CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0);
}
-void scalar_cmov_test(void) {
+static void scalar_cmov_test(void) {
static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
static const secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
static const secp256k1_scalar max = SECP256K1_SCALAR_CONST(
@@ -7015,7 +7465,7 @@ void scalar_cmov_test(void) {
CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0);
}
-void ge_storage_cmov_test(void) {
+static void ge_storage_cmov_test(void) {
static const secp256k1_ge_storage zero = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
static const secp256k1_ge_storage one = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1);
static const secp256k1_ge_storage max = SECP256K1_GE_STORAGE_CONST(
@@ -7047,7 +7497,7 @@ void ge_storage_cmov_test(void) {
CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0);
}
-void run_cmov_tests(void) {
+static void run_cmov_tests(void) {
int_cmov_test();
fe_cmov_test();
fe_storage_cmov_test();
@@ -7066,40 +7516,69 @@ int main(int argc, char **argv) {
/* find iteration count */
if (argc > 1) {
- count = strtol(argv[1], NULL, 0);
+ COUNT = strtol(argv[1], NULL, 0);
} else {
const char* env = getenv("SECP256K1_TEST_ITERS");
if (env && strlen(env) > 0) {
- count = strtol(env, NULL, 0);
+ COUNT = strtol(env, NULL, 0);
}
}
- if (count <= 0) {
+ if (COUNT <= 0) {
fputs("An iteration count of 0 or less is not allowed.\n", stderr);
return EXIT_FAILURE;
}
- printf("test count = %i\n", count);
+ printf("test count = %i\n", COUNT);
/* find random seed */
secp256k1_testrand_init(argc > 2 ? argv[2] : NULL);
- /* initialize */
- run_context_tests(0);
- run_context_tests(1);
- run_scratch_tests();
- ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
- if (secp256k1_testrand_bits(1)) {
+ /*** Setup test environment ***/
+
+ /* Create a global context available to all tests */
+ CTX = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+ /* Randomize the context only with probability 15/16
+ to make sure we test without context randomization from time to time.
+ TODO Reconsider this when recalibrating the tests. */
+ if (secp256k1_testrand_bits(4)) {
unsigned char rand32[32];
secp256k1_testrand256(rand32);
- CHECK(secp256k1_context_randomize(ctx, secp256k1_testrand_bits(1) ? rand32 : NULL));
+ CHECK(secp256k1_context_randomize(CTX, rand32));
}
+ /* Make a writable copy of secp256k1_context_static in order to test the effect of API functions
+ that write to the context. The API does not support cloning the static context, so we use
+ memcpy instead. The user is not supposed to copy a context but we should still ensure that
+ the API functions handle copies of the static context gracefully. */
+ STATIC_CTX = malloc(sizeof(*secp256k1_context_static));
+ CHECK(STATIC_CTX != NULL);
+ memcpy(STATIC_CTX, secp256k1_context_static, sizeof(secp256k1_context));
+ CHECK(!secp256k1_context_is_proper(STATIC_CTX));
+
+ /*** Run actual tests ***/
+
+ /* selftest tests */
+ run_selftest_tests();
+ /* context tests */
+ run_proper_context_tests(0); run_proper_context_tests(1);
+ run_static_context_tests(0); run_static_context_tests(1);
+ run_deprecated_context_flags_test();
+
+ /* scratch tests */
+ run_scratch_tests();
+
+ /* randomness tests */
run_rand_bits();
run_rand_int();
+ /* integer arithmetic tests */
+#ifdef SECP256K1_WIDEMUL_INT128
+ run_int128_tests();
+#endif
run_ctz_tests();
run_modinv_tests();
run_inverse_tests();
+ /* hash tests */
run_sha256_known_output_tests();
run_sha256_counter_tests();
run_hmac_sha256_tests();
@@ -7152,6 +7631,7 @@ int main(int argc, char **argv) {
#endif
/* ecdsa tests */
+ run_ec_illegal_argument_tests();
run_pubkey_comparison();
run_random_pubkeys();
run_ecdsa_der_parse();
@@ -7178,10 +7658,11 @@ int main(int argc, char **argv) {
run_cmov_tests();
- secp256k1_testrand_finish();
+ /*** Tear down test environment ***/
+ free(STATIC_CTX);
+ secp256k1_context_destroy(CTX);
- /* shutdown */
- secp256k1_context_destroy(ctx);
+ secp256k1_testrand_finish();
printf("no problems found\n");
return 0;
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
index 6a4e2340f2..86b9334cae 100644
--- a/src/secp256k1/src/tests_exhaustive.c
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -4,10 +4,6 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
@@ -28,7 +24,7 @@
static int count = 2;
/** stolen from tests.c */
-void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
+static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
CHECK(a->infinity == b->infinity);
if (a->infinity) {
return;
@@ -37,7 +33,7 @@ void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
CHECK(secp256k1_fe_equal_var(&a->y, &b->y));
}
-void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
+static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
secp256k1_fe z2s;
secp256k1_fe u1, u2, s1, s2;
CHECK(a->infinity == b->infinity);
@@ -54,7 +50,7 @@ void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
CHECK(secp256k1_fe_equal_var(&s1, &s2));
}
-void random_fe(secp256k1_fe *x) {
+static void random_fe(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_testrand256(bin);
@@ -74,7 +70,7 @@ SECP256K1_INLINE static int skip_section(uint64_t* iter) {
return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core;
}
-int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
+static int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
const unsigned char *key32, const unsigned char *algo16,
void *data, unsigned int attempt) {
secp256k1_scalar s;
@@ -94,7 +90,7 @@ int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned cha
return 1;
}
-void test_exhaustive_endomorphism(const secp256k1_ge *group) {
+static void test_exhaustive_endomorphism(const secp256k1_ge *group) {
int i;
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
secp256k1_ge res;
@@ -103,7 +99,7 @@ void test_exhaustive_endomorphism(const secp256k1_ge *group) {
}
}
-void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) {
+static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) {
int i, j;
uint64_t iter = 0;
@@ -163,7 +159,7 @@ void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *gr
}
}
-void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_gej *groupj) {
+static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_gej *groupj) {
int i, j, r_log;
uint64_t iter = 0;
for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) {
@@ -199,7 +195,7 @@ static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t
return 1;
}
-void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) {
+static void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) {
int i, j, k, x, y;
uint64_t iter = 0;
secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096);
@@ -229,7 +225,7 @@ void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
}
-void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) {
+static void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) {
secp256k1_fe x;
unsigned char x_bin[32];
k %= EXHAUSTIVE_TEST_ORDER;
@@ -239,7 +235,7 @@ void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overfl
secp256k1_scalar_set_b32(r, x_bin, overflow);
}
-void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) {
+static void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) {
int s, r, msg, key;
uint64_t iter = 0;
for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) {
@@ -292,7 +288,7 @@ void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *gr
}
}
-void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
+static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
int i, j, k;
uint64_t iter = 0;
@@ -342,15 +338,15 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
}
#ifdef ENABLE_MODULE_RECOVERY
-#include "src/modules/recovery/tests_exhaustive_impl.h"
+#include "modules/recovery/tests_exhaustive_impl.h"
#endif
#ifdef ENABLE_MODULE_EXTRAKEYS
-#include "src/modules/extrakeys/tests_exhaustive_impl.h"
+#include "modules/extrakeys/tests_exhaustive_impl.h"
#endif
#ifdef ENABLE_MODULE_SCHNORRSIG
-#include "src/modules/schnorrsig/tests_exhaustive_impl.h"
+#include "modules/schnorrsig/tests_exhaustive_impl.h"
#endif
int main(int argc, char** argv) {
@@ -396,7 +392,7 @@ int main(int argc, char** argv) {
while (count--) {
/* Build context */
- ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_testrand256(rand32);
CHECK(secp256k1_context_randomize(ctx, rand32));
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index dac86bd77f..e75c5ad552 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -7,15 +7,16 @@
#ifndef SECP256K1_UTIL_H
#define SECP256K1_UTIL_H
-#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
-#endif
-
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <limits.h>
+#define STR_(x) #x
+#define STR(x) STR_(x)
+#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x
+#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x))
+
typedef struct {
void (*fn)(const char *text, void* data);
const void* data;
@@ -96,25 +97,6 @@ static const secp256k1_callback default_error_callback = {
#define VERIFY_SETUP(stmt)
#endif
-/* Define `VG_UNDEF` and `VG_CHECK` when VALGRIND is defined */
-#if !defined(VG_CHECK)
-# if defined(VALGRIND)
-# include <valgrind/memcheck.h>
-# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))
-# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))
-# else
-# define VG_UNDEF(x,y)
-# define VG_CHECK(x,y)
-# endif
-#endif
-
-/* Like `VG_CHECK` but on VERIFY only */
-#if defined(VERIFY)
-#define VG_CHECK_VERIFY(x,y) VG_CHECK((x), (y))
-#else
-#define VG_CHECK_VERIFY(x,y)
-#endif
-
static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {
void *ret = malloc(size);
if (ret == NULL) {
@@ -225,28 +207,36 @@ static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag)
*r = (int)(r_masked | a_masked);
}
-/* If USE_FORCE_WIDEMUL_{INT128,INT64} is set, use that wide multiplication implementation.
- * Otherwise use the presence of __SIZEOF_INT128__ to decide.
- */
-#if defined(USE_FORCE_WIDEMUL_INT128)
+#if defined(USE_FORCE_WIDEMUL_INT128_STRUCT)
+/* If USE_FORCE_WIDEMUL_INT128_STRUCT is set, use int128_struct. */
+# define SECP256K1_WIDEMUL_INT128 1
+# define SECP256K1_INT128_STRUCT 1
+#elif defined(USE_FORCE_WIDEMUL_INT128)
+/* If USE_FORCE_WIDEMUL_INT128 is set, use int128. */
# define SECP256K1_WIDEMUL_INT128 1
+# define SECP256K1_INT128_NATIVE 1
#elif defined(USE_FORCE_WIDEMUL_INT64)
+/* If USE_FORCE_WIDEMUL_INT64 is set, use int64. */
# define SECP256K1_WIDEMUL_INT64 1
#elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__)
+/* If a native 128-bit integer type exists, use int128. */
# define SECP256K1_WIDEMUL_INT128 1
+# define SECP256K1_INT128_NATIVE 1
+#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
+/* On 64-bit MSVC targets (x86_64 and arm64), use int128_struct
+ * (which has special logic to implement using intrinsics on those systems). */
+# define SECP256K1_WIDEMUL_INT128 1
+# define SECP256K1_INT128_STRUCT 1
+#elif SIZE_MAX > 0xffffffff
+/* Systems with 64-bit pointers (and thus registers) very likely benefit from
+ * using 64-bit based arithmetic (even if we need to fall back to 32x32->64 based
+ * multiplication logic). */
+# define SECP256K1_WIDEMUL_INT128 1
+# define SECP256K1_INT128_STRUCT 1
#else
+/* Lastly, fall back to int64 based arithmetic. */
# define SECP256K1_WIDEMUL_INT64 1
#endif
-#if defined(SECP256K1_WIDEMUL_INT128)
-# if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__)
-SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
-SECP256K1_GNUC_EXT typedef __int128 int128_t;
-#define UINT128_MAX ((uint128_t)(-1))
-#define INT128_MAX ((int128_t)(UINT128_MAX >> 1))
-#define INT128_MIN (-INT128_MAX - 1)
-/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */
-# endif
-#endif
#ifndef __has_builtin
#define __has_builtin(x) 0
@@ -261,7 +251,7 @@ static SECP256K1_INLINE int secp256k1_ctz32_var_debruijn(uint32_t x) {
0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B,
0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B
};
- return debruijn[((x & -x) * 0x04D7651F) >> 27];
+ return debruijn[(uint32_t)((x & -x) * 0x04D7651FU) >> 27];
}
/* Determine the number of trailing zero bits in a (non-zero) 64-bit x.
@@ -274,7 +264,7 @@ static SECP256K1_INLINE int secp256k1_ctz64_var_debruijn(uint64_t x) {
63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
};
- return debruijn[((x & -x) * 0x022FDD63CC95386D) >> 58];
+ return debruijn[(uint64_t)((x & -x) * 0x022FDD63CC95386DU) >> 58];
}
/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */
diff --git a/src/serialize.h b/src/serialize.h
index 89a9f32240..7bc7b10779 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -1005,11 +1005,11 @@ struct CSerActionUnserialize
class CSizeComputer
{
protected:
- size_t nSize;
+ size_t nSize{0};
const int nVersion;
public:
- explicit CSizeComputer(int nVersionIn) : nSize(0), nVersion(nVersionIn) {}
+ explicit CSizeComputer(int nVersionIn) : nVersion(nVersionIn) {}
void write(Span<const std::byte> src)
{
diff --git a/src/shutdown.cpp b/src/shutdown.cpp
index 1dbc55aeb5..2fffc0663c 100644
--- a/src/shutdown.cpp
+++ b/src/shutdown.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -27,7 +27,7 @@ bool AbortNode(const std::string& strMessage, bilingual_str user_message)
if (user_message.empty()) {
user_message = _("A fatal internal error occurred, see debug.log for details");
}
- AbortError(user_message);
+ InitError(user_message);
StartShutdown();
return false;
}
diff --git a/src/span.h b/src/span.h
index 444d63001f..4692eca7fb 100644
--- a/src/span.h
+++ b/src/span.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -96,7 +96,7 @@ template<typename C>
class Span
{
C* m_data;
- std::size_t m_size;
+ std::size_t m_size{0};
template <class T>
struct is_Span_int : public std::false_type {};
@@ -107,7 +107,7 @@ class Span
public:
- constexpr Span() noexcept : m_data(nullptr), m_size(0) {}
+ constexpr Span() noexcept : m_data(nullptr) {}
/** Construct a span from a begin pointer and a size.
*
diff --git a/src/streams.h b/src/streams.h
index 24778ab331..8788343809 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -182,16 +182,13 @@ public:
* >> and << read and write unformatted data using the above serialization templates.
* Fills with data in linear time; some stringstream implementations take N^2 time.
*/
-class CDataStream
+class DataStream
{
protected:
using vector_type = SerializeData;
vector_type vch;
vector_type::size_type m_read_pos{0};
- int nType;
- int nVersion;
-
public:
typedef vector_type::allocator_type allocator_type;
typedef vector_type::size_type size_type;
@@ -203,23 +200,9 @@ public:
typedef vector_type::const_iterator const_iterator;
typedef vector_type::reverse_iterator reverse_iterator;
- explicit CDataStream(int nTypeIn, int nVersionIn)
- : nType{nTypeIn},
- nVersion{nVersionIn} {}
-
- explicit CDataStream(Span<const uint8_t> sp, int type, int version) : CDataStream{AsBytes(sp), type, version} {}
- explicit CDataStream(Span<const value_type> sp, int nTypeIn, int nVersionIn)
- : vch(sp.data(), sp.data() + sp.size()),
- nType{nTypeIn},
- nVersion{nVersionIn} {}
-
- template <typename... Args>
- CDataStream(int nTypeIn, int nVersionIn, Args&&... args)
- : nType{nTypeIn},
- nVersion{nVersionIn}
- {
- ::SerializeMany(*this, std::forward<Args>(args)...);
- }
+ explicit DataStream() {}
+ explicit DataStream(Span<const uint8_t> sp) : DataStream{AsBytes(sp)} {}
+ explicit DataStream(Span<const value_type> sp) : vch(sp.data(), sp.data() + sp.size()) {}
std::string str() const
{
@@ -269,14 +252,8 @@ public:
// Stream subset
//
bool eof() const { return size() == 0; }
- CDataStream* rdbuf() { return this; }
int in_avail() const { return size(); }
- void SetType(int n) { nType = n; }
- int GetType() const { return nType; }
- void SetVersion(int n) { nVersion = n; }
- int GetVersion() const { return nVersion; }
-
void read(Span<value_type> dst)
{
if (dst.size() == 0) return;
@@ -284,7 +261,7 @@ public:
// Read from the beginning of the buffer
auto next_read_pos{CheckedAdd(m_read_pos, dst.size())};
if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {
- throw std::ios_base::failure("CDataStream::read(): end of data");
+ throw std::ios_base::failure("DataStream::read(): end of data");
}
memcpy(dst.data(), &vch[m_read_pos], dst.size());
if (next_read_pos.value() == vch.size()) {
@@ -300,7 +277,7 @@ public:
// Ignore from the beginning of the buffer
auto next_read_pos{CheckedAdd(m_read_pos, num_ignore)};
if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {
- throw std::ios_base::failure("CDataStream::ignore(): end of data");
+ throw std::ios_base::failure("DataStream::ignore(): end of data");
}
if (next_read_pos.value() == vch.size()) {
m_read_pos = 0;
@@ -325,7 +302,7 @@ public:
}
template<typename T>
- CDataStream& operator<<(const T& obj)
+ DataStream& operator<<(const T& obj)
{
// Serialize to this stream
::Serialize(*this, obj);
@@ -333,7 +310,7 @@ public:
}
template<typename T>
- CDataStream& operator>>(T&& obj)
+ DataStream& operator>>(T&& obj)
{
// Unserialize from this stream
::Unserialize(*this, obj);
@@ -364,6 +341,42 @@ public:
}
};
+class CDataStream : public DataStream
+{
+private:
+ int nType;
+ int nVersion;
+
+public:
+ explicit CDataStream(int nTypeIn, int nVersionIn)
+ : nType{nTypeIn},
+ nVersion{nVersionIn} {}
+
+ explicit CDataStream(Span<const uint8_t> sp, int type, int version) : CDataStream{AsBytes(sp), type, version} {}
+ explicit CDataStream(Span<const value_type> sp, int nTypeIn, int nVersionIn)
+ : DataStream{sp},
+ nType{nTypeIn},
+ nVersion{nVersionIn} {}
+
+ int GetType() const { return nType; }
+ void SetVersion(int n) { nVersion = n; }
+ int GetVersion() const { return nVersion; }
+
+ template <typename T>
+ CDataStream& operator<<(const T& obj)
+ {
+ ::Serialize(*this, obj);
+ return *this;
+ }
+
+ template <typename T>
+ CDataStream& operator>>(T&& obj)
+ {
+ ::Unserialize(*this, obj);
+ return *this;
+ }
+};
+
template <typename IStream>
class BitStreamReader
{
@@ -488,12 +501,14 @@ public:
AutoFile(const AutoFile&) = delete;
AutoFile& operator=(const AutoFile&) = delete;
- void fclose()
+ int fclose()
{
+ int retval{0};
if (file) {
- ::fclose(file);
+ retval = ::fclose(file);
file = nullptr;
}
+ return retval;
}
/** Get wrapped FILE* with transfer of ownership.
@@ -605,13 +620,12 @@ private:
const int nVersion;
FILE *src; //!< source file
- uint64_t nSrcPos; //!< how many bytes have been read from source
- uint64_t m_read_pos; //!< how many bytes have been read from this
+ uint64_t nSrcPos{0}; //!< how many bytes have been read from source
+ uint64_t m_read_pos{0}; //!< 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<std::byte> vchBuf; //!< the buffer
-protected:
//! read data from the source to fill the buffer
bool Fill() {
unsigned int pos = nSrcPos % vchBuf.size();
@@ -629,9 +643,31 @@ protected:
return true;
}
+ //! Advance the stream's read pointer (m_read_pos) by up to 'length' bytes,
+ //! filling the buffer from the file so that at least one byte is available.
+ //! Return a pointer to the available buffer data and the number of bytes
+ //! (which may be less than the requested length) that may be accessed
+ //! beginning at that pointer.
+ std::pair<std::byte*, size_t> AdvanceStream(size_t length)
+ {
+ assert(m_read_pos <= nSrcPos);
+ if (m_read_pos + length > nReadLimit) {
+ throw std::ios_base::failure("Attempt to position past buffer limit");
+ }
+ // If there are no bytes available, read from the file.
+ if (m_read_pos == nSrcPos && length > 0) Fill();
+
+ size_t buffer_offset{static_cast<size_t>(m_read_pos % vchBuf.size())};
+ size_t buffer_available{static_cast<size_t>(vchBuf.size() - buffer_offset)};
+ size_t bytes_until_source_pos{static_cast<size_t>(nSrcPos - m_read_pos)};
+ size_t advance{std::min({length, buffer_available, bytes_until_source_pos})};
+ m_read_pos += advance;
+ return std::make_pair(&vchBuf[buffer_offset], advance);
+ }
+
public:
CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn)
- : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), m_read_pos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0})
+ : nType(nTypeIn), nVersion(nVersionIn), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0})
{
if (nRewindIn >= nBufSize)
throw std::ios_base::failure("Rewind limit must be less than buffer size");
@@ -666,24 +702,21 @@ public:
//! read a number of bytes
void read(Span<std::byte> dst)
{
- if (dst.size() + m_read_pos > nReadLimit) {
- throw std::ios_base::failure("Read attempted past buffer limit");
- }
while (dst.size() > 0) {
- if (m_read_pos == nSrcPos)
- Fill();
- unsigned int pos = m_read_pos % vchBuf.size();
- size_t nNow = dst.size();
- if (nNow + pos > vchBuf.size())
- nNow = vchBuf.size() - pos;
- if (nNow + m_read_pos > nSrcPos)
- nNow = nSrcPos - m_read_pos;
- memcpy(dst.data(), &vchBuf[pos], nNow);
- m_read_pos += nNow;
- dst = dst.subspan(nNow);
+ auto [buffer_pointer, length]{AdvanceStream(dst.size())};
+ memcpy(dst.data(), buffer_pointer, length);
+ dst = dst.subspan(length);
}
}
+ //! Move the read position ahead in the stream to the given position.
+ //! Use SetPos() to back up in the stream, not SkipTo().
+ void SkipTo(const uint64_t file_pos)
+ {
+ assert(file_pos >= m_read_pos);
+ while (m_read_pos < file_pos) AdvanceStream(file_pos - m_read_pos);
+ }
+
//! return the current reading position
uint64_t GetPos() const {
return m_read_pos;
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index c6bd685189..a0918bf463 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -56,6 +56,7 @@ struct secure_allocator : public std::allocator<T> {
};
// This is exactly like std::string, but with a custom allocator.
+// TODO: Consider finding a way to make incoming RPC request.params[i] mlock()ed as well
typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
#endif // BITCOIN_SUPPORT_ALLOCATORS_SECURE_H
diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h
index 0befe0ffcd..795eea3bc0 100644
--- a/src/support/allocators/zeroafterfree.h
+++ b/src/support/allocators/zeroafterfree.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/support/cleanse.h b/src/support/cleanse.h
index b1227770c7..161f3cc388 100644
--- a/src/support/cleanse.h
+++ b/src/support/cleanse.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index e48accf0a4..f92d1d8fb7 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2020 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -19,6 +19,9 @@
#endif
#include <algorithm>
+#include <limits>
+#include <stdexcept>
+#include <utility>
#ifdef ARENA_DEBUG
#include <iomanip>
#include <iostream>
@@ -39,12 +42,12 @@ static inline size_t align_up(size_t x, size_t align)
// Implementation: Arena
Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
- base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
+ base(base_in), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
{
// Start with one free chunk that covers the entire arena
auto it = size_to_free_chunk.emplace(size_in, base);
chunks_free.emplace(base, it);
- chunks_free_end.emplace(base + size_in, it);
+ chunks_free_end.emplace(static_cast<char*>(base) + size_in, it);
}
Arena::~Arena()
@@ -70,8 +73,9 @@ void* Arena::alloc(size_t size)
// Create the used-chunk, taking its space from the end of the free-chunk
const size_t size_remaining = size_ptr_it->first - size;
- auto allocated = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first;
- chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first);
+ char* const free_chunk = static_cast<char*>(size_ptr_it->second);
+ auto allocated = chunks_used.emplace(free_chunk + size_remaining, size).first;
+ chunks_free_end.erase(free_chunk + size_ptr_it->first);
if (size_ptr_it->first == size) {
// whole chunk is used up
chunks_free.erase(size_ptr_it->second);
@@ -79,11 +83,11 @@ void* Arena::alloc(size_t size)
// still some memory left in the chunk
auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second);
chunks_free[size_ptr_it->second] = it_remaining;
- chunks_free_end.emplace(size_ptr_it->second + size_remaining, it_remaining);
+ chunks_free_end.emplace(free_chunk + size_remaining, it_remaining);
}
size_to_free_chunk.erase(size_ptr_it);
- return reinterpret_cast<void*>(allocated->first);
+ return allocated->first;
}
void Arena::free(void *ptr)
@@ -94,11 +98,11 @@ void Arena::free(void *ptr)
}
// Remove chunk from used map
- auto i = chunks_used.find(static_cast<char*>(ptr));
+ auto i = chunks_used.find(ptr);
if (i == chunks_used.end()) {
throw std::runtime_error("Arena: invalid or double free");
}
- std::pair<char*, size_t> freed = *i;
+ auto freed = std::make_pair(static_cast<char*>(i->first), i->second);
chunks_used.erase(i);
// coalesce freed with previous chunk
@@ -277,8 +281,8 @@ size_t PosixLockedPageAllocator::GetLimit()
/*******************************************************************************/
// Implementation: LockedPool
-LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):
- allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)
+LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in)
+ : allocator(std::move(allocator_in)), lf_cb(lf_cb_in)
{
}
diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h
index 03e4e371a3..81e0df513a 100644
--- a/src/support/lockedpool.h
+++ b/src/support/lockedpool.h
@@ -5,11 +5,11 @@
#ifndef BITCOIN_SUPPORT_LOCKEDPOOL_H
#define BITCOIN_SUPPORT_LOCKEDPOOL_H
-#include <stdint.h>
+#include <cstddef>
#include <list>
#include <map>
-#include <mutex>
#include <memory>
+#include <mutex>
#include <unordered_map>
/**
@@ -89,23 +89,23 @@ public:
*/
bool addressInArena(void *ptr) const { return ptr >= base && ptr < end; }
private:
- typedef std::multimap<size_t, char*> SizeToChunkSortedMap;
+ typedef std::multimap<size_t, void*> SizeToChunkSortedMap;
/** Map to enable O(log(n)) best-fit allocation, as it's sorted by size */
SizeToChunkSortedMap size_to_free_chunk;
- typedef std::unordered_map<char*, SizeToChunkSortedMap::const_iterator> ChunkToSizeMap;
+ typedef std::unordered_map<void*, SizeToChunkSortedMap::const_iterator> ChunkToSizeMap;
/** Map from begin of free chunk to its node in size_to_free_chunk */
ChunkToSizeMap chunks_free;
/** Map from end of free chunk to its node in size_to_free_chunk */
ChunkToSizeMap chunks_free_end;
/** Map from begin of used chunk to its size */
- std::unordered_map<char*, size_t> chunks_used;
+ std::unordered_map<void*, size_t> chunks_used;
/** Base address of arena */
- char* base;
+ void* base;
/** End address of arena */
- char* end;
+ void* end;
/** Minimum chunk alignment */
size_t alignment;
};
@@ -198,7 +198,7 @@ private:
std::list<LockedPageArena> arenas;
LockingFailed_Callback lf_cb;
- size_t cumulative_bytes_locked;
+ size_t cumulative_bytes_locked{0};
/** Mutex protects access to this pool's data structures, including arenas.
*/
mutable std::mutex mutex;
diff --git a/src/sync.h b/src/sync.h
index a9d0091bd2..7242a793ab 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,7 +11,7 @@
#include <logging/timer.h>
#endif
-#include <threadsafety.h>
+#include <threadsafety.h> // IWYU pragma: export
#include <util/macros.h>
#include <condition_variable>
@@ -111,7 +111,7 @@ public:
return PARENT::try_lock();
}
- using UniqueLock = std::unique_lock<PARENT>;
+ using unique_lock = std::unique_lock<PARENT>;
#ifdef __clang__
//! For negative capabilities in the Clang Thread Safety Analysis.
//! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction
@@ -147,11 +147,13 @@ inline void AssertLockNotHeldInline(const char* name, const char* file, int line
inline void AssertLockNotHeldInline(const char* name, const char* file, int line, GlobalMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); }
#define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs)
-/** Wrapper around std::unique_lock style lock for Mutex. */
-template <typename Mutex, typename Base = typename Mutex::UniqueLock>
-class SCOPED_LOCKABLE UniqueLock : public Base
+/** Wrapper around std::unique_lock style lock for MutexType. */
+template <typename MutexType>
+class SCOPED_LOCKABLE UniqueLock : public MutexType::unique_lock
{
private:
+ using Base = typename MutexType::unique_lock;
+
void Enter(const char* pszName, const char* pszFile, int nLine)
{
EnterCritical(pszName, pszFile, nLine, Base::mutex());
@@ -173,7 +175,7 @@ private:
}
public:
- UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
+ UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
{
if (fTry)
TryEnter(pszName, pszFile, nLine);
@@ -181,7 +183,7 @@ public:
Enter(pszName, pszFile, nLine);
}
- UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
+ UniqueLock(MutexType* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
{
if (!pmutexIn) return;
@@ -241,29 +243,24 @@ public:
#define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, #g, __FILE__, __LINE__)
-template<typename MutexArg>
-using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
-
// When locking a Mutex, require negative capability to ensure the lock
// is not already held
inline Mutex& MaybeCheckNotHeld(Mutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
inline Mutex* MaybeCheckNotHeld(Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
-// When locking a GlobalMutex, just check it is not locked in the surrounding scope
-inline GlobalMutex& MaybeCheckNotHeld(GlobalMutex& cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
-inline GlobalMutex* MaybeCheckNotHeld(GlobalMutex* cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
-
-// When locking a RecursiveMutex, it's okay to already hold the lock
-// but check that it is not known to be locked in the surrounding scope anyway
-inline RecursiveMutex& MaybeCheckNotHeld(RecursiveMutex& cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
-inline RecursiveMutex* MaybeCheckNotHeld(RecursiveMutex* cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
+// When locking a GlobalMutex or RecursiveMutex, just check it is not
+// locked in the surrounding scope.
+template <typename MutexType>
+inline MutexType& MaybeCheckNotHeld(MutexType& m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }
+template <typename MutexType>
+inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }
-#define LOCK(cs) DebugLock<decltype(cs)> UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
+#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) \
- DebugLock<decltype(cs1)> criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
- DebugLock<decltype(cs2)> criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
-#define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
-#define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
+ UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
+ UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
+#define TRY_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
+#define WAIT_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
#define ENTER_CRITICAL_SECTION(cs) \
{ \
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index b10d32ccec..758691cfde 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -67,22 +67,22 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
CNetAddr source = ResolveIP("252.2.2.2");
// Test: Does Addrman respond correctly when empty.
- BOOST_CHECK_EQUAL(addrman->size(), 0U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 0U);
auto addr_null = addrman->Select().first;
- BOOST_CHECK_EQUAL(addr_null.ToString(), "[::]:0");
+ BOOST_CHECK_EQUAL(addr_null.ToStringAddrPort(), "[::]:0");
// Test: Does Addrman::Add work as expected.
CService addr1 = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
- BOOST_CHECK_EQUAL(addrman->size(), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
auto addr_ret1 = addrman->Select().first;
- BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
+ BOOST_CHECK_EQUAL(addr_ret1.ToStringAddrPort(), "250.1.1.1:8333");
// Test: Does IP address deduplication work correctly.
// Expected dup IP should not be added.
CService addr1_dup = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(!addrman->Add({CAddress(addr1_dup, NODE_NONE)}, source));
- BOOST_CHECK_EQUAL(addrman->size(), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
// Test: New table has one addr and we add a diff addr we should
@@ -93,7 +93,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
CService addr2 = ResolveService("250.1.1.2", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
- BOOST_CHECK(addrman->size() >= 1);
+ BOOST_CHECK(addrman->Size() >= 1);
// Test: reset addrman and test AddrMan::Add multiple addresses works as expected
addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE));
vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE));
BOOST_CHECK(addrman->Add(vAddr, source));
- BOOST_CHECK(addrman->size() >= 1);
+ BOOST_CHECK(addrman->Size() >= 1);
}
BOOST_AUTO_TEST_CASE(addrman_ports)
@@ -110,26 +110,26 @@ BOOST_AUTO_TEST_CASE(addrman_ports)
CNetAddr source = ResolveIP("252.2.2.2");
- BOOST_CHECK_EQUAL(addrman->size(), 0U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 0U);
// Test 7; Addr with same IP but diff port does not replace existing addr.
CService addr1 = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
- BOOST_CHECK_EQUAL(addrman->size(), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
CService addr1_port = ResolveService("250.1.1.1", 8334);
BOOST_CHECK(addrman->Add({CAddress(addr1_port, NODE_NONE)}, source));
- BOOST_CHECK_EQUAL(addrman->size(), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 2U);
auto addr_ret2 = addrman->Select().first;
- BOOST_CHECK(addr_ret2.ToString() == "250.1.1.1:8333" || addr_ret2.ToString() == "250.1.1.1:8334");
+ BOOST_CHECK(addr_ret2.ToStringAddrPort() == "250.1.1.1:8333" || addr_ret2.ToStringAddrPort() == "250.1.1.1:8334");
// Test: Add same IP but diff port to tried table; this converts the entry with
// the specified port to tried, but not the other.
addrman->Good(CAddress(addr1_port, NODE_NONE));
- BOOST_CHECK_EQUAL(addrman->size(), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 2U);
bool newOnly = true;
auto addr_ret3 = addrman->Select(newOnly).first;
- BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
+ BOOST_CHECK_EQUAL(addr_ret3.ToStringAddrPort(), "250.1.1.1:8333");
}
@@ -142,22 +142,22 @@ BOOST_AUTO_TEST_CASE(addrman_select)
// Test: Select from new with 1 addr in new.
CService addr1 = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
- BOOST_CHECK_EQUAL(addrman->size(), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
bool newOnly = true;
auto addr_ret1 = addrman->Select(newOnly).first;
- BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
+ BOOST_CHECK_EQUAL(addr_ret1.ToStringAddrPort(), "250.1.1.1:8333");
// Test: move addr to tried, select from new expected nothing returned.
BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
- BOOST_CHECK_EQUAL(addrman->size(), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
auto addr_ret2 = addrman->Select(newOnly).first;
- BOOST_CHECK_EQUAL(addr_ret2.ToString(), "[::]:0");
+ BOOST_CHECK_EQUAL(addr_ret2.ToStringAddrPort(), "[::]:0");
auto addr_ret3 = addrman->Select().first;
- BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
+ BOOST_CHECK_EQUAL(addr_ret3.ToStringAddrPort(), "250.1.1.1:8333");
- BOOST_CHECK_EQUAL(addrman->size(), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
// Add three addresses to new table.
@@ -182,7 +182,7 @@ BOOST_AUTO_TEST_CASE(addrman_select)
BOOST_CHECK(addrman->Good(CAddress(addr7, NODE_NONE)));
// Test: 6 addrs + 1 addr from last test = 7.
- BOOST_CHECK_EQUAL(addrman->size(), 7U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 7U);
// Test: Select pulls from new and tried regardless of port number.
std::set<uint16_t> ports;
@@ -200,25 +200,25 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions)
uint32_t num_addrs{0};
- BOOST_CHECK_EQUAL(addrman->size(), num_addrs);
+ BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
while (num_addrs < 22) { // Magic number! 250.1.1.1 - 250.1.1.22 do not collide with deterministic key = 1
CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
// Test: No collision in new table yet.
- BOOST_CHECK_EQUAL(addrman->size(), num_addrs);
+ BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
}
// Test: new table collision!
CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
uint32_t collisions{1};
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
- BOOST_CHECK_EQUAL(addrman->size(), num_addrs - collisions);
+ BOOST_CHECK_EQUAL(addrman->Size(), num_addrs - collisions);
CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
- BOOST_CHECK_EQUAL(addrman->size(), num_addrs - collisions);
+ BOOST_CHECK_EQUAL(addrman->Size(), num_addrs - collisions);
}
BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
@@ -236,7 +236,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
}
AddressPosition addr_pos = addrman->FindAddressEntry(addr).value();
BOOST_CHECK_EQUAL(addr_pos.multiplicity, 1U);
- BOOST_CHECK_EQUAL(addrman->size(), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
// if nTime increases, an addr can occur in up to 8 buckets
// The acceptance probability decreases exponentially with existing multiplicity -
@@ -250,7 +250,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value();
BOOST_CHECK_EQUAL(addr_pos_multi.multiplicity, 8U);
// multiplicity doesn't affect size
- BOOST_CHECK_EQUAL(addrman->size(), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
}
BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
@@ -261,7 +261,7 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
uint32_t num_addrs{0};
- BOOST_CHECK_EQUAL(addrman->size(), num_addrs);
+ BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
while (num_addrs < 35) { // Magic number! 250.1.1.1 - 250.1.1.35 do not collide in tried with deterministic key = 1
CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
@@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
// Test: Sanity check, GetAddr should never return anything if addrman
// is empty.
- BOOST_CHECK_EQUAL(addrman->size(), 0U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 0U);
std::vector<CAddress> vAddr1 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
@@ -336,11 +336,11 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
}
std::vector<CAddress> vAddr = addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt);
- size_t percent23 = (addrman->size() * 23) / 100;
+ size_t percent23 = (addrman->Size() * 23) / 100;
BOOST_CHECK_EQUAL(vAddr.size(), percent23);
BOOST_CHECK_EQUAL(vAddr.size(), 461U);
- // (Addrman.size() < number of addresses added) due to address collisions.
- BOOST_CHECK_EQUAL(addrman->size(), 2006U);
+ // (addrman.Size() < number of addresses added) due to address collisions.
+ BOOST_CHECK_EQUAL(addrman->Size(), 2006U);
}
@@ -681,7 +681,7 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
addrman->Add({new1, tried1, new2, tried2}, CNetAddr{});
addrman->Good(tried1);
addrman->Good(tried2);
- BOOST_REQUIRE_EQUAL(addrman->size(), 4);
+ BOOST_REQUIRE_EQUAL(addrman->Size(), 4);
stream << *addrman;
@@ -704,17 +704,17 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
stream >> *addrman;
- BOOST_CHECK_EQUAL(addrman->size(), 2);
+ BOOST_CHECK_EQUAL(addrman->Size(), 2);
}
BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
- BOOST_CHECK(addrman->size() == 0);
+ BOOST_CHECK(addrman->Size() == 0);
// Empty addrman should return blank addrman info.
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
// Add twenty two addresses.
CNetAddr source = ResolveIP("252.2.2.2");
@@ -724,7 +724,7 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
// No collisions in tried.
BOOST_CHECK(addrman->Good(addr));
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
}
// Ensure Good handles duplicates well.
@@ -736,7 +736,7 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
BOOST_CHECK(!addrman->Good(addr));
// Verify duplicate address not marked as a collision.
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
}
}
@@ -758,13 +758,13 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
CService addr36 = ResolveService("250.1.1.36");
BOOST_CHECK(addrman->Add({CAddress(addr36, NODE_NONE)}, source));
BOOST_CHECK(!addrman->Good(addr36));
- BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToString(), "250.1.1.19:0");
+ BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.19:0");
// 36 should be discarded and 19 not evicted.
// This means we keep 19 in the tried table and
// 36 stays in the new table.
addrman->ResolveCollisions();
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
// Lets create two collisions.
for (unsigned int i = 37; i < 59; i++) {
@@ -778,28 +778,28 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
BOOST_CHECK(addrman->Add({CAddress(addr59, NODE_NONE)}, source));
BOOST_CHECK(!addrman->Good(addr59));
- BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToString(), "250.1.1.10:0");
+ BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.10:0");
// Cause a second collision in the new table.
BOOST_CHECK(!addrman->Add({CAddress(addr36, NODE_NONE)}, source));
// 36 still cannot be moved from new to tried due to colliding with 19
BOOST_CHECK(!addrman->Good(addr36));
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() != "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() != "[::]:0");
// Resolve all collisions.
addrman->ResolveCollisions();
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
}
BOOST_AUTO_TEST_CASE(addrman_evictionworks)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
- BOOST_CHECK(addrman->size() == 0);
+ BOOST_CHECK(addrman->Size() == 0);
// Empty addrman should return blank addrman info.
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
// Add 35 addresses
CNetAddr source = ResolveIP("252.2.2.2");
@@ -817,7 +817,7 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
BOOST_CHECK(!addrman->Good(addr));
auto info = addrman->SelectTriedCollision().first;
- BOOST_CHECK_EQUAL(info.ToString(), "250.1.1.19:0");
+ BOOST_CHECK_EQUAL(info.ToStringAddrPort(), "250.1.1.19:0");
// Ensure test of address fails, so that it is evicted.
// Update entry in tried by setting last good connection in the deep past.
@@ -826,7 +826,7 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
// Should swap 36 for 19.
addrman->ResolveCollisions();
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
AddressPosition addr_pos{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()};
BOOST_CHECK(addr_pos.tried);
@@ -835,18 +835,18 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
// We check this by verifying Good() returns false and also verifying that
// we have no collisions.
BOOST_CHECK(!addrman->Good(addr));
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
// 19 should fail as a collision (not a duplicate) if we now attempt to move
// it to the tried table.
CService addr19 = ResolveService("250.1.1.19");
BOOST_CHECK(!addrman->Good(addr19));
- BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToString(), "250.1.1.36:0");
+ BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.36:0");
// Eviction is also successful if too much time has passed since last try
SetMockTime(GetTime() + 4 * 60 *60);
addrman->ResolveCollisions();
- BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
+ BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
//Now 19 is in tried again, and 36 back to new
AddressPosition addr_pos19{addrman->FindAddressEntry(CAddress(addr19, NODE_NONE)).value()};
BOOST_CHECK(addr_pos19.tried);
@@ -878,14 +878,14 @@ BOOST_AUTO_TEST_CASE(load_addrman)
BOOST_CHECK(Lookup("252.5.1.1", source, 8333, false));
std::vector<CAddress> addresses{CAddress(addr1, NODE_NONE), CAddress(addr2, NODE_NONE), CAddress(addr3, NODE_NONE)};
BOOST_CHECK(addrman.Add(addresses, source));
- BOOST_CHECK(addrman.size() == 3);
+ BOOST_CHECK(addrman.Size() == 3);
// Test that the de-serialization does not throw an exception.
CDataStream ssPeers1 = AddrmanToStream(addrman);
bool exceptionThrown = false;
AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
- BOOST_CHECK(addrman1.size() == 0);
+ BOOST_CHECK(addrman1.Size() == 0);
try {
unsigned char pchMsgTmp[4];
ssPeers1 >> pchMsgTmp;
@@ -894,16 +894,16 @@ BOOST_AUTO_TEST_CASE(load_addrman)
exceptionThrown = true;
}
- BOOST_CHECK(addrman1.size() == 3);
+ BOOST_CHECK(addrman1.Size() == 3);
BOOST_CHECK(exceptionThrown == false);
// Test that ReadFromStream creates an addrman with the correct number of addrs.
CDataStream ssPeers2 = AddrmanToStream(addrman);
AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
- BOOST_CHECK(addrman2.size() == 0);
+ BOOST_CHECK(addrman2.Size() == 0);
ReadFromStream(addrman2, ssPeers2);
- BOOST_CHECK(addrman2.size() == 3);
+ BOOST_CHECK(addrman2.Size() == 3);
}
// Produce a corrupt peers.dat that claims 20 addrs when it only has one addr.
@@ -939,7 +939,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
CDataStream ssPeers1 = MakeCorruptPeersDat();
bool exceptionThrown = false;
AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
- BOOST_CHECK(addrman1.size() == 0);
+ BOOST_CHECK(addrman1.Size() == 0);
try {
unsigned char pchMsgTmp[4];
ssPeers1 >> pchMsgTmp;
@@ -947,15 +947,13 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
} catch (const std::exception&) {
exceptionThrown = true;
}
- // Even though de-serialization failed addrman is not left in a clean state.
- BOOST_CHECK(addrman1.size() == 1);
BOOST_CHECK(exceptionThrown);
// Test that ReadFromStream fails if peers.dat is corrupt
CDataStream ssPeers2 = MakeCorruptPeersDat();
AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
- BOOST_CHECK(addrman2.size() == 0);
+ BOOST_CHECK(addrman2.Size() == 0);
BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
}
@@ -969,7 +967,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
const auto start_time{Now<NodeSeconds>() - 10000s};
addr.nTime = start_time;
BOOST_CHECK(addrman->Add({addr}, source));
- BOOST_CHECK_EQUAL(addrman->size(), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
// Updating an addrman entry with a different port doesn't change it
CAddress addr_diff_port{CAddress(ResolveService("250.1.1.1", 8334), NODE_NONE)};
@@ -990,4 +988,42 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
}
+BOOST_AUTO_TEST_CASE(addrman_size)
+{
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
+ const CNetAddr source = ResolveIP("252.2.2.2");
+
+ // empty addrman
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 0U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 0U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 0U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 0U);
+
+ // add two ipv4 addresses, one to tried and new
+ const CAddress addr1{ResolveService("250.1.1.1", 8333), NODE_NONE};
+ BOOST_CHECK(addrman->Add({addr1}, source));
+ BOOST_CHECK(addrman->Good(addr1));
+ const CAddress addr2{ResolveService("250.1.1.2", 8333), NODE_NONE};
+ BOOST_CHECK(addrman->Add({addr2}, source));
+
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/true), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 1U);
+
+ // add one i2p address to new
+ CService i2p_addr;
+ i2p_addr.SetSpecial("UDHDrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.I2P");
+ const CAddress addr3{i2p_addr, NODE_NONE};
+ BOOST_CHECK(addrman->Add({addr3}, source));
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 3U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/std::nullopt), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/true), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/argsman_tests.cpp b/src/test/argsman_tests.cpp
new file mode 100644
index 0000000000..d00876bc70
--- /dev/null
+++ b/src/test/argsman_tests.cpp
@@ -0,0 +1,1043 @@
+// Copyright (c) 2011-2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <util/system.h>
+#include <fs.h>
+#include <sync.h>
+#include <test/util/logging.h>
+#include <test/util/setup_common.h>
+#include <test/util/str.h>
+#include <util/strencodings.h>
+#include <univalue.h>
+
+#include <array>
+#include <optional>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(argsman_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(util_datadir)
+{
+ // Use local args variable instead of m_args to avoid making assumptions about test setup
+ ArgsManager args;
+ args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
+
+ const fs::path dd_norm = args.GetDataDirBase();
+
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/");
+ args.ClearPathCache();
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
+
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/.");
+ args.ClearPathCache();
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
+
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/./");
+ args.ClearPathCache();
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
+
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/.//");
+ args.ClearPathCache();
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
+}
+
+struct TestArgsManager : public ArgsManager
+{
+ TestArgsManager() { m_network_only_args.clear(); }
+ void ReadConfigString(const std::string str_config)
+ {
+ std::istringstream streamConfig(str_config);
+ {
+ LOCK(cs_args);
+ m_settings.ro_config.clear();
+ m_config_sections.clear();
+ }
+ std::string error;
+ BOOST_REQUIRE(ReadConfigStream(streamConfig, "", error));
+ }
+ void SetNetworkOnlyArg(const std::string arg)
+ {
+ LOCK(cs_args);
+ m_network_only_args.insert(arg);
+ }
+ void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args)
+ {
+ for (const auto& arg : args) {
+ AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS);
+ }
+ }
+ using ArgsManager::GetSetting;
+ using ArgsManager::GetSettingsList;
+ using ArgsManager::ReadConfigStream;
+ using ArgsManager::cs_args;
+ using ArgsManager::m_network;
+ using ArgsManager::m_settings;
+};
+
+//! Test GetSetting and GetArg type coercion, negation, and default value handling.
+class CheckValueTest : public TestChain100Setup
+{
+public:
+ struct Expect {
+ util::SettingsValue setting;
+ bool default_string = false;
+ bool default_int = false;
+ bool default_bool = false;
+ const char* string_value = nullptr;
+ std::optional<int64_t> int_value;
+ std::optional<bool> bool_value;
+ std::optional<std::vector<std::string>> list_value;
+ const char* error = nullptr;
+
+ explicit Expect(util::SettingsValue s) : setting(std::move(s)) {}
+ Expect& DefaultString() { default_string = true; return *this; }
+ Expect& DefaultInt() { default_int = true; return *this; }
+ Expect& DefaultBool() { default_bool = true; return *this; }
+ Expect& String(const char* s) { string_value = s; return *this; }
+ Expect& Int(int64_t i) { int_value = i; return *this; }
+ Expect& Bool(bool b) { bool_value = b; return *this; }
+ Expect& List(std::vector<std::string> m) { list_value = std::move(m); return *this; }
+ Expect& Error(const char* e) { error = e; return *this; }
+ };
+
+ void CheckValue(unsigned int flags, const char* arg, const Expect& expect)
+ {
+ TestArgsManager test;
+ test.SetupArgs({{"-value", flags}});
+ const char* argv[] = {"ignored", arg};
+ std::string error;
+ bool success = test.ParseParameters(arg ? 2 : 1, (char**)argv, error);
+
+ BOOST_CHECK_EQUAL(test.GetSetting("-value").write(), expect.setting.write());
+ auto settings_list = test.GetSettingsList("-value");
+ if (expect.setting.isNull() || expect.setting.isFalse()) {
+ BOOST_CHECK_EQUAL(settings_list.size(), 0U);
+ } else {
+ BOOST_CHECK_EQUAL(settings_list.size(), 1U);
+ BOOST_CHECK_EQUAL(settings_list[0].write(), expect.setting.write());
+ }
+
+ if (expect.error) {
+ BOOST_CHECK(!success);
+ BOOST_CHECK_NE(error.find(expect.error), std::string::npos);
+ } else {
+ BOOST_CHECK(success);
+ BOOST_CHECK_EQUAL(error, "");
+ }
+
+ if (expect.default_string) {
+ BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), "zzzzz");
+ } else if (expect.string_value) {
+ BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), expect.string_value);
+ } else {
+ BOOST_CHECK(!success);
+ }
+
+ if (expect.default_int) {
+ BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), 99999);
+ } else if (expect.int_value) {
+ BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), *expect.int_value);
+ } else {
+ BOOST_CHECK(!success);
+ }
+
+ if (expect.default_bool) {
+ BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), false);
+ BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), true);
+ } else if (expect.bool_value) {
+ BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), *expect.bool_value);
+ BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), *expect.bool_value);
+ } else {
+ BOOST_CHECK(!success);
+ }
+
+ if (expect.list_value) {
+ auto l = test.GetArgs("-value");
+ BOOST_CHECK_EQUAL_COLLECTIONS(l.begin(), l.end(), expect.list_value->begin(), expect.list_value->end());
+ } else {
+ BOOST_CHECK(!success);
+ }
+ }
+};
+
+BOOST_FIXTURE_TEST_CASE(util_CheckValue, CheckValueTest)
+{
+ using M = ArgsManager;
+
+ CheckValue(M::ALLOW_ANY, nullptr, Expect{{}}.DefaultString().DefaultInt().DefaultBool().List({}));
+ CheckValue(M::ALLOW_ANY, "-novalue", Expect{false}.String("0").Int(0).Bool(false).List({}));
+ CheckValue(M::ALLOW_ANY, "-novalue=", Expect{false}.String("0").Int(0).Bool(false).List({}));
+ CheckValue(M::ALLOW_ANY, "-novalue=0", Expect{true}.String("1").Int(1).Bool(true).List({"1"}));
+ CheckValue(M::ALLOW_ANY, "-novalue=1", Expect{false}.String("0").Int(0).Bool(false).List({}));
+ CheckValue(M::ALLOW_ANY, "-novalue=2", Expect{false}.String("0").Int(0).Bool(false).List({}));
+ CheckValue(M::ALLOW_ANY, "-novalue=abc", Expect{true}.String("1").Int(1).Bool(true).List({"1"}));
+ CheckValue(M::ALLOW_ANY, "-value", Expect{""}.String("").Int(0).Bool(true).List({""}));
+ CheckValue(M::ALLOW_ANY, "-value=", Expect{""}.String("").Int(0).Bool(true).List({""}));
+ CheckValue(M::ALLOW_ANY, "-value=0", Expect{"0"}.String("0").Int(0).Bool(false).List({"0"}));
+ CheckValue(M::ALLOW_ANY, "-value=1", Expect{"1"}.String("1").Int(1).Bool(true).List({"1"}));
+ CheckValue(M::ALLOW_ANY, "-value=2", Expect{"2"}.String("2").Int(2).Bool(true).List({"2"}));
+ CheckValue(M::ALLOW_ANY, "-value=abc", Expect{"abc"}.String("abc").Int(0).Bool(false).List({"abc"}));
+}
+
+struct NoIncludeConfTest {
+ std::string Parse(const char* arg)
+ {
+ TestArgsManager test;
+ test.SetupArgs({{"-includeconf", ArgsManager::ALLOW_ANY}});
+ std::array argv{"ignored", arg};
+ std::string error;
+ (void)test.ParseParameters(argv.size(), argv.data(), error);
+ return error;
+ }
+};
+
+BOOST_FIXTURE_TEST_CASE(util_NoIncludeConf, NoIncludeConfTest)
+{
+ BOOST_CHECK_EQUAL(Parse("-noincludeconf"), "");
+ BOOST_CHECK_EQUAL(Parse("-includeconf"), "-includeconf cannot be used from commandline; -includeconf=\"\"");
+ BOOST_CHECK_EQUAL(Parse("-includeconf=file"), "-includeconf cannot be used from commandline; -includeconf=\"file\"");
+}
+
+BOOST_AUTO_TEST_CASE(util_ParseParameters)
+{
+ TestArgsManager testArgs;
+ const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
+ const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
+ const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY);
+ const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
+
+ const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
+
+ std::string error;
+ LOCK(testArgs.cs_args);
+ testArgs.SetupArgs({a, b, ccc, d});
+ BOOST_CHECK(testArgs.ParseParameters(0, (char**)argv_test, error));
+ BOOST_CHECK(testArgs.m_settings.command_line_options.empty() && testArgs.m_settings.ro_config.empty());
+
+ BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error));
+ BOOST_CHECK(testArgs.m_settings.command_line_options.empty() && testArgs.m_settings.ro_config.empty());
+
+ BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error));
+ // expectation: -ignored is ignored (program name argument),
+ // -a, -b and -ccc end up in map, -d ignored because it is after
+ // a non-option argument (non-GNU option parsing)
+ BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 3 && testArgs.m_settings.ro_config.empty());
+ BOOST_CHECK(testArgs.IsArgSet("-a") && testArgs.IsArgSet("-b") && testArgs.IsArgSet("-ccc")
+ && !testArgs.IsArgSet("f") && !testArgs.IsArgSet("-d"));
+ BOOST_CHECK(testArgs.m_settings.command_line_options.count("a") && testArgs.m_settings.command_line_options.count("b") && testArgs.m_settings.command_line_options.count("ccc")
+ && !testArgs.m_settings.command_line_options.count("f") && !testArgs.m_settings.command_line_options.count("d"));
+
+ BOOST_CHECK(testArgs.m_settings.command_line_options["a"].size() == 1);
+ BOOST_CHECK(testArgs.m_settings.command_line_options["a"].front().get_str() == "");
+ BOOST_CHECK(testArgs.m_settings.command_line_options["ccc"].size() == 2);
+ BOOST_CHECK(testArgs.m_settings.command_line_options["ccc"].front().get_str() == "argument");
+ BOOST_CHECK(testArgs.m_settings.command_line_options["ccc"].back().get_str() == "multiple");
+ BOOST_CHECK(testArgs.GetArgs("-ccc").size() == 2);
+}
+
+BOOST_AUTO_TEST_CASE(util_ParseInvalidParameters)
+{
+ TestArgsManager test;
+ test.SetupArgs({{"-registered", ArgsManager::ALLOW_ANY}});
+
+ const char* argv[] = {"ignored", "-registered"};
+ std::string error;
+ BOOST_CHECK(test.ParseParameters(2, (char**)argv, error));
+ BOOST_CHECK_EQUAL(error, "");
+
+ argv[1] = "-unregistered";
+ BOOST_CHECK(!test.ParseParameters(2, (char**)argv, error));
+ BOOST_CHECK_EQUAL(error, "Invalid parameter -unregistered");
+
+ // Make sure registered parameters prefixed with a chain name trigger errors.
+ // (Previously, they were accepted and ignored.)
+ argv[1] = "-test.registered";
+ BOOST_CHECK(!test.ParseParameters(2, (char**)argv, error));
+ BOOST_CHECK_EQUAL(error, "Invalid parameter -test.registered");
+}
+
+static void TestParse(const std::string& str, bool expected_bool, int64_t expected_int)
+{
+ TestArgsManager test;
+ test.SetupArgs({{"-value", ArgsManager::ALLOW_ANY}});
+ std::string arg = "-value=" + str;
+ const char* argv[] = {"ignored", arg.c_str()};
+ std::string error;
+ BOOST_CHECK(test.ParseParameters(2, (char**)argv, error));
+ BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), expected_bool);
+ BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), expected_bool);
+ BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99998), expected_int);
+ BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), expected_int);
+}
+
+// Test bool and int parsing.
+BOOST_AUTO_TEST_CASE(util_ArgParsing)
+{
+ // Some of these cases could be ambiguous or surprising to users, and might
+ // be worth triggering errors or warnings in the future. But for now basic
+ // test coverage is useful to avoid breaking backwards compatibility
+ // unintentionally.
+ TestParse("", true, 0);
+ TestParse(" ", false, 0);
+ TestParse("0", false, 0);
+ TestParse("0 ", false, 0);
+ TestParse(" 0", false, 0);
+ TestParse("+0", false, 0);
+ TestParse("-0", false, 0);
+ TestParse("5", true, 5);
+ TestParse("5 ", true, 5);
+ TestParse(" 5", true, 5);
+ TestParse("+5", true, 5);
+ TestParse("-5", true, -5);
+ TestParse("0 5", false, 0);
+ TestParse("5 0", true, 5);
+ TestParse("050", true, 50);
+ TestParse("0.", false, 0);
+ TestParse("5.", true, 5);
+ TestParse("0.0", false, 0);
+ TestParse("0.5", false, 0);
+ TestParse("5.0", true, 5);
+ TestParse("5.5", true, 5);
+ TestParse("x", false, 0);
+ TestParse("x0", false, 0);
+ TestParse("x5", false, 0);
+ TestParse("0x", false, 0);
+ TestParse("5x", true, 5);
+ TestParse("0x5", false, 0);
+ TestParse("false", false, 0);
+ TestParse("true", false, 0);
+ TestParse("yes", false, 0);
+ TestParse("no", false, 0);
+}
+
+BOOST_AUTO_TEST_CASE(util_GetBoolArg)
+{
+ TestArgsManager testArgs;
+ const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
+ const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
+ const auto c = std::make_pair("-c", ArgsManager::ALLOW_ANY);
+ const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
+ const auto e = std::make_pair("-e", ArgsManager::ALLOW_ANY);
+ const auto f = std::make_pair("-f", ArgsManager::ALLOW_ANY);
+
+ const char *argv_test[] = {
+ "ignored", "-a", "-nob", "-c=0", "-d=1", "-e=false", "-f=true"};
+ std::string error;
+ LOCK(testArgs.cs_args);
+ testArgs.SetupArgs({a, b, c, d, e, f});
+ BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error));
+
+ // Each letter should be set.
+ for (const char opt : "abcdef")
+ BOOST_CHECK(testArgs.IsArgSet({'-', opt}) || !opt);
+
+ // Nothing else should be in the map
+ BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 6 &&
+ testArgs.m_settings.ro_config.empty());
+
+ // The -no prefix should get stripped on the way in.
+ BOOST_CHECK(!testArgs.IsArgSet("-nob"));
+
+ // The -b option is flagged as negated, and nothing else is
+ BOOST_CHECK(testArgs.IsArgNegated("-b"));
+ BOOST_CHECK(!testArgs.IsArgNegated("-a"));
+
+ // Check expected values.
+ BOOST_CHECK(testArgs.GetBoolArg("-a", false) == true);
+ BOOST_CHECK(testArgs.GetBoolArg("-b", true) == false);
+ BOOST_CHECK(testArgs.GetBoolArg("-c", true) == false);
+ BOOST_CHECK(testArgs.GetBoolArg("-d", false) == true);
+ BOOST_CHECK(testArgs.GetBoolArg("-e", true) == false);
+ BOOST_CHECK(testArgs.GetBoolArg("-f", true) == false);
+}
+
+BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
+{
+ // Test some awful edge cases that hopefully no user will ever exercise.
+ TestArgsManager testArgs;
+
+ // Params test
+ const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY);
+ const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
+ const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"};
+ testArgs.SetupArgs({foo, bar});
+ std::string error;
+ BOOST_CHECK(testArgs.ParseParameters(4, (char**)argv_test, error));
+
+ // This was passed twice, second one overrides the negative setting.
+ BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
+ BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "");
+
+ // A double negative is a positive, and not marked as negated.
+ BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
+ BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
+
+ // Config test
+ const char *conf_test = "nofoo=1\nfoo=1\nnobar=0\n";
+ BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error));
+ testArgs.ReadConfigString(conf_test);
+
+ // This was passed twice, second one overrides the negative setting,
+ // and the value.
+ BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
+ BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "1");
+
+ // A double negative is a positive, and does not count as negated.
+ BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
+ BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
+
+ // Combined test
+ const char *combo_test_args[] = {"ignored", "-nofoo", "-bar"};
+ const char *combo_test_conf = "foo=1\nnobar=1\n";
+ BOOST_CHECK(testArgs.ParseParameters(3, (char**)combo_test_args, error));
+ testArgs.ReadConfigString(combo_test_conf);
+
+ // Command line overrides, but doesn't erase old setting
+ BOOST_CHECK(testArgs.IsArgNegated("-foo"));
+ BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
+ BOOST_CHECK(testArgs.GetArgs("-foo").size() == 0);
+
+ // Command line overrides, but doesn't erase old setting
+ BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
+ BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "");
+ BOOST_CHECK(testArgs.GetArgs("-bar").size() == 1
+ && testArgs.GetArgs("-bar").front() == "");
+}
+
+BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
+{
+ const char *str_config =
+ "a=\n"
+ "b=1\n"
+ "ccc=argument\n"
+ "ccc=multiple\n"
+ "d=e\n"
+ "nofff=1\n"
+ "noggg=0\n"
+ "h=1\n"
+ "noh=1\n"
+ "noi=1\n"
+ "i=1\n"
+ "sec1.ccc=extend1\n"
+ "\n"
+ "[sec1]\n"
+ "ccc=extend2\n"
+ "d=eee\n"
+ "h=1\n"
+ "[sec2]\n"
+ "ccc=extend3\n"
+ "iii=2\n";
+
+ TestArgsManager test_args;
+ LOCK(test_args.cs_args);
+ const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
+ const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
+ const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY);
+ const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
+ const auto e = std::make_pair("-e", ArgsManager::ALLOW_ANY);
+ const auto fff = std::make_pair("-fff", ArgsManager::ALLOW_ANY);
+ const auto ggg = std::make_pair("-ggg", ArgsManager::ALLOW_ANY);
+ const auto h = std::make_pair("-h", ArgsManager::ALLOW_ANY);
+ const auto i = std::make_pair("-i", ArgsManager::ALLOW_ANY);
+ const auto iii = std::make_pair("-iii", ArgsManager::ALLOW_ANY);
+ test_args.SetupArgs({a, b, ccc, d, e, fff, ggg, h, i, iii});
+
+ test_args.ReadConfigString(str_config);
+ // expectation: a, b, ccc, d, fff, ggg, h, i end up in map
+ // so do sec1.ccc, sec1.d, sec1.h, sec2.ccc, sec2.iii
+
+ BOOST_CHECK(test_args.m_settings.command_line_options.empty());
+ BOOST_CHECK(test_args.m_settings.ro_config.size() == 3);
+ BOOST_CHECK(test_args.m_settings.ro_config[""].size() == 8);
+ BOOST_CHECK(test_args.m_settings.ro_config["sec1"].size() == 3);
+ BOOST_CHECK(test_args.m_settings.ro_config["sec2"].size() == 2);
+
+ BOOST_CHECK(test_args.m_settings.ro_config[""].count("a"));
+ BOOST_CHECK(test_args.m_settings.ro_config[""].count("b"));
+ BOOST_CHECK(test_args.m_settings.ro_config[""].count("ccc"));
+ BOOST_CHECK(test_args.m_settings.ro_config[""].count("d"));
+ BOOST_CHECK(test_args.m_settings.ro_config[""].count("fff"));
+ BOOST_CHECK(test_args.m_settings.ro_config[""].count("ggg"));
+ BOOST_CHECK(test_args.m_settings.ro_config[""].count("h"));
+ BOOST_CHECK(test_args.m_settings.ro_config[""].count("i"));
+ BOOST_CHECK(test_args.m_settings.ro_config["sec1"].count("ccc"));
+ BOOST_CHECK(test_args.m_settings.ro_config["sec1"].count("h"));
+ BOOST_CHECK(test_args.m_settings.ro_config["sec2"].count("ccc"));
+ BOOST_CHECK(test_args.m_settings.ro_config["sec2"].count("iii"));
+
+ BOOST_CHECK(test_args.IsArgSet("-a"));
+ BOOST_CHECK(test_args.IsArgSet("-b"));
+ BOOST_CHECK(test_args.IsArgSet("-ccc"));
+ BOOST_CHECK(test_args.IsArgSet("-d"));
+ BOOST_CHECK(test_args.IsArgSet("-fff"));
+ BOOST_CHECK(test_args.IsArgSet("-ggg"));
+ BOOST_CHECK(test_args.IsArgSet("-h"));
+ BOOST_CHECK(test_args.IsArgSet("-i"));
+ BOOST_CHECK(!test_args.IsArgSet("-zzz"));
+ BOOST_CHECK(!test_args.IsArgSet("-iii"));
+
+ BOOST_CHECK_EQUAL(test_args.GetArg("-a", "xxx"), "");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-b", "xxx"), "1");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-ccc", "xxx"), "argument");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-d", "xxx"), "e");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-fff", "xxx"), "0");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-ggg", "xxx"), "1");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-h", "xxx"), "0");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-i", "xxx"), "1");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-zzz", "xxx"), "xxx");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-iii", "xxx"), "xxx");
+
+ for (const bool def : {false, true}) {
+ BOOST_CHECK(test_args.GetBoolArg("-a", def));
+ BOOST_CHECK(test_args.GetBoolArg("-b", def));
+ BOOST_CHECK(!test_args.GetBoolArg("-ccc", def));
+ BOOST_CHECK(!test_args.GetBoolArg("-d", def));
+ BOOST_CHECK(!test_args.GetBoolArg("-fff", def));
+ BOOST_CHECK(test_args.GetBoolArg("-ggg", def));
+ BOOST_CHECK(!test_args.GetBoolArg("-h", def));
+ BOOST_CHECK(test_args.GetBoolArg("-i", def));
+ BOOST_CHECK(test_args.GetBoolArg("-zzz", def) == def);
+ BOOST_CHECK(test_args.GetBoolArg("-iii", def) == def);
+ }
+
+ BOOST_CHECK(test_args.GetArgs("-a").size() == 1
+ && test_args.GetArgs("-a").front() == "");
+ BOOST_CHECK(test_args.GetArgs("-b").size() == 1
+ && test_args.GetArgs("-b").front() == "1");
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2
+ && test_args.GetArgs("-ccc").front() == "argument"
+ && test_args.GetArgs("-ccc").back() == "multiple");
+ BOOST_CHECK(test_args.GetArgs("-fff").size() == 0);
+ BOOST_CHECK(test_args.GetArgs("-nofff").size() == 0);
+ BOOST_CHECK(test_args.GetArgs("-ggg").size() == 1
+ && test_args.GetArgs("-ggg").front() == "1");
+ BOOST_CHECK(test_args.GetArgs("-noggg").size() == 0);
+ BOOST_CHECK(test_args.GetArgs("-h").size() == 0);
+ BOOST_CHECK(test_args.GetArgs("-noh").size() == 0);
+ BOOST_CHECK(test_args.GetArgs("-i").size() == 1
+ && test_args.GetArgs("-i").front() == "1");
+ BOOST_CHECK(test_args.GetArgs("-noi").size() == 0);
+ BOOST_CHECK(test_args.GetArgs("-zzz").size() == 0);
+
+ BOOST_CHECK(!test_args.IsArgNegated("-a"));
+ BOOST_CHECK(!test_args.IsArgNegated("-b"));
+ BOOST_CHECK(!test_args.IsArgNegated("-ccc"));
+ BOOST_CHECK(!test_args.IsArgNegated("-d"));
+ BOOST_CHECK(test_args.IsArgNegated("-fff"));
+ BOOST_CHECK(!test_args.IsArgNegated("-ggg"));
+ BOOST_CHECK(test_args.IsArgNegated("-h")); // last setting takes precedence
+ BOOST_CHECK(!test_args.IsArgNegated("-i")); // last setting takes precedence
+ BOOST_CHECK(!test_args.IsArgNegated("-zzz"));
+
+ // Test sections work
+ test_args.SelectConfigNetwork("sec1");
+
+ // same as original
+ BOOST_CHECK_EQUAL(test_args.GetArg("-a", "xxx"), "");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-b", "xxx"), "1");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-fff", "xxx"), "0");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-ggg", "xxx"), "1");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-zzz", "xxx"), "xxx");
+ BOOST_CHECK_EQUAL(test_args.GetArg("-iii", "xxx"), "xxx");
+ // d is overridden
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
+ // section-specific setting
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
+ // section takes priority for multiple values
+ BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend1");
+ // check multiple values works
+ const std::vector<std::string> sec1_ccc_expected = {"extend1","extend2","argument","multiple"};
+ const auto& sec1_ccc_res = test_args.GetArgs("-ccc");
+ BOOST_CHECK_EQUAL_COLLECTIONS(sec1_ccc_res.begin(), sec1_ccc_res.end(), sec1_ccc_expected.begin(), sec1_ccc_expected.end());
+
+ test_args.SelectConfigNetwork("sec2");
+
+ // same as original
+ BOOST_CHECK(test_args.GetArg("-a", "xxx") == "");
+ BOOST_CHECK(test_args.GetArg("-b", "xxx") == "1");
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
+ BOOST_CHECK(test_args.GetArg("-fff", "xxx") == "0");
+ BOOST_CHECK(test_args.GetArg("-ggg", "xxx") == "1");
+ BOOST_CHECK(test_args.GetArg("-zzz", "xxx") == "xxx");
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
+ // section-specific setting
+ BOOST_CHECK(test_args.GetArg("-iii", "xxx") == "2");
+ // section takes priority for multiple values
+ BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend3");
+ // check multiple values works
+ const std::vector<std::string> sec2_ccc_expected = {"extend3","argument","multiple"};
+ const auto& sec2_ccc_res = test_args.GetArgs("-ccc");
+ BOOST_CHECK_EQUAL_COLLECTIONS(sec2_ccc_res.begin(), sec2_ccc_res.end(), sec2_ccc_expected.begin(), sec2_ccc_expected.end());
+
+ // Test section only options
+
+ test_args.SetNetworkOnlyArg("-d");
+ test_args.SetNetworkOnlyArg("-ccc");
+ test_args.SetNetworkOnlyArg("-h");
+
+ test_args.SelectConfigNetwork(CBaseChainParams::MAIN);
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
+
+ test_args.SelectConfigNetwork("sec1");
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
+ BOOST_CHECK(test_args.GetArgs("-d").size() == 1);
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
+
+ test_args.SelectConfigNetwork("sec2");
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "xxx");
+ BOOST_CHECK(test_args.GetArgs("-d").size() == 0);
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 1);
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
+}
+
+BOOST_AUTO_TEST_CASE(util_GetArg)
+{
+ TestArgsManager testArgs;
+ LOCK(testArgs.cs_args);
+ testArgs.m_settings.command_line_options.clear();
+ testArgs.m_settings.command_line_options["strtest1"] = {"string..."};
+ // strtest2 undefined on purpose
+ testArgs.m_settings.command_line_options["inttest1"] = {"12345"};
+ testArgs.m_settings.command_line_options["inttest2"] = {"81985529216486895"};
+ // inttest3 undefined on purpose
+ testArgs.m_settings.command_line_options["booltest1"] = {""};
+ // booltest2 undefined on purpose
+ testArgs.m_settings.command_line_options["booltest3"] = {"0"};
+ testArgs.m_settings.command_line_options["booltest4"] = {"1"};
+
+ // priorities
+ testArgs.m_settings.command_line_options["pritest1"] = {"a", "b"};
+ testArgs.m_settings.ro_config[""]["pritest2"] = {"a", "b"};
+ testArgs.m_settings.command_line_options["pritest3"] = {"a"};
+ testArgs.m_settings.ro_config[""]["pritest3"] = {"b"};
+ testArgs.m_settings.command_line_options["pritest4"] = {"a","b"};
+ testArgs.m_settings.ro_config[""]["pritest4"] = {"c","d"};
+
+ BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string...");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
+ BOOST_CHECK_EQUAL(testArgs.GetIntArg("inttest1", -1), 12345);
+ BOOST_CHECK_EQUAL(testArgs.GetIntArg("inttest2", -1), 81985529216486895LL);
+ BOOST_CHECK_EQUAL(testArgs.GetIntArg("inttest3", -1), -1);
+ BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), true);
+ BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest2", false), false);
+ BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest3", false), false);
+ BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest4", false), true);
+
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest1", "default"), "b");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest2", "default"), "a");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest3", "default"), "a");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest4", "default"), "b");
+}
+
+BOOST_AUTO_TEST_CASE(util_GetChainName)
+{
+ TestArgsManager test_args;
+ const auto testnet = std::make_pair("-testnet", ArgsManager::ALLOW_ANY);
+ const auto regtest = std::make_pair("-regtest", ArgsManager::ALLOW_ANY);
+ test_args.SetupArgs({testnet, regtest});
+
+ const char* argv_testnet[] = {"cmd", "-testnet"};
+ const char* argv_regtest[] = {"cmd", "-regtest"};
+ const char* argv_test_no_reg[] = {"cmd", "-testnet", "-noregtest"};
+ const char* argv_both[] = {"cmd", "-testnet", "-regtest"};
+
+ // equivalent to "-testnet"
+ // regtest in testnet section is ignored
+ const char* testnetconf = "testnet=1\nregtest=0\n[test]\nregtest=1";
+ std::string error;
+
+ BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "main");
+
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest");
+
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
+ BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+
+ BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+
+ // check setting the network to test (and thus making
+ // [test] regtest=1 potentially relevant) doesn't break things
+ test_args.SelectConfigNetwork("test");
+
+ BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_test_no_reg, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+}
+
+// Test different ways settings can be merged, and verify results. This test can
+// be used to confirm that updates to settings code don't change behavior
+// unintentionally.
+//
+// The test covers:
+//
+// - Combining different setting actions. Possible actions are: configuring a
+// setting, negating a setting (adding "-no" prefix), and configuring/negating
+// settings in a network section (adding "main." or "test." prefixes).
+//
+// - Combining settings from command line arguments and a config file.
+//
+// - Combining SoftSet and ForceSet calls.
+//
+// - Testing "main" and "test" network values to make sure settings from network
+// sections are applied and to check for mainnet-specific behaviors like
+// inheriting settings from the default section.
+//
+// - Testing network-specific settings like "-wallet", that may be ignored
+// outside a network section, and non-network specific settings like "-server"
+// that aren't sensitive to the network.
+//
+struct ArgsMergeTestingSetup : public BasicTestingSetup {
+ //! Max number of actions to sequence together. Can decrease this when
+ //! debugging to make test results easier to understand.
+ static constexpr int MAX_ACTIONS = 3;
+
+ enum Action { NONE, SET, NEGATE, SECTION_SET, SECTION_NEGATE };
+ using ActionList = Action[MAX_ACTIONS];
+
+ //! Enumerate all possible test configurations.
+ template <typename Fn>
+ void ForEachMergeSetup(Fn&& fn)
+ {
+ ActionList arg_actions = {};
+ // command_line_options do not have sections. Only iterate over SET and NEGATE
+ ForEachNoDup(arg_actions, SET, NEGATE, [&] {
+ ActionList conf_actions = {};
+ ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] {
+ for (bool soft_set : {false, true}) {
+ for (bool force_set : {false, true}) {
+ for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
+ for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
+ for (bool net_specific : {false, true}) {
+ fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
+ }
+ }
+ }
+ }
+ }
+ });
+ });
+ }
+
+ //! Translate actions into a list of <key>=<value> setting strings.
+ std::vector<std::string> GetValues(const ActionList& actions,
+ const std::string& section,
+ const std::string& name,
+ const std::string& value_prefix)
+ {
+ std::vector<std::string> values;
+ int suffix = 0;
+ for (Action action : actions) {
+ if (action == NONE) break;
+ std::string prefix;
+ if (action == SECTION_SET || action == SECTION_NEGATE) prefix = section + ".";
+ if (action == SET || action == SECTION_SET) {
+ for (int i = 0; i < 2; ++i) {
+ values.push_back(prefix + name + "=" + value_prefix + ToString(++suffix));
+ }
+ }
+ if (action == NEGATE || action == SECTION_NEGATE) {
+ values.push_back(prefix + "no" + name + "=1");
+ }
+ }
+ return values;
+ }
+};
+
+// Regression test covering different ways config settings can be merged. The
+// test parses and merges settings, representing the results as strings that get
+// compared against an expected hash. To debug, the result strings can be dumped
+// to a file (see comments below).
+BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
+{
+ CHash256 out_sha;
+ FILE* out_file = nullptr;
+ if (const char* out_path = getenv("ARGS_MERGE_TEST_OUT")) {
+ out_file = fsbridge::fopen(out_path, "w");
+ if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed");
+ }
+
+ ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions, bool soft_set, bool force_set,
+ const std::string& section, const std::string& network, bool net_specific) {
+ TestArgsManager parser;
+ LOCK(parser.cs_args);
+
+ std::string desc = "net=";
+ desc += network;
+ parser.m_network = network;
+
+ const std::string& name = net_specific ? "wallet" : "server";
+ const std::string key = "-" + name;
+ parser.AddArg(key, name, ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ if (net_specific) parser.SetNetworkOnlyArg(key);
+
+ auto args = GetValues(arg_actions, section, name, "a");
+ std::vector<const char*> argv = {"ignored"};
+ for (auto& arg : args) {
+ arg.insert(0, "-");
+ desc += " ";
+ desc += arg;
+ argv.push_back(arg.c_str());
+ }
+ std::string error;
+ BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
+ BOOST_CHECK_EQUAL(error, "");
+
+ std::string conf;
+ for (auto& conf_val : GetValues(conf_actions, section, name, "c")) {
+ desc += " ";
+ desc += conf_val;
+ conf += conf_val;
+ conf += "\n";
+ }
+ std::istringstream conf_stream(conf);
+ BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
+ BOOST_CHECK_EQUAL(error, "");
+
+ if (soft_set) {
+ desc += " soft";
+ parser.SoftSetArg(key, "soft1");
+ parser.SoftSetArg(key, "soft2");
+ }
+
+ if (force_set) {
+ desc += " force";
+ parser.ForceSetArg(key, "force1");
+ parser.ForceSetArg(key, "force2");
+ }
+
+ desc += " || ";
+
+ if (!parser.IsArgSet(key)) {
+ desc += "unset";
+ BOOST_CHECK(!parser.IsArgNegated(key));
+ BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "default");
+ BOOST_CHECK(parser.GetArgs(key).empty());
+ } else if (parser.IsArgNegated(key)) {
+ desc += "negated";
+ BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "0");
+ BOOST_CHECK(parser.GetArgs(key).empty());
+ } else {
+ desc += parser.GetArg(key, "default");
+ desc += " |";
+ for (const auto& arg : parser.GetArgs(key)) {
+ desc += " ";
+ desc += arg;
+ }
+ }
+
+ std::set<std::string> ignored = parser.GetUnsuitableSectionOnlyArgs();
+ if (!ignored.empty()) {
+ desc += " | ignored";
+ for (const auto& arg : ignored) {
+ desc += " ";
+ desc += arg;
+ }
+ }
+
+ desc += "\n";
+
+ out_sha.Write(MakeUCharSpan(desc));
+ if (out_file) {
+ BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
+ }
+ });
+
+ if (out_file) {
+ if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed");
+ out_file = nullptr;
+ }
+
+ unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE];
+ out_sha.Finalize(out_sha_bytes);
+ std::string out_sha_hex = HexStr(out_sha_bytes);
+
+ // If check below fails, should manually dump the results with:
+ //
+ // ARGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ArgsMerge
+ //
+ // And verify diff against previous results to make sure the changes are expected.
+ //
+ // Results file is formatted like:
+ //
+ // <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output>
+ BOOST_CHECK_EQUAL(out_sha_hex, "d1e436c1cd510d0ec44d5205d4b4e3bee6387d316e0075c58206cb16603f3d82");
+}
+
+// Similar test as above, but for ArgsManager::GetChainName function.
+struct ChainMergeTestingSetup : public BasicTestingSetup {
+ static constexpr int MAX_ACTIONS = 2;
+
+ enum Action { NONE, ENABLE_TEST, DISABLE_TEST, NEGATE_TEST, ENABLE_REG, DISABLE_REG, NEGATE_REG };
+ using ActionList = Action[MAX_ACTIONS];
+
+ //! Enumerate all possible test configurations.
+ template <typename Fn>
+ void ForEachMergeSetup(Fn&& fn)
+ {
+ ActionList arg_actions = {};
+ ForEachNoDup(arg_actions, ENABLE_TEST, NEGATE_REG, [&] {
+ ActionList conf_actions = {};
+ ForEachNoDup(conf_actions, ENABLE_TEST, NEGATE_REG, [&] { fn(arg_actions, conf_actions); });
+ });
+ }
+};
+
+BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
+{
+ CHash256 out_sha;
+ FILE* out_file = nullptr;
+ if (const char* out_path = getenv("CHAIN_MERGE_TEST_OUT")) {
+ out_file = fsbridge::fopen(out_path, "w");
+ if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed");
+ }
+
+ ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions) {
+ TestArgsManager parser;
+ LOCK(parser.cs_args);
+ parser.AddArg("-regtest", "regtest", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ parser.AddArg("-testnet", "testnet", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+
+ auto arg = [](Action action) { return action == ENABLE_TEST ? "-testnet=1" :
+ action == DISABLE_TEST ? "-testnet=0" :
+ action == NEGATE_TEST ? "-notestnet=1" :
+ action == ENABLE_REG ? "-regtest=1" :
+ action == DISABLE_REG ? "-regtest=0" :
+ action == NEGATE_REG ? "-noregtest=1" : nullptr; };
+
+ std::string desc;
+ std::vector<const char*> argv = {"ignored"};
+ for (Action action : arg_actions) {
+ const char* argstr = arg(action);
+ if (!argstr) break;
+ argv.push_back(argstr);
+ desc += " ";
+ desc += argv.back();
+ }
+ std::string error;
+ BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
+ BOOST_CHECK_EQUAL(error, "");
+
+ std::string conf;
+ for (Action action : conf_actions) {
+ const char* argstr = arg(action);
+ if (!argstr) break;
+ desc += " ";
+ desc += argstr + 1;
+ conf += argstr + 1;
+ conf += "\n";
+ }
+ std::istringstream conf_stream(conf);
+ BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
+ BOOST_CHECK_EQUAL(error, "");
+
+ desc += " || ";
+ try {
+ desc += parser.GetChainName();
+ } catch (const std::runtime_error& e) {
+ desc += "error: ";
+ desc += e.what();
+ }
+ desc += "\n";
+
+ out_sha.Write(MakeUCharSpan(desc));
+ if (out_file) {
+ BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
+ }
+ });
+
+ if (out_file) {
+ if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed");
+ out_file = nullptr;
+ }
+
+ unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE];
+ out_sha.Finalize(out_sha_bytes);
+ std::string out_sha_hex = HexStr(out_sha_bytes);
+
+ // If check below fails, should manually dump the results with:
+ //
+ // CHAIN_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ChainMerge
+ //
+ // And verify diff against previous results to make sure the changes are expected.
+ //
+ // Results file is formatted like:
+ //
+ // <input> || <output>
+ BOOST_CHECK_EQUAL(out_sha_hex, "f263493e300023b6509963887444c41386f44b63bc30047eb8402e8c1144854c");
+}
+
+BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
+{
+ // Test writing setting.
+ TestArgsManager args1;
+ args1.ForceSetArg("-datadir", fs::PathToString(m_path_root));
+ args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; });
+ args1.WriteSettingsFile();
+
+ // Test reading setting.
+ TestArgsManager args2;
+ args2.ForceSetArg("-datadir", fs::PathToString(m_path_root));
+ args2.ReadSettingsFile();
+ args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
+
+ // Test error logging, and remove previously written setting.
+ {
+ ASSERT_DEBUG_LOG("Failed renaming settings file");
+ fs::remove(args1.GetDataDirBase() / "settings.json");
+ fs::create_directory(args1.GetDataDirBase() / "settings.json");
+ args2.WriteSettingsFile();
+ fs::remove(args1.GetDataDirBase() / "settings.json");
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp
index a923d38467..6a37b7d83b 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/banman_tests.cpp b/src/test/banman_tests.cpp
index ecf60834ce..cebe3629d4 100644
--- a/src/test/banman_tests.cpp
+++ b/src/test/banman_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
index c6109dfeb0..4617beecd9 100644
--- a/src/test/base32_tests.cpp
+++ b/src/test/base32_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 249f89ae2f..7f3ca6bf93 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -1,10 +1,12 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <test/data/base58_encode_decode.json.h>
#include <base58.h>
+#include <test/util/json.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <util/strencodings.h>
#include <util/vector.h>
@@ -16,8 +18,6 @@
using namespace std::literals;
-UniValue read_json(const std::string& jsondata);
-
BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup)
// Goal: test low-level base58 encoding functionality
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index 54a02c6bf8..6462aa82fb 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 75b29ae0aa..fe3d8995e9 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2021 The Bitcoin Core developers
+// Copyright (c) 2013-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp
index 0157e25071..b590467a43 100644
--- a/src/test/blockchain_tests.cpp
+++ b/src/test/blockchain_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2020 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 78b82b9b20..4348a20886 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,6 +7,8 @@
#include <consensus/merkle.h>
#include <pow.h>
#include <streams.h>
+#include <test/util/random.h>
+#include <test/util/txmempool.h>
#include <test/util/setup_common.h>
@@ -309,7 +311,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
req1.indexes[2] = 3;
req1.indexes[3] = 4;
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << req1;
BlockTransactionsRequest req2;
@@ -329,7 +331,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) {
req0.blockhash = InsecureRand256();
req0.indexes.resize(1);
req0.indexes[0] = 0xffff;
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << req0;
BlockTransactionsRequest req1;
@@ -349,7 +351,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) {
req0.indexes[0] = 0x7000;
req0.indexes[1] = 0x10000 - 0x7000 - 2;
req0.indexes[2] = 0;
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << req0.blockhash;
WriteCompactSize(stream, req0.indexes.size());
WriteCompactSize(stream, req0.indexes[0]);
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index 2798e998af..a572bb02b9 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp
index 0831188327..9388b4c96a 100644
--- a/src/test/blockfilter_tests.cpp
+++ b/src/test/blockfilter_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -110,7 +110,7 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
// Test serialization/unserialization.
BlockFilter block_filter2;
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << block_filter;
stream >> block_filter2;
diff --git a/src/test/blockmanager_tests.cpp b/src/test/blockmanager_tests.cpp
new file mode 100644
index 0000000000..2118f476cd
--- /dev/null
+++ b/src/test/blockmanager_tests.cpp
@@ -0,0 +1,85 @@
+// Copyright (c) 2022 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 <chainparams.h>
+#include <node/blockstorage.h>
+#include <node/context.h>
+#include <validation.h>
+
+#include <boost/test/unit_test.hpp>
+#include <test/util/setup_common.h>
+
+using node::BlockManager;
+using node::BLOCK_SERIALIZATION_HEADER_SIZE;
+using node::MAX_BLOCKFILE_SIZE;
+using node::OpenBlockFile;
+
+// use BasicTestingSetup here for the data directory configuration, setup, and cleanup
+BOOST_FIXTURE_TEST_SUITE(blockmanager_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
+{
+ const auto params {CreateChainParams(ArgsManager{}, CBaseChainParams::MAIN)};
+ BlockManager blockman{{}};
+ CChain chain {};
+ // simulate adding a genesis block normally
+ BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, *params, nullptr).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
+ // simulate what happens during reindex
+ // simulate a well-formed genesis block being found at offset 8 in the blk00000.dat file
+ // the block is found at offset 8 because there is an 8 byte serialization header
+ // consisting of 4 magic bytes + 4 length bytes before each block in a well-formed blk file.
+ FlatFilePos pos{0, BLOCK_SERIALIZATION_HEADER_SIZE};
+ BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, *params, &pos).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
+ // now simulate what happens after reindex for the first new block processed
+ // the actual block contents don't matter, just that it's a block.
+ // verify that the write position is at offset 0x12d.
+ // this is a check to make sure that https://github.com/bitcoin/bitcoin/issues/21379 does not recur
+ // 8 bytes (for serialization header) + 285 (for serialized genesis block) = 293
+ // add another 8 bytes for the second block's serialization header and we get 293 + 8 = 301
+ FlatFilePos actual{blockman.SaveBlockToDisk(params->GenesisBlock(), 1, chain, *params, nullptr)};
+ BOOST_CHECK_EQUAL(actual.nPos, BLOCK_SERIALIZATION_HEADER_SIZE + ::GetSerializeSize(params->GenesisBlock(), CLIENT_VERSION) + BLOCK_SERIALIZATION_HEADER_SIZE);
+}
+
+BOOST_FIXTURE_TEST_CASE(blockmanager_scan_unlink_already_pruned_files, TestChain100Setup)
+{
+ // Cap last block file size, and mine new block in a new block file.
+ const auto& chainman = Assert(m_node.chainman);
+ auto& blockman = chainman->m_blockman;
+ const CBlockIndex* old_tip{WITH_LOCK(chainman->GetMutex(), return chainman->ActiveChain().Tip())};
+ WITH_LOCK(chainman->GetMutex(), blockman.GetBlockFileInfo(old_tip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE);
+ CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+
+ // Prune the older block file, but don't unlink it
+ int file_number;
+ {
+ LOCK(chainman->GetMutex());
+ file_number = old_tip->GetBlockPos().nFile;
+ blockman.PruneOneBlockFile(file_number);
+ }
+
+ const FlatFilePos pos(file_number, 0);
+
+ // Check that the file is not unlinked after ScanAndUnlinkAlreadyPrunedFiles
+ // if m_have_pruned is not yet set
+ WITH_LOCK(chainman->GetMutex(), blockman.ScanAndUnlinkAlreadyPrunedFiles());
+ BOOST_CHECK(!AutoFile(OpenBlockFile(pos, true)).IsNull());
+
+ // Check that the file is unlinked after ScanAndUnlinkAlreadyPrunedFiles
+ // once m_have_pruned is set
+ blockman.m_have_pruned = true;
+ WITH_LOCK(chainman->GetMutex(), blockman.ScanAndUnlinkAlreadyPrunedFiles());
+ BOOST_CHECK(AutoFile(OpenBlockFile(pos, true)).IsNull());
+
+ // Check that calling with already pruned files doesn't cause an error
+ WITH_LOCK(chainman->GetMutex(), blockman.ScanAndUnlinkAlreadyPrunedFiles());
+
+ // Check that the new tip file has not been removed
+ const CBlockIndex* new_tip{WITH_LOCK(chainman->GetMutex(), return chainman->ActiveChain().Tip())};
+ BOOST_CHECK_NE(old_tip, new_tip);
+ const int new_file_number{WITH_LOCK(chainman->GetMutex(), return new_tip->GetBlockPos().nFile)};
+ const FlatFilePos new_pos(new_file_number, 0);
+ BOOST_CHECK(!AutoFile(OpenBlockFile(new_pos, true)).IsNull());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 35c4108caa..5d4c5eea0e 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,6 +12,7 @@
#include <random.h>
#include <serialize.h>
#include <streams.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <uint256.h>
#include <util/strencodings.h>
@@ -39,7 +40,7 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize)
filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5"));
BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "Bloom filter doesn't contain just-inserted object (3)!");
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << filter;
std::vector<uint8_t> expected = ParseHex("03614e9b050000000000000001");
@@ -66,7 +67,7 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak)
filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5"));
BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "Bloom filter doesn't contain just-inserted object (3)!");
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << filter;
std::vector<uint8_t> expected = ParseHex("03ce4299050000000100008001");
@@ -87,7 +88,7 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
uint160 hash = pubkey.GetID();
filter.insert(hash);
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream stream{};
stream << filter;
std::vector<unsigned char> expected = ParseHex("038fc16b080000000000000001");
@@ -340,7 +341,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize)
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
- CDataStream merkleStream(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream merkleStream{};
merkleStream << merkleBlock;
std::vector<uint8_t> expected = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101");
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 875522d744..135f107159 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 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 <checkqueue.h>
#include <sync.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <util/system.h>
#include <util/time.h>
@@ -194,7 +195,7 @@ static void Correct_Queue_range(std::vector<size_t> range)
BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero)
{
std::vector<size_t> range;
- range.push_back((size_t)0);
+ range.push_back(size_t{0});
Correct_Queue_range(range);
}
/** Test that 1 check is correct
@@ -202,7 +203,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero)
BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One)
{
std::vector<size_t> range;
- range.push_back((size_t)1);
+ range.push_back(size_t{1});
Correct_Queue_range(range);
}
/** Test that MAX check is correct
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index b333a9f72d..e082800fc3 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2021 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,6 +6,7 @@
#include <coins.h>
#include <script/standard.h>
#include <streams.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <txdb.h>
#include <uint256.h>
@@ -53,9 +54,9 @@ public:
uint256 GetBestBlock() const override { return hashBestBlock_; }
- bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock) override
+ bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock, bool erase = true) override
{
- for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {
+ for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = erase ? mapCoins.erase(it) : std::next(it)) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
// Same optimization used in CCoinsViewDB is to only write dirty entries.
map_[it->first] = it->second.coin;
@@ -64,7 +65,6 @@ public:
map_.erase(it->first);
}
}
- mapCoins.erase(it++);
}
if (!hashBlock.IsNull())
hashBestBlock_ = hashBlock;
@@ -126,13 +126,14 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
bool found_an_entry = false;
bool missed_an_entry = false;
bool uncached_an_entry = false;
+ bool flushed_without_erase = false;
// A simple map to track what we expect the cache stack to represent.
std::map<COutPoint, Coin> result;
// The cache stack.
- std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top.
- stack.push_back(new CCoinsViewCacheTest(base)); // Start with one cache.
+ std::vector<std::unique_ptr<CCoinsViewCacheTest>> stack; // A stack of CCoinsViewCaches on top.
+ stack.push_back(std::make_unique<CCoinsViewCacheTest>(base)); // Start with one cache.
// Use a limited set of random transaction ids, so we do test overwriting entries.
std::vector<uint256> txids;
@@ -154,9 +155,16 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
bool test_havecoin_after = InsecureRandBits(2) == 0;
bool result_havecoin = test_havecoin_before ? stack.back()->HaveCoin(COutPoint(txid, 0)) : false;
- const Coin& entry = (InsecureRandRange(500) == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));
+
+ // Infrequently, test usage of AccessByTxid instead of AccessCoin - the
+ // former just delegates to the latter and returns the first unspent in a txn.
+ const Coin& entry = (InsecureRandRange(500) == 0) ?
+ AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));
BOOST_CHECK(coin == entry);
- BOOST_CHECK(!test_havecoin_before || result_havecoin == !entry.IsSpent());
+
+ if (test_havecoin_before) {
+ BOOST_CHECK(result_havecoin == !entry.IsSpent());
+ }
if (test_havecoin_after) {
bool ret = stack.back()->HaveCoin(COutPoint(txid, 0));
@@ -165,26 +173,31 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
if (InsecureRandRange(5) == 0 || coin.IsSpent()) {
Coin newcoin;
- newcoin.out.nValue = InsecureRand32();
+ newcoin.out.nValue = InsecureRandMoneyAmount();
newcoin.nHeight = 1;
+
+ // Infrequently test adding unspendable coins.
if (InsecureRandRange(16) == 0 && coin.IsSpent()) {
newcoin.out.scriptPubKey.assign(1 + InsecureRandBits(6), OP_RETURN);
BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable());
added_an_unspendable_entry = true;
} else {
- newcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0); // Random sizes so we can test memory usage accounting
+ // Random sizes so we can test memory usage accounting
+ newcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0);
(coin.IsSpent() ? added_an_entry : updated_an_entry) = true;
coin = newcoin;
}
- stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), !coin.IsSpent() || InsecureRand32() & 1);
+ bool is_overwrite = !coin.IsSpent() || InsecureRand32() & 1;
+ stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), is_overwrite);
} else {
+ // Spend the coin.
removed_an_entry = true;
coin.Clear();
BOOST_CHECK(stack.back()->SpendCoin(COutPoint(txid, 0)));
}
}
- // One every 10 iterations, remove a random entry from the cache
+ // Once every 10 iterations, remove a random entry from the cache
if (InsecureRandRange(10) == 0) {
COutPoint out(txids[InsecureRand32() % txids.size()], 0);
int cacheid = InsecureRand32() % stack.size();
@@ -206,7 +219,7 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
found_an_entry = true;
}
}
- for (const CCoinsViewCacheTest *test : stack) {
+ for (const auto& test : stack) {
test->SelfTest();
}
}
@@ -216,7 +229,9 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
if (stack.size() > 1 && InsecureRandBool() == 0) {
unsigned int flushIndex = InsecureRandRange(stack.size() - 1);
if (fake_best_block) stack[flushIndex]->SetBestBlock(InsecureRand256());
- BOOST_CHECK(stack[flushIndex]->Flush());
+ bool should_erase = InsecureRandRange(4) < 3;
+ BOOST_CHECK(should_erase ? stack[flushIndex]->Flush() : stack[flushIndex]->Sync());
+ flushed_without_erase |= !should_erase;
}
}
if (InsecureRandRange(100) == 0) {
@@ -224,19 +239,20 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
if (stack.size() > 0 && InsecureRandBool() == 0) {
//Remove the top cache
if (fake_best_block) stack.back()->SetBestBlock(InsecureRand256());
- BOOST_CHECK(stack.back()->Flush());
- delete stack.back();
+ bool should_erase = InsecureRandRange(4) < 3;
+ BOOST_CHECK(should_erase ? stack.back()->Flush() : stack.back()->Sync());
+ flushed_without_erase |= !should_erase;
stack.pop_back();
}
if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) {
//Add a new cache
CCoinsView* tip = base;
if (stack.size() > 0) {
- tip = stack.back();
+ tip = stack.back().get();
} else {
removed_all_caches = true;
}
- stack.push_back(new CCoinsViewCacheTest(tip));
+ stack.push_back(std::make_unique<CCoinsViewCacheTest>(tip));
if (stack.size() == 4) {
reached_4_caches = true;
}
@@ -244,12 +260,6 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
}
}
- // Clean up the stack.
- while (stack.size() > 0) {
- delete stack.back();
- stack.pop_back();
- }
-
// Verify coverage.
BOOST_CHECK(removed_all_caches);
BOOST_CHECK(reached_4_caches);
@@ -260,6 +270,7 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
BOOST_CHECK(found_an_entry);
BOOST_CHECK(missed_an_entry);
BOOST_CHECK(uncached_an_entry);
+ BOOST_CHECK(flushed_without_erase);
}
// Run the above simulation for multiple base types.
@@ -268,7 +279,7 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
CCoinsViewTest base;
SimulationTest(&base, false);
- CCoinsViewDB db_base{"test", /*nCacheSize=*/1 << 23, /*fMemory=*/true, /*fWipe=*/false};
+ CCoinsViewDB db_base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}};
SimulationTest(&db_base, true);
}
@@ -304,8 +315,8 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// The cache stack.
CCoinsViewTest base; // A CCoinsViewTest at the bottom.
- std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top.
- stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.
+ std::vector<std::unique_ptr<CCoinsViewCacheTest>> stack; // A stack of CCoinsViewCaches on top.
+ stack.push_back(std::make_unique<CCoinsViewCacheTest>(&base)); // Start with one cache.
// Track the txids we've used in various sets
std::set<COutPoint> coinbase_coins;
@@ -470,25 +481,18 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// Every 100 iterations, change the cache stack.
if (stack.size() > 0 && InsecureRandBool() == 0) {
BOOST_CHECK(stack.back()->Flush());
- delete stack.back();
stack.pop_back();
}
if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) {
CCoinsView* tip = &base;
if (stack.size() > 0) {
- tip = stack.back();
+ tip = stack.back().get();
}
- stack.push_back(new CCoinsViewCacheTest(tip));
+ stack.push_back(std::make_unique<CCoinsViewCacheTest>(tip));
}
}
}
- // Clean up the stack.
- while (stack.size() > 0) {
- delete stack.back();
- stack.pop_back();
- }
-
// Verify coverage.
BOOST_CHECK(spent_a_duplicate_coinbase);
@@ -498,7 +502,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
BOOST_AUTO_TEST_CASE(ccoins_serialization)
{
// Good example
- CDataStream ss1(ParseHex("97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"), SER_DISK, CLIENT_VERSION);
+ DataStream ss1{ParseHex("97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35")};
Coin cc1;
ss1 >> cc1;
BOOST_CHECK_EQUAL(cc1.fCoinBase, false);
@@ -507,7 +511,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))))));
// Good example
- CDataStream ss2(ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"), SER_DISK, CLIENT_VERSION);
+ DataStream ss2{ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4")};
Coin cc2;
ss2 >> cc2;
BOOST_CHECK_EQUAL(cc2.fCoinBase, true);
@@ -516,7 +520,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))))));
// Smallest possible example
- CDataStream ss3(ParseHex("000006"), SER_DISK, CLIENT_VERSION);
+ DataStream ss3{ParseHex("000006")};
Coin cc3;
ss3 >> cc3;
BOOST_CHECK_EQUAL(cc3.fCoinBase, false);
@@ -525,7 +529,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
BOOST_CHECK_EQUAL(cc3.out.scriptPubKey.size(), 0U);
// scriptPubKey that ends beyond the end of the stream
- CDataStream ss4(ParseHex("000007"), SER_DISK, CLIENT_VERSION);
+ DataStream ss4{ParseHex("000007")};
try {
Coin cc4;
ss4 >> cc4;
@@ -534,11 +538,11 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
}
// Very large scriptPubKey (3*10^9 bytes) past the end of the stream
- CDataStream tmp(SER_DISK, CLIENT_VERSION);
+ DataStream tmp{};
uint64_t x = 3000000000ULL;
tmp << VARINT(x);
BOOST_CHECK_EQUAL(HexStr(tmp), "8a95c0bb00");
- CDataStream ss5(ParseHex("00008a95c0bb00"), SER_DISK, CLIENT_VERSION);
+ DataStream ss5{ParseHex("00008a95c0bb00")};
try {
Coin cc5;
ss5 >> cc5;
@@ -589,9 +593,9 @@ static size_t InsertCoinsMapEntry(CCoinsMap& map, CAmount value, char flags)
return inserted.first->second.coin.DynamicMemoryUsage();
}
-void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags)
+void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags, const COutPoint& outp = OUTPOINT)
{
- auto it = map.find(OUTPOINT);
+ auto it = map.find(outp);
if (it == map.end()) {
value = ABSENT;
flags = NO_ENTRY;
@@ -877,4 +881,199 @@ BOOST_AUTO_TEST_CASE(ccoins_write)
CheckWriteCoins(parent_value, child_value, parent_value, parent_flags, child_flags, parent_flags);
}
+
+Coin MakeCoin()
+{
+ Coin coin;
+ coin.out.nValue = InsecureRand32();
+ coin.nHeight = InsecureRandRange(4096);
+ coin.fCoinBase = 0;
+ return coin;
+}
+
+
+//! For CCoinsViewCache instances backed by either another cache instance or
+//! leveldb, test cache behavior and flag state (DIRTY/FRESH) by
+//!
+//! 1. Adding a random coin to the child-most cache,
+//! 2. Flushing all caches (without erasing),
+//! 3. Ensure the entry still exists in the cache and has been written to parent,
+//! 4. (if `do_erasing_flush`) Flushing the caches again (with erasing),
+//! 5. (if `do_erasing_flush`) Ensure the entry has been written to the parent and is no longer in the cache,
+//! 6. Spend the coin, ensure it no longer exists in the parent.
+//!
+void TestFlushBehavior(
+ CCoinsViewCacheTest* view,
+ CCoinsViewDB& base,
+ std::vector<std::unique_ptr<CCoinsViewCacheTest>>& all_caches,
+ bool do_erasing_flush)
+{
+ CAmount value;
+ char flags;
+ size_t cache_usage;
+
+ auto flush_all = [&all_caches](bool erase) {
+ // Flush in reverse order to ensure that flushes happen from children up.
+ for (auto i = all_caches.rbegin(); i != all_caches.rend(); ++i) {
+ auto& cache = *i;
+ // hashBlock must be filled before flushing to disk; value is
+ // unimportant here. This is normally done during connect/disconnect block.
+ cache->SetBestBlock(InsecureRand256());
+ erase ? cache->Flush() : cache->Sync();
+ }
+ };
+
+ uint256 txid = InsecureRand256();
+ COutPoint outp = COutPoint(txid, 0);
+ Coin coin = MakeCoin();
+ // Ensure the coins views haven't seen this coin before.
+ BOOST_CHECK(!base.HaveCoin(outp));
+ BOOST_CHECK(!view->HaveCoin(outp));
+
+ // --- 1. Adding a random coin to the child cache
+ //
+ view->AddCoin(outp, Coin(coin), false);
+
+ cache_usage = view->DynamicMemoryUsage();
+ // `base` shouldn't have coin (no flush yet) but `view` should have cached it.
+ BOOST_CHECK(!base.HaveCoin(outp));
+ BOOST_CHECK(view->HaveCoin(outp));
+
+ GetCoinsMapEntry(view->map(), value, flags, outp);
+ BOOST_CHECK_EQUAL(value, coin.out.nValue);
+ BOOST_CHECK_EQUAL(flags, DIRTY|FRESH);
+
+ // --- 2. Flushing all caches (without erasing)
+ //
+ flush_all(/*erase=*/ false);
+
+ // CoinsMap usage should be unchanged since we didn't erase anything.
+ BOOST_CHECK_EQUAL(cache_usage, view->DynamicMemoryUsage());
+
+ // --- 3. Ensuring the entry still exists in the cache and has been written to parent
+ //
+ GetCoinsMapEntry(view->map(), value, flags, outp);
+ BOOST_CHECK_EQUAL(value, coin.out.nValue);
+ BOOST_CHECK_EQUAL(flags, 0); // Flags should have been wiped.
+
+ // Both views should now have the coin.
+ BOOST_CHECK(base.HaveCoin(outp));
+ BOOST_CHECK(view->HaveCoin(outp));
+
+ if (do_erasing_flush) {
+ // --- 4. Flushing the caches again (with erasing)
+ //
+ flush_all(/*erase=*/ true);
+
+ // Memory usage should have gone down.
+ BOOST_CHECK(view->DynamicMemoryUsage() < cache_usage);
+
+ // --- 5. Ensuring the entry is no longer in the cache
+ //
+ GetCoinsMapEntry(view->map(), value, flags, outp);
+ BOOST_CHECK_EQUAL(value, ABSENT);
+ BOOST_CHECK_EQUAL(flags, NO_ENTRY);
+
+ view->AccessCoin(outp);
+ GetCoinsMapEntry(view->map(), value, flags, outp);
+ BOOST_CHECK_EQUAL(value, coin.out.nValue);
+ BOOST_CHECK_EQUAL(flags, 0);
+ }
+
+ // Can't overwrite an entry without specifying that an overwrite is
+ // expected.
+ BOOST_CHECK_THROW(
+ view->AddCoin(outp, Coin(coin), /*possible_overwrite=*/ false),
+ std::logic_error);
+
+ // --- 6. Spend the coin.
+ //
+ BOOST_CHECK(view->SpendCoin(outp));
+
+ // The coin should be in the cache, but spent and marked dirty.
+ GetCoinsMapEntry(view->map(), value, flags, outp);
+ BOOST_CHECK_EQUAL(value, SPENT);
+ BOOST_CHECK_EQUAL(flags, DIRTY);
+ BOOST_CHECK(!view->HaveCoin(outp)); // Coin should be considered spent in `view`.
+ BOOST_CHECK(base.HaveCoin(outp)); // But coin should still be unspent in `base`.
+
+ flush_all(/*erase=*/ false);
+
+ // Coin should be considered spent in both views.
+ BOOST_CHECK(!view->HaveCoin(outp));
+ BOOST_CHECK(!base.HaveCoin(outp));
+
+ // Spent coin should not be spendable.
+ BOOST_CHECK(!view->SpendCoin(outp));
+
+ // --- Bonus check: ensure that a coin added to the base view via one cache
+ // can be spent by another cache which has never seen it.
+ //
+ txid = InsecureRand256();
+ outp = COutPoint(txid, 0);
+ coin = MakeCoin();
+ BOOST_CHECK(!base.HaveCoin(outp));
+ BOOST_CHECK(!all_caches[0]->HaveCoin(outp));
+ BOOST_CHECK(!all_caches[1]->HaveCoin(outp));
+
+ all_caches[0]->AddCoin(outp, std::move(coin), false);
+ all_caches[0]->Sync();
+ BOOST_CHECK(base.HaveCoin(outp));
+ BOOST_CHECK(all_caches[0]->HaveCoin(outp));
+ BOOST_CHECK(!all_caches[1]->HaveCoinInCache(outp));
+
+ BOOST_CHECK(all_caches[1]->SpendCoin(outp));
+ flush_all(/*erase=*/ false);
+ BOOST_CHECK(!base.HaveCoin(outp));
+ BOOST_CHECK(!all_caches[0]->HaveCoin(outp));
+ BOOST_CHECK(!all_caches[1]->HaveCoin(outp));
+
+ flush_all(/*erase=*/ true); // Erase all cache content.
+
+ // --- Bonus check 2: ensure that a FRESH, spent coin is deleted by Sync()
+ //
+ txid = InsecureRand256();
+ outp = COutPoint(txid, 0);
+ coin = MakeCoin();
+ CAmount coin_val = coin.out.nValue;
+ BOOST_CHECK(!base.HaveCoin(outp));
+ BOOST_CHECK(!all_caches[0]->HaveCoin(outp));
+ BOOST_CHECK(!all_caches[1]->HaveCoin(outp));
+
+ // Add and spend from same cache without flushing.
+ all_caches[0]->AddCoin(outp, std::move(coin), false);
+
+ // Coin should be FRESH in the cache.
+ GetCoinsMapEntry(all_caches[0]->map(), value, flags, outp);
+ BOOST_CHECK_EQUAL(value, coin_val);
+ BOOST_CHECK_EQUAL(flags, DIRTY|FRESH);
+
+ // Base shouldn't have seen coin.
+ BOOST_CHECK(!base.HaveCoin(outp));
+
+ BOOST_CHECK(all_caches[0]->SpendCoin(outp));
+ all_caches[0]->Sync();
+
+ // Ensure there is no sign of the coin after spend/flush.
+ GetCoinsMapEntry(all_caches[0]->map(), value, flags, outp);
+ BOOST_CHECK_EQUAL(value, ABSENT);
+ BOOST_CHECK_EQUAL(flags, NO_ENTRY);
+ BOOST_CHECK(!all_caches[0]->HaveCoinInCache(outp));
+ BOOST_CHECK(!base.HaveCoin(outp));
+}
+
+BOOST_AUTO_TEST_CASE(ccoins_flush_behavior)
+{
+ // Create two in-memory caches atop a leveldb view.
+ CCoinsViewDB base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}};
+ std::vector<std::unique_ptr<CCoinsViewCacheTest>> caches;
+ caches.push_back(std::make_unique<CCoinsViewCacheTest>(&base));
+ caches.push_back(std::make_unique<CCoinsViewCacheTest>(caches.back().get()));
+
+ for (const auto& view : caches) {
+ TestFlushBehavior(view.get(), base, caches, /*do_erasing_flush=*/false);
+ TestFlushBehavior(view.get(), base, caches, /*do_erasing_flush=*/true);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp
index 2a6a777cfe..503a58076b 100644
--- a/src/test/coinstatsindex_tests.cpp
+++ b/src/test/coinstatsindex_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -76,10 +76,16 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
BOOST_CHECK(block_index != new_block_index);
+ // It is not safe to stop and destroy the index until it finishes handling
+ // the last BlockConnected notification. The BlockUntilSyncedToCurrentChain()
+ // call above is sufficient to ensure this, but the
+ // SyncWithValidationInterfaceQueue() call below is also needed to ensure
+ // TSAN always sees the test thread waiting for the notification thread, and
+ // avoid potential false positive reports.
+ SyncWithValidationInterfaceQueue();
+
// Shutdown sequence (c.f. Shutdown() in init.cpp)
coin_stats_index.Stop();
-
- // Rest of shutdown sequence and destructors happen in ~TestingSetup()
}
// Test shutdown between BlockConnected and ChainStateFlushed notifications,
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 6148edf115..e4e8596a5d 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -17,6 +17,7 @@
#include <crypto/muhash.h>
#include <random.h>
#include <streams.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <util/strencodings.h>
@@ -133,14 +134,14 @@ static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, b
static void TestChaCha20(const std::string &hex_message, const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout)
{
std::vector<unsigned char> key = ParseHex(hexkey);
+ assert(key.size() == 32);
std::vector<unsigned char> m = ParseHex(hex_message);
- ChaCha20 rng(key.data(), key.size());
+ ChaCha20 rng(key.data());
rng.SetIV(nonce);
- rng.Seek(seek);
- std::vector<unsigned char> out = ParseHex(hexout);
+ rng.Seek64(seek);
std::vector<unsigned char> outres;
- outres.resize(out.size());
- assert(hex_message.empty() || m.size() == out.size());
+ outres.resize(hexout.size() / 2);
+ assert(hex_message.empty() || m.size() * 2 == hexout.size());
// perform the ChaCha20 round(s), if message is provided it will output the encrypted ciphertext otherwise the keystream
if (!hex_message.empty()) {
@@ -148,17 +149,38 @@ static void TestChaCha20(const std::string &hex_message, const std::string &hexk
} else {
rng.Keystream(outres.data(), outres.size());
}
- BOOST_CHECK(out == outres);
+ BOOST_CHECK_EQUAL(hexout, HexStr(outres));
if (!hex_message.empty()) {
// Manually XOR with the keystream and compare the output
rng.SetIV(nonce);
- rng.Seek(seek);
+ rng.Seek64(seek);
std::vector<unsigned char> only_keystream(outres.size());
rng.Keystream(only_keystream.data(), only_keystream.size());
for (size_t i = 0; i != m.size(); i++) {
outres[i] = m[i] ^ only_keystream[i];
}
- BOOST_CHECK(out == outres);
+ BOOST_CHECK_EQUAL(hexout, HexStr(outres));
+ }
+
+ // Repeat 10x, but fragmented into 3 chunks, to exercise the ChaCha20 class's caching.
+ for (int i = 0; i < 10; ++i) {
+ size_t lens[3];
+ lens[0] = InsecureRandRange(hexout.size() / 2U + 1U);
+ lens[1] = InsecureRandRange(hexout.size() / 2U + 1U - lens[0]);
+ lens[2] = hexout.size() / 2U - lens[0] - lens[1];
+
+ rng.Seek64(seek);
+ outres.assign(hexout.size() / 2U, 0);
+ size_t pos = 0;
+ for (int j = 0; j < 3; ++j) {
+ if (!hex_message.empty()) {
+ rng.Crypt(m.data() + pos, outres.data() + pos, lens[j]);
+ } else {
+ rng.Keystream(outres.data() + pos, lens[j]);
+ }
+ pos += lens[j];
+ }
+ BOOST_CHECK_EQUAL(hexout, HexStr(outres));
}
}
@@ -460,7 +482,88 @@ BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) {
BOOST_AUTO_TEST_CASE(chacha20_testvector)
{
- // Test vector from RFC 7539
+ // RFC 7539/8439 A.1 Test Vector #1:
+ TestChaCha20("",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ 0, 0,
+ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7"
+ "da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586");
+
+ // RFC 7539/8439 A.1 Test Vector #2:
+ TestChaCha20("",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ 0, 1,
+ "9f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed"
+ "29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f");
+
+ // RFC 7539/8439 A.1 Test Vector #3:
+ TestChaCha20("",
+ "0000000000000000000000000000000000000000000000000000000000000001",
+ 0, 1,
+ "3aeb5224ecf849929b9d828db1ced4dd832025e8018b8160b82284f3c949aa5a"
+ "8eca00bbb4a73bdad192b5c42f73f2fd4e273644c8b36125a64addeb006c13a0");
+
+ // RFC 7539/8439 A.1 Test Vector #4:
+ TestChaCha20("",
+ "00ff000000000000000000000000000000000000000000000000000000000000",
+ 0, 2,
+ "72d54dfbf12ec44b362692df94137f328fea8da73990265ec1bbbea1ae9af0ca"
+ "13b25aa26cb4a648cb9b9d1be65b2c0924a66c54d545ec1b7374f4872e99f096");
+
+ // RFC 7539/8439 A.1 Test Vector #5:
+ TestChaCha20("",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ 0x200000000000000, 0,
+ "c2c64d378cd536374ae204b9ef933fcd1a8b2288b3dfa49672ab765b54ee27c7"
+ "8a970e0e955c14f3a88e741b97c286f75f8fc299e8148362fa198a39531bed6d");
+
+ // RFC 7539/8439 A.2 Test Vector #1:
+ TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ 0, 0,
+ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7"
+ "da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586");
+
+ // RFC 7539/8439 A.2 Test Vector #2:
+ TestChaCha20("416e79207375626d697373696f6e20746f20746865204945544620696e74656e"
+ "6465642062792074686520436f6e7472696275746f7220666f72207075626c69"
+ "636174696f6e20617320616c6c206f722070617274206f6620616e2049455446"
+ "20496e7465726e65742d4472616674206f722052464320616e6420616e792073"
+ "746174656d656e74206d6164652077697468696e2074686520636f6e74657874"
+ "206f6620616e204945544620616374697669747920697320636f6e7369646572"
+ "656420616e20224945544620436f6e747269627574696f6e222e205375636820"
+ "73746174656d656e747320696e636c756465206f72616c2073746174656d656e"
+ "747320696e20494554462073657373696f6e732c2061732077656c6c20617320"
+ "7772697474656e20616e6420656c656374726f6e696320636f6d6d756e696361"
+ "74696f6e73206d61646520617420616e792074696d65206f7220706c6163652c"
+ "207768696368206172652061646472657373656420746f",
+ "0000000000000000000000000000000000000000000000000000000000000001",
+ 0x200000000000000, 1,
+ "a3fbf07df3fa2fde4f376ca23e82737041605d9f4f4f57bd8cff2c1d4b7955ec"
+ "2a97948bd3722915c8f3d337f7d370050e9e96d647b7c39f56e031ca5eb6250d"
+ "4042e02785ececfa4b4bb5e8ead0440e20b6e8db09d881a7c6132f420e527950"
+ "42bdfa7773d8a9051447b3291ce1411c680465552aa6c405b7764d5e87bea85a"
+ "d00f8449ed8f72d0d662ab052691ca66424bc86d2df80ea41f43abf937d3259d"
+ "c4b2d0dfb48a6c9139ddd7f76966e928e635553ba76c5c879d7b35d49eb2e62b"
+ "0871cdac638939e25e8a1e0ef9d5280fa8ca328b351c3c765989cbcf3daa8b6c"
+ "cc3aaf9f3979c92b3720fc88dc95ed84a1be059c6499b9fda236e7e818b04b0b"
+ "c39c1e876b193bfe5569753f88128cc08aaa9b63d1a16f80ef2554d7189c411f"
+ "5869ca52c5b83fa36ff216b9c1d30062bebcfd2dc5bce0911934fda79a86f6e6"
+ "98ced759c3ff9b6477338f3da4f9cd8514ea9982ccafb341b2384dd902f3d1ab"
+ "7ac61dd29c6f21ba5b862f3730e37cfdc4fd806c22f221");
+
+ // RFC 7539/8439 A.2 Test Vector #3:
+ TestChaCha20("2754776173206272696c6c69672c20616e642074686520736c6974687920746f"
+ "7665730a446964206779726520616e642067696d626c6520696e207468652077"
+ "6162653a0a416c6c206d696d737920776572652074686520626f726f676f7665"
+ "732c0a416e6420746865206d6f6d65207261746873206f757467726162652e",
+ "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0",
+ 0x200000000000000, 42,
+ "62e6347f95ed87a45ffae7426f27a1df5fb69110044c0d73118effa95b01e5cf"
+ "166d3df2d721caf9b21e5fb14c616871fd84c54f9d65b283196c7fe4f60553eb"
+ "f39c6402c42234e32a356b3e764312a61a5532055716ead6962568f87d3f3f77"
+ "04c6a8d1bcd1bf4d50d6154b6da731b187b58dfd728afa36757a797ac188d1");
// test encryption
TestChaCha20("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756"
@@ -477,27 +580,24 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector)
"224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cb"
"a40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a"
"832c89c167eacd901d7e2bf363");
+}
- // Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7
- TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0, 0,
- "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b"
- "8f41518a11cc387b669b2ee6586");
- TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000001", 0, 0,
- "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d79"
- "2b1c43fea817e9ad275ae546963");
- TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0,
- "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b52770"
- "62eb7a0433e445f41e3");
- TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 1, 0,
- "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc4"
- "97a0b466e7d6bbdb0041b2f586b");
- TestChaCha20("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0,
- "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3b"
- "e59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc1"
- "18be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5"
- "a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5"
- "360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78"
- "fab78c9");
+BOOST_AUTO_TEST_CASE(chacha20_midblock)
+{
+ auto key = ParseHex("0000000000000000000000000000000000000000000000000000000000000000");
+ ChaCha20 c20{key.data()};
+ // get one block of keystream
+ unsigned char block[64];
+ c20.Keystream(block, CHACHA20_ROUND_OUTPUT);
+ unsigned char b1[5], b2[7], b3[52];
+ c20 = ChaCha20{key.data()};
+ c20.Keystream(b1, 5);
+ c20.Keystream(b2, 7);
+ c20.Keystream(b3, 52);
+
+ BOOST_CHECK_EQUAL(0, memcmp(b1, block, 5));
+ BOOST_CHECK_EQUAL(0, memcmp(b2, block + 5, 7));
+ BOOST_CHECK_EQUAL(0, memcmp(b3, block + 12, 52));
}
BOOST_AUTO_TEST_CASE(poly1305_testvector)
@@ -617,7 +717,7 @@ static void TestChaCha20Poly1305AEAD(bool must_succeed, unsigned int expected_aa
ChaCha20Poly1305AEAD aead(aead_K_1.data(), aead_K_1.size(), aead_K_2.data(), aead_K_2.size());
// create a chacha20 instance to compare against
- ChaCha20 cmp_ctx(aead_K_1.data(), 32);
+ ChaCha20 cmp_ctx(aead_K_1.data());
// encipher
bool res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true);
@@ -631,7 +731,7 @@ static void TestChaCha20Poly1305AEAD(bool must_succeed, unsigned int expected_aa
// manually construct the AAD keystream
cmp_ctx.SetIV(seqnr_aad);
- cmp_ctx.Seek(0);
+ cmp_ctx.Seek64(0);
cmp_ctx.Keystream(cmp_ctx_buffer.data(), 64);
BOOST_CHECK(memcmp(expected_aad_keystream.data(), cmp_ctx_buffer.data(), expected_aad_keystream.size()) == 0);
// crypt the 3 length bytes and compare the length
@@ -659,7 +759,7 @@ static void TestChaCha20Poly1305AEAD(bool must_succeed, unsigned int expected_aa
}
// set nonce and block counter, output the keystream
cmp_ctx.SetIV(seqnr_aad);
- cmp_ctx.Seek(0);
+ cmp_ctx.Seek64(0);
cmp_ctx.Keystream(cmp_ctx_buffer.data(), 64);
// crypt the 3 length bytes and compare the length
@@ -723,14 +823,14 @@ BOOST_AUTO_TEST_CASE(countbits_tests)
// Check handling of zero.
BOOST_CHECK_EQUAL(CountBits(0), 0U);
} else if (i < 10) {
- for (uint64_t j = (uint64_t)1 << (i - 1); (j >> i) == 0; ++j) {
+ for (uint64_t j = uint64_t{1} << (i - 1); (j >> i) == 0; ++j) {
// Exhaustively test up to 10 bits
BOOST_CHECK_EQUAL(CountBits(j), i);
}
} else {
for (int k = 0; k < 1000; k++) {
// Randomly test 1000 samples of each length above 10 bits.
- uint64_t j = ((uint64_t)1) << (i - 1) | ctx.randbits(i - 1);
+ uint64_t j = (uint64_t{1}) << (i - 1) | ctx.randbits(i - 1);
BOOST_CHECK_EQUAL(CountBits(j), i);
}
}
@@ -925,7 +1025,7 @@ BOOST_AUTO_TEST_CASE(muhash_tests)
// Test MuHash3072 serialization
MuHash3072 serchk = FromInt(1); serchk *= FromInt(2);
std::string ser_exp = "1fa093295ea30a6a3acdc7b3f770fa538eff537528e990e2910e40bbcfd7f6696b1256901929094694b56316de342f593303dd12ac43e06dce1be1ff8301c845beb15468fff0ef002dbf80c29f26e6452bccc91b5cb9437ad410d2a67ea847887fa3c6a6553309946880fe20db2c73fe0641adbd4e86edfee0d9f8cd0ee1230898873dc13ed8ddcaf045c80faa082774279007a2253f8922ee3ef361d378a6af3ddaf180b190ac97e556888c36b3d1fb1c85aab9ccd46e3deaeb7b7cf5db067a7e9ff86b658cf3acd6662bbcce37232daa753c48b794356c020090c831a8304416e2aa7ad633c0ddb2f11be1be316a81be7f7e472071c042cb68faef549c221ebff209273638b741aba5a81675c45a5fa92fea4ca821d7a324cb1e1a2ccd3b76c4228ec8066dad2a5df6e1bd0de45c7dd5de8070bdb46db6c554cf9aefc9b7b2bbf9f75b1864d9f95005314593905c0109b71f703d49944ae94477b51dac10a816bb6d1c700bafabc8bd86fac8df24be519a2f2836b16392e18036cb13e48c5c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- CDataStream ss_chk(SER_DISK, PROTOCOL_VERSION);
+ DataStream ss_chk{};
ss_chk << serchk;
BOOST_CHECK_EQUAL(ser_exp, HexStr(ss_chk.str()));
@@ -938,7 +1038,7 @@ BOOST_AUTO_TEST_CASE(muhash_tests)
BOOST_CHECK_EQUAL(HexStr(out), HexStr(out3));
// Test MuHash3072 overflow, meaning the internal data is larger than the modulus.
- CDataStream ss_max(ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), SER_DISK, PROTOCOL_VERSION);
+ DataStream ss_max{ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")};
MuHash3072 overflowchk;
ss_max >> overflowchk;
diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp
index c7c34cc8c9..eafbcf5681 100644
--- a/src/test/cuckoocache_tests.cpp
+++ b/src/test/cuckoocache_tests.cpp
@@ -1,9 +1,11 @@
// Copyright (c) 2012-2021 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 <cuckoocache.h>
#include <random.h>
#include <script/sigcache.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index ab4c587c46..723a1ceee3 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -1,10 +1,12 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 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 <dbwrapper.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <uint256.h>
+#include <util/string.h>
#include <memory>
@@ -27,7 +29,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
- CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
+ CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate});
uint8_t key{'k'};
uint256 in = InsecureRand256();
uint256 res;
@@ -46,7 +48,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data)
// Perform tests both obfuscated and non-obfuscated.
for (bool obfuscate : {false, true}) {
fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false");
- CDBWrapper dbw(ph, (1 << 20), false, true, obfuscate);
+ CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = false, .wipe_data = true, .obfuscate = obfuscate});
uint256 res;
uint32_t res_uint_32;
@@ -127,7 +129,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false");
- CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
+ CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate});
uint8_t key{'i'};
uint256 in = InsecureRand256();
@@ -163,7 +165,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
- CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
+ CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate});
// The two keys are intentionally chosen for ordering
uint8_t key{'j'};
@@ -206,7 +208,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
fs::create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false);
+ std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(DBParams{.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = false});
uint8_t key{'k'};
uint256 in = InsecureRand256();
uint256 res;
@@ -219,7 +221,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
dbw.reset();
// Now, set up another wrapper that wants to obfuscate the same directory
- CDBWrapper odbw(ph, (1 << 10), false, false, true);
+ CDBWrapper odbw({.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = true});
// Check that the key/val we wrote with unobfuscated wrapper exists and
// is readable.
@@ -247,7 +249,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
fs::create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false);
+ std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(DBParams{.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = false});
uint8_t key{'k'};
uint256 in = InsecureRand256();
uint256 res;
@@ -260,7 +262,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
dbw.reset();
// Simulate a -reindex by wiping the existing data store
- CDBWrapper odbw(ph, (1 << 10), false, true, true);
+ CDBWrapper odbw({.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = true, .obfuscate = true});
// Check that the key/val we wrote with unobfuscated wrapper doesn't exist
uint256 res2;
@@ -279,7 +281,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_AUTO_TEST_CASE(iterator_ordering)
{
fs::path ph = m_args.GetDataDirBase() / "iterator_ordering";
- CDBWrapper dbw(ph, (1 << 20), true, false, false);
+ CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = false});
for (int x=0x00; x<256; ++x) {
uint8_t key = x;
uint32_t value = x*x;
@@ -324,12 +326,6 @@ struct StringContentsSerializer {
StringContentsSerializer() = default;
explicit StringContentsSerializer(const std::string& inp) : str(inp) {}
- StringContentsSerializer& operator+=(const std::string& s) {
- str += s;
- return *this;
- }
- StringContentsSerializer& operator+=(const StringContentsSerializer& s) { return *this += s.str; }
-
template<typename Stream>
void Serialize(Stream& s) const
{
@@ -343,44 +339,34 @@ struct StringContentsSerializer {
{
str.clear();
uint8_t c{0};
- while (true) {
- try {
- s >> c;
- str.push_back(c);
- } catch (const std::ios_base::failure&) {
- break;
- }
+ while (!s.eof()) {
+ s >> c;
+ str.push_back(c);
}
}
};
BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{
- char buf[10];
-
fs::path ph = m_args.GetDataDirBase() / "iterator_string_ordering";
- CDBWrapper dbw(ph, (1 << 20), true, false, false);
- for (int x=0x00; x<10; ++x) {
- for (int y = 0; y < 10; y++) {
- snprintf(buf, sizeof(buf), "%d", x);
- StringContentsSerializer key(buf);
- for (int z = 0; z < y; z++)
+ CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = false});
+ for (int x = 0; x < 10; ++x) {
+ for (int y = 0; y < 10; ++y) {
+ std::string key{ToString(x)};
+ for (int z = 0; z < y; ++z)
key += key;
uint32_t value = x*x;
- BOOST_CHECK(dbw.Write(key, value));
+ BOOST_CHECK(dbw.Write(StringContentsSerializer{key}, value));
}
}
std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
for (const int seek_start : {0, 5}) {
- snprintf(buf, sizeof(buf), "%d", seek_start);
- StringContentsSerializer seek_key(buf);
- it->Seek(seek_key);
- for (unsigned int x=seek_start; x<10; ++x) {
- for (int y = 0; y < 10; y++) {
- snprintf(buf, sizeof(buf), "%d", x);
- std::string exp_key(buf);
- for (int z = 0; z < y; z++)
+ it->Seek(StringContentsSerializer{ToString(seek_start)});
+ for (unsigned int x = seek_start; x < 10; ++x) {
+ for (int y = 0; y < 10; ++y) {
+ std::string exp_key{ToString(x)};
+ for (int z = 0; z < y; ++z)
exp_key += exp_key;
StringContentsSerializer key;
uint32_t value;
@@ -405,7 +391,7 @@ BOOST_AUTO_TEST_CASE(unicodepath)
// the ANSI CreateDirectoryA call and the code page isn't UTF8.
// It will succeed if created with CreateDirectoryW.
fs::path ph = m_args.GetDataDirBase() / "test_runner_â‚¿_ðŸƒ_20191128_104644";
- CDBWrapper dbw(ph, (1 << 20));
+ CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20});
fs::path lockPath = ph / "LOCK";
BOOST_CHECK(fs::exists(lockPath));
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 7150698e64..aca2b8eff0 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index 6b2ef74e19..c4b2b4c63b 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -45,6 +45,7 @@ constexpr int DERIVE_HARDENED = 16; // The final derivation is hardened, i.e. en
constexpr int MIXED_PUBKEYS = 32;
constexpr int XONLY_KEYS = 64; // X-only pubkeys are in use (and thus inferring/caching may swap parity of pubkeys/keyids)
constexpr int MISSING_PRIVKEYS = 128; // Not all private keys are available, so ToPrivateString will fail.
+constexpr int SIGNABLE_FAILS = 256; // We can sign with this descriptor, but actually trying to sign will fail
/** Compare two descriptors. If only one of them has a checksum, the checksum is ignored. */
bool EqualDescriptor(std::string a, std::string b)
@@ -126,8 +127,11 @@ std::set<std::pair<CPubKey, KeyOriginInfo>> GetKeyOriginData(const FlatSigningPr
return ret;
}
-void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY,
- bool replace_apostrophe_with_h_in_prv=false, bool replace_apostrophe_with_h_in_pub=false)
+void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_pub, int flags,
+ const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type,
+ const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY, bool replace_apostrophe_with_h_in_prv=false,
+ bool replace_apostrophe_with_h_in_pub=false, uint32_t spender_nlocktime=0, uint32_t spender_nsequence=CTxIn::SEQUENCE_FINAL,
+ std::map<std::vector<uint8_t>, std::vector<uint8_t>> preimages={})
{
FlatSigningProvider keys_priv, keys_pub;
std::set<std::vector<uint32_t>> left_paths = paths;
@@ -303,16 +307,24 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
for (size_t n = 0; n < spks.size(); ++n) {
BOOST_CHECK_EQUAL(ref[n], HexStr(spks[n]));
- if (flags & SIGNABLE) {
+ if (flags & (SIGNABLE | SIGNABLE_FAILS)) {
CMutableTransaction spend;
+ spend.nLockTime = spender_nlocktime;
spend.vin.resize(1);
+ spend.vin[0].nSequence = spender_nsequence;
spend.vout.resize(1);
std::vector<CTxOut> utxos(1);
PrecomputedTransactionData txdata;
txdata.Init(spend, std::move(utxos), /*force=*/true);
MutableTransactionSignatureCreator creator{spend, 0, CAmount{0}, &txdata, SIGHASH_DEFAULT};
SignatureData sigdata;
- BOOST_CHECK_MESSAGE(ProduceSignature(FlatSigningProvider{keys_priv}.Merge(FlatSigningProvider{script_provider}), creator, spks[n], sigdata), prv);
+ // We assume there is no collision between the hashes (eg h1=SHA256(SHA256(x)) and h2=SHA256(x))
+ sigdata.sha256_preimages = preimages;
+ sigdata.hash256_preimages = preimages;
+ sigdata.ripemd160_preimages = preimages;
+ sigdata.hash160_preimages = preimages;
+ const auto prod_sig_res = ProduceSignature(FlatSigningProvider{keys_priv}.Merge(FlatSigningProvider{script_provider}), creator, spks[n], sigdata);
+ BOOST_CHECK_MESSAGE(prod_sig_res == !(flags & SIGNABLE_FAILS), prv);
}
/* Infer a descriptor from the generated script, and verify its solvability and that it roundtrips. */
@@ -340,29 +352,40 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
BOOST_CHECK_MESSAGE(left_paths.empty(), "Not all expected key paths found: " + prv);
}
-void Check(const std::string& prv, const std::string& pub, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY)
+void Check(const std::string& prv, const std::string& pub, const std::string& norm_pub, int flags,
+ const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type,
+ const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY, uint32_t spender_nlocktime=0,
+ uint32_t spender_nsequence=CTxIn::SEQUENCE_FINAL, std::map<std::vector<uint8_t>, std::vector<uint8_t>> preimages={})
{
bool found_apostrophes_in_prv = false;
bool found_apostrophes_in_pub = false;
// Do not replace apostrophes with 'h' in prv and pub
- DoCheck(prv, pub, norm_pub, flags, scripts, type, paths);
+ DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /*replace_apostrophe_with_h_in_prv=*/false,
+ /*replace_apostrophe_with_h_in_pub=*/false, /*spender_nlocktime=*/spender_nlocktime,
+ /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages);
// Replace apostrophes with 'h' in prv but not in pub, if apostrophes are found in prv
if (prv.find('\'') != std::string::npos) {
found_apostrophes_in_prv = true;
- DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /* replace_apostrophe_with_h_in_prv = */true, /*replace_apostrophe_with_h_in_pub = */false);
+ DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /*replace_apostrophe_with_h_in_prv=*/true,
+ /*replace_apostrophe_with_h_in_pub=*/false, /*spender_nlocktime=*/spender_nlocktime,
+ /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages);
}
// Replace apostrophes with 'h' in pub but not in prv, if apostrophes are found in pub
if (pub.find('\'') != std::string::npos) {
found_apostrophes_in_pub = true;
- DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /* replace_apostrophe_with_h_in_prv = */false, /*replace_apostrophe_with_h_in_pub = */true);
+ DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /*replace_apostrophe_with_h_in_prv=*/false,
+ /*replace_apostrophe_with_h_in_pub=*/true, /*spender_nlocktime=*/spender_nlocktime,
+ /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages);
}
// Replace apostrophes with 'h' both in prv and in pub, if apostrophes are found in both
if (found_apostrophes_in_prv && found_apostrophes_in_pub) {
- DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /* replace_apostrophe_with_h_in_prv = */true, /*replace_apostrophe_with_h_in_pub = */true);
+ DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /*replace_apostrophe_with_h_in_prv=*/true,
+ /*replace_apostrophe_with_h_in_pub=*/true, /*spender_nlocktime=*/spender_nlocktime,
+ /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages);
}
}
@@ -528,9 +551,31 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
CheckUnparsable("wsh(and_b(and_b(older(1),a:older(100000000)),s:pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd)))", "wsh(and_b(and_b(older(1),a:older(100000000)),s:pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)))", "and_b(older(1),a:older(100000000)) is not sane: contains mixes of timelocks expressed in blocks and seconds");
CheckUnparsable("wsh(and_b(or_b(pkh(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),s:pk(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn)),s:pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd)))", "wsh(and_b(or_b(pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),s:pk(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0)),s:pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)))", "and_b(or_b(pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),s:pk(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0)),s:pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)) is not sane: contains duplicate public keys");
// Valid with extended keys.
- Check("wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)))", "wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", "wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", UNSOLVABLE, {{"0020acf425291b98a1d7e0d4690139442abc289175be32ef1f75945e339924246d73"}}, OutputType::BECH32, {{},{0}});
- // Valid under sh(wsh()) and with a mix of xpubs and raw keys
- Check("sh(wsh(thresh(1,pkh(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),a:and_n(multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0),n:older(2)))))", "sh(wsh(thresh(1,pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", "sh(wsh(thresh(1,pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", UNSOLVABLE | MIXED_PUBKEYS, {{"a914767e9119ff3b3ac0cb6dcfe21de1842ccf85f1c487"}}, OutputType::P2SH_SEGWIT, {{},{0}});
+ Check("wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)))", "wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", "wsh(and_v(v:ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e),multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", DEFAULT, {{"0020acf425291b98a1d7e0d4690139442abc289175be32ef1f75945e339924246d73"}}, OutputType::BECH32, {{},{0}});
+ // Valid under sh(wsh()) and with a mix of xpubs and raw keys.
+ Check("sh(wsh(thresh(1,pkh(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),a:and_n(multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0),n:older(2)))))", "sh(wsh(thresh(1,pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", "sh(wsh(thresh(1,pkh(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", SIGNABLE | MIXED_PUBKEYS, {{"a914767e9119ff3b3ac0cb6dcfe21de1842ccf85f1c487"}}, OutputType::P2SH_SEGWIT, {{},{0}});
+ // An exotic multisig, we can sign for both branches
+ Check("wsh(thresh(1,pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc),a:pkh(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)))", "wsh(thresh(1,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL),a:pkh(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", "wsh(thresh(1,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL),a:pkh(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)))", SIGNABLE, {{"00204a4528fbc0947e02e921b54bd476fc8cc2ebb5c6ae2ccf10ed29fe2937fb6892"}}, OutputType::BECH32, {{},{0}});
+ // We can sign for a script requiring the two kinds of timelock.
+ // But if we don't set a sequence high enough, we'll fail.
+ Check("sh(wsh(thresh(2,ndv:after(1000),a:and_n(multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0),n:older(2)))))", "sh(wsh(thresh(2,ndv:after(1000),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", "sh(wsh(thresh(2,ndv:after(1000),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", SIGNABLE_FAILS, {{"a914099f400961f930d4c16c3b33c0e2a58ef53ac38f87"}}, OutputType::P2SH_SEGWIT, {{},{0}}, /*spender_nlocktime=*/1000, /*spender_nsequence=*/1);
+ // And same for the nLockTime.
+ Check("sh(wsh(thresh(2,ndv:after(1000),a:and_n(multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0),n:older(2)))))", "sh(wsh(thresh(2,ndv:after(1000),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", "sh(wsh(thresh(2,ndv:after(1000),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", SIGNABLE_FAILS, {{"a914099f400961f930d4c16c3b33c0e2a58ef53ac38f87"}}, OutputType::P2SH_SEGWIT, {{},{0}}, /*spender_nlocktime=*/999, /*spender_nsequence=*/2);
+ // But if both are set to (at least) the required value, we'll succeed.
+ Check("sh(wsh(thresh(2,ndv:after(1000),a:and_n(multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0),n:older(2)))))", "sh(wsh(thresh(2,ndv:after(1000),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", "sh(wsh(thresh(2,ndv:after(1000),a:and_n(multi(1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0),n:older(2)))))", SIGNABLE, {{"a914099f400961f930d4c16c3b33c0e2a58ef53ac38f87"}}, OutputType::P2SH_SEGWIT, {{},{0}}, /*spender_nlocktime=*/1000, /*spender_nsequence=*/2);
+ // We can't sign for a script requiring a ripemd160 preimage without providing it.
+ Check("wsh(and_v(v:ripemd160(ff9aa1829c90d26e73301383f549e1497b7d6325),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:ripemd160(ff9aa1829c90d26e73301383f549e1497b7d6325),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:ripemd160(ff9aa1829c90d26e73301383f549e1497b7d6325),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE_FAILS, {{"002001549deda34cbc4a5982263191380f522695a2ddc2f99fc3a65c736264bd6cab"}}, OutputType::BECH32, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {});
+ // But if we provide it, we can.
+ Check("wsh(and_v(v:ripemd160(ff9aa1829c90d26e73301383f549e1497b7d6325),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:ripemd160(ff9aa1829c90d26e73301383f549e1497b7d6325),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:ripemd160(ff9aa1829c90d26e73301383f549e1497b7d6325),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE, {{"002001549deda34cbc4a5982263191380f522695a2ddc2f99fc3a65c736264bd6cab"}}, OutputType::BECH32, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{ParseHex("ff9aa1829c90d26e73301383f549e1497b7d6325"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}});
+ // Same for sha256
+ Check("wsh(and_v(v:sha256(7426ba0604c3f8682c7016b44673f85c5bd9da2fa6c1080810cf53ae320c9863),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:sha256(7426ba0604c3f8682c7016b44673f85c5bd9da2fa6c1080810cf53ae320c9863),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:sha256(7426ba0604c3f8682c7016b44673f85c5bd9da2fa6c1080810cf53ae320c9863),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE_FAILS, {{"002071f7283dbbb9a55ed43a54cda16ba0efd0f16dc48fe200f299e57bb5d7be8dd4"}}, OutputType::BECH32, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {});
+ Check("wsh(and_v(v:sha256(7426ba0604c3f8682c7016b44673f85c5bd9da2fa6c1080810cf53ae320c9863),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:sha256(7426ba0604c3f8682c7016b44673f85c5bd9da2fa6c1080810cf53ae320c9863),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:sha256(7426ba0604c3f8682c7016b44673f85c5bd9da2fa6c1080810cf53ae320c9863),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE, {{"002071f7283dbbb9a55ed43a54cda16ba0efd0f16dc48fe200f299e57bb5d7be8dd4"}}, OutputType::BECH32, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{ParseHex("7426ba0604c3f8682c7016b44673f85c5bd9da2fa6c1080810cf53ae320c9863"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}});
+ // Same for hash160
+ Check("wsh(and_v(v:hash160(292e2df59e3a22109200beed0cdc84b12e66793e),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:hash160(292e2df59e3a22109200beed0cdc84b12e66793e),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:hash160(292e2df59e3a22109200beed0cdc84b12e66793e),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE_FAILS, {{"00209b9d5b45735d0e15df5b41d6594602d3de472262f7b75edc6cf5f3e3fa4e3ae4"}}, OutputType::BECH32, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {});
+ Check("wsh(and_v(v:hash160(292e2df59e3a22109200beed0cdc84b12e66793e),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:hash160(292e2df59e3a22109200beed0cdc84b12e66793e),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:hash160(292e2df59e3a22109200beed0cdc84b12e66793e),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE, {{"00209b9d5b45735d0e15df5b41d6594602d3de472262f7b75edc6cf5f3e3fa4e3ae4"}}, OutputType::BECH32, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{ParseHex("292e2df59e3a22109200beed0cdc84b12e66793e"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}});
+ // Same for hash256
+ Check("wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE_FAILS, {{"0020cf62bf97baf977aec69cbc290c372899f913337a9093e8f066ab59b8657a365c"}}, OutputType::BECH32, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {});
+ Check("wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE, {{"0020cf62bf97baf977aec69cbc290c372899f913337a9093e8f066ab59b8657a365c"}}, OutputType::BECH32, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{ParseHex("ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}});
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index 605faa08e4..9931d19c2b 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index d2554483d4..7e7d630daa 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
diff --git a/src/test/fuzz/addition_overflow.cpp b/src/test/fuzz/addition_overflow.cpp
index 372c1a370e..7b84bfda20 100644
--- a/src/test/fuzz/addition_overflow.cpp
+++ b/src/test/fuzz/addition_overflow.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index 7668940cbc..a59e41dbb5 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
#include <time.h>
#include <util/asmap.h>
@@ -116,7 +117,7 @@ void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
const std::chrono::seconds time_penalty{fast_random_context.randrange(100000001)};
addrman.Add({addr}, source, time_penalty);
- if (n > 0 && addrman.size() % n == 0) {
+ if (n > 0 && addrman.Size() % n == 0) {
addrman.Good(addr, Now<NodeSeconds>());
}
@@ -303,7 +304,7 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
/*max_pct=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
/*network=*/std::nullopt);
(void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool());
- (void)const_addr_man.size();
+ (void)const_addr_man.Size();
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
data_stream << const_addr_man;
}
diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
index 1a8957d090..a7b41370a8 100644
--- a/src/test/fuzz/autofile.cpp
+++ b/src/test/fuzz/autofile.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index b2969ecdc0..273dcfd850 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,6 +8,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
#include <util/readwritefile.h>
#include <util/system.h>
diff --git a/src/test/fuzz/base_encode_decode.cpp b/src/test/fuzz/base_encode_decode.cpp
index 48356065b0..d322416d34 100644
--- a/src/test/fuzz/base_encode_decode.cpp
+++ b/src/test/fuzz/base_encode_decode.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,12 +14,7 @@
#include <string>
#include <vector>
-void initialize_base_encode_decode()
-{
- static const ECCVerifyHandle verify_handle;
-}
-
-FUZZ_TARGET_INIT(base_encode_decode, initialize_base_encode_decode)
+FUZZ_TARGET(base_encode_decode)
{
const std::string random_encoded_string(buffer.begin(), buffer.end());
diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp
index b7ed2c6abd..c3e17724eb 100644
--- a/src/test/fuzz/block.cpp
+++ b/src/test/fuzz/block.cpp
@@ -19,7 +19,6 @@
void initialize_block()
{
- static const ECCVerifyHandle verify_handle;
SelectParams(CBaseChainParams::REGTEST);
}
diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
index a8c3318629..67cac8fa4e 100644
--- a/src/test/fuzz/buffered_file.cpp
+++ b/src/test/fuzz/buffered_file.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/chain.cpp b/src/test/fuzz/chain.cpp
index 01edb06138..49b9898228 100644
--- a/src/test/fuzz/chain.cpp
+++ b/src/test/fuzz/chain.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/checkqueue.cpp b/src/test/fuzz/checkqueue.cpp
index 7d107995aa..6256aefaa3 100644
--- a/src/test/fuzz/checkqueue.cpp
+++ b/src/test/fuzz/checkqueue.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index 6c96702f1e..e80c772aa4 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -46,7 +46,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CCoinsView backend_coins_view;
- CCoinsViewCache coins_view_cache{&backend_coins_view};
+ CCoinsViewCache coins_view_cache{&backend_coins_view, /*deterministic=*/true};
COutPoint random_out_point;
Coin random_coin;
CMutableTransaction random_mutable_transaction;
@@ -75,6 +75,9 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
(void)coins_view_cache.Flush();
},
[&] {
+ (void)coins_view_cache.Sync();
+ },
+ [&] {
coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider));
},
[&] {
diff --git a/src/test/fuzz/coinscache_sim.cpp b/src/test/fuzz/coinscache_sim.cpp
new file mode 100644
index 0000000000..f350c9d032
--- /dev/null
+++ b/src/test/fuzz/coinscache_sim.cpp
@@ -0,0 +1,478 @@
+// Copyright (c) 2023 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <coins.h>
+#include <crypto/sha256.h>
+#include <primitives/transaction.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/util.h>
+
+#include <assert.h>
+#include <optional>
+#include <memory>
+#include <stdint.h>
+#include <vector>
+
+namespace {
+
+/** Number of distinct COutPoint values used in this test. */
+constexpr uint32_t NUM_OUTPOINTS = 256;
+/** Number of distinct Coin values used in this test (ignoring nHeight). */
+constexpr uint32_t NUM_COINS = 256;
+/** Maximum number CCoinsViewCache objects used in this test. */
+constexpr uint32_t MAX_CACHES = 4;
+/** Data type large enough to hold NUM_COINS-1. */
+using coinidx_type = uint8_t;
+
+struct PrecomputedData
+{
+ //! Randomly generated COutPoint values.
+ COutPoint outpoints[NUM_OUTPOINTS];
+
+ //! Randomly generated Coin values.
+ Coin coins[NUM_COINS];
+
+ PrecomputedData()
+ {
+ static const uint8_t PREFIX_O[1] = {'o'}; /** Hash prefix for outpoint hashes. */
+ static const uint8_t PREFIX_S[1] = {'s'}; /** Hash prefix for coins scriptPubKeys. */
+ static const uint8_t PREFIX_M[1] = {'m'}; /** Hash prefix for coins nValue/fCoinBase. */
+
+ for (uint32_t i = 0; i < NUM_OUTPOINTS; ++i) {
+ uint32_t idx = (i * 1200U) >> 12; /* Map 3 or 4 entries to same txid. */
+ const uint8_t ser[4] = {uint8_t(idx), uint8_t(idx >> 8), uint8_t(idx >> 16), uint8_t(idx >> 24)};
+ CSHA256().Write(PREFIX_O, 1).Write(ser, sizeof(ser)).Finalize(outpoints[i].hash.begin());
+ outpoints[i].n = i;
+ }
+
+ for (uint32_t i = 0; i < NUM_COINS; ++i) {
+ const uint8_t ser[4] = {uint8_t(i), uint8_t(i >> 8), uint8_t(i >> 16), uint8_t(i >> 24)};
+ uint256 hash;
+ CSHA256().Write(PREFIX_S, 1).Write(ser, sizeof(ser)).Finalize(hash.begin());
+ /* Convert hash to scriptPubkeys (of different lengths, so SanityCheck's cached memory
+ * usage check has a chance to detect mismatches). */
+ switch (i % 5U) {
+ case 0: /* P2PKH */
+ coins[i].out.scriptPubKey.resize(25);
+ coins[i].out.scriptPubKey[0] = OP_DUP;
+ coins[i].out.scriptPubKey[1] = OP_HASH160;
+ coins[i].out.scriptPubKey[2] = 20;
+ std::copy(hash.begin(), hash.begin() + 20, coins[i].out.scriptPubKey.begin() + 3);
+ coins[i].out.scriptPubKey[23] = OP_EQUALVERIFY;
+ coins[i].out.scriptPubKey[24] = OP_CHECKSIG;
+ break;
+ case 1: /* P2SH */
+ coins[i].out.scriptPubKey.resize(23);
+ coins[i].out.scriptPubKey[0] = OP_HASH160;
+ coins[i].out.scriptPubKey[1] = 20;
+ std::copy(hash.begin(), hash.begin() + 20, coins[i].out.scriptPubKey.begin() + 2);
+ coins[i].out.scriptPubKey[12] = OP_EQUAL;
+ break;
+ case 2: /* P2WPKH */
+ coins[i].out.scriptPubKey.resize(22);
+ coins[i].out.scriptPubKey[0] = OP_0;
+ coins[i].out.scriptPubKey[1] = 20;
+ std::copy(hash.begin(), hash.begin() + 20, coins[i].out.scriptPubKey.begin() + 2);
+ break;
+ case 3: /* P2WSH */
+ coins[i].out.scriptPubKey.resize(34);
+ coins[i].out.scriptPubKey[0] = OP_0;
+ coins[i].out.scriptPubKey[1] = 32;
+ std::copy(hash.begin(), hash.begin() + 32, coins[i].out.scriptPubKey.begin() + 2);
+ break;
+ case 4: /* P2TR */
+ coins[i].out.scriptPubKey.resize(34);
+ coins[i].out.scriptPubKey[0] = OP_1;
+ coins[i].out.scriptPubKey[1] = 32;
+ std::copy(hash.begin(), hash.begin() + 32, coins[i].out.scriptPubKey.begin() + 2);
+ break;
+ }
+ /* Hash again to construct nValue and fCoinBase. */
+ CSHA256().Write(PREFIX_M, 1).Write(ser, sizeof(ser)).Finalize(hash.begin());
+ coins[i].out.nValue = CAmount(hash.GetUint64(0) % MAX_MONEY);
+ coins[i].fCoinBase = (hash.GetUint64(1) & 7) == 0;
+ coins[i].nHeight = 0; /* Real nHeight used in simulation is set dynamically. */
+ }
+ }
+};
+
+enum class EntryType : uint8_t
+{
+ /* This entry in the cache does not exist (so we'd have to look in the parent cache). */
+ NONE,
+
+ /* This entry in the cache corresponds to an unspent coin. */
+ UNSPENT,
+
+ /* This entry in the cache corresponds to a spent coin. */
+ SPENT,
+};
+
+struct CacheEntry
+{
+ /* Type of entry. */
+ EntryType entrytype;
+
+ /* Index in the coins array this entry corresponds to (only if entrytype == UNSPENT). */
+ coinidx_type coinidx;
+
+ /* nHeight value for this entry (so the coins[coinidx].nHeight value is ignored; only if entrytype == UNSPENT). */
+ uint32_t height;
+};
+
+struct CacheLevel
+{
+ CacheEntry entry[NUM_OUTPOINTS];
+
+ void Wipe() {
+ for (uint32_t i = 0; i < NUM_OUTPOINTS; ++i) {
+ entry[i].entrytype = EntryType::NONE;
+ }
+ }
+};
+
+/** Class for the base of the hierarchy (roughly simulating a memory-backed CCoinsViewDB).
+ *
+ * The initial state consists of the empty UTXO set, though coins whose output index
+ * is 3 (mod 5) always have GetCoin() succeed (but returning an IsSpent() coin unless a UTXO
+ * exists). Coins whose output index is 4 (mod 5) have GetCoin() always succeed after being spent.
+ * This exercises code paths with spent, non-DIRTY cache entries.
+ */
+class CoinsViewBottom final : public CCoinsView
+{
+ std::map<COutPoint, Coin> m_data;
+
+public:
+ bool GetCoin(const COutPoint& outpoint, Coin& coin) const final
+ {
+ auto it = m_data.find(outpoint);
+ if (it == m_data.end()) {
+ if ((outpoint.n % 5) == 3) {
+ coin.Clear();
+ return true;
+ }
+ return false;
+ } else {
+ coin = it->second;
+ return true;
+ }
+ }
+
+ bool HaveCoin(const COutPoint& outpoint) const final
+ {
+ return m_data.count(outpoint);
+ }
+
+ uint256 GetBestBlock() const final { return {}; }
+ std::vector<uint256> GetHeadBlocks() const final { return {}; }
+ std::unique_ptr<CCoinsViewCursor> Cursor() const final { return {}; }
+ size_t EstimateSize() const final { return m_data.size(); }
+
+ bool BatchWrite(CCoinsMap& data, const uint256&, bool erase) final
+ {
+ for (auto it = data.begin(); it != data.end(); it = erase ? data.erase(it) : std::next(it)) {
+ if (it->second.flags & CCoinsCacheEntry::DIRTY) {
+ if (it->second.coin.IsSpent() && (it->first.n % 5) != 4) {
+ m_data.erase(it->first);
+ } else if (erase) {
+ m_data[it->first] = std::move(it->second.coin);
+ } else {
+ m_data[it->first] = it->second.coin;
+ }
+ } else {
+ /* For non-dirty entries being written, compare them with what we have. */
+ auto it2 = m_data.find(it->first);
+ if (it->second.coin.IsSpent()) {
+ assert(it2 == m_data.end() || it2->second.IsSpent());
+ } else {
+ assert(it2 != m_data.end());
+ assert(it->second.coin.out == it2->second.out);
+ assert(it->second.coin.fCoinBase == it2->second.fCoinBase);
+ assert(it->second.coin.nHeight == it2->second.nHeight);
+ }
+ }
+ }
+ return true;
+ }
+};
+
+} // namespace
+
+FUZZ_TARGET(coinscache_sim)
+{
+ /** Precomputed COutPoint and CCoins values. */
+ static const PrecomputedData data;
+
+ /** Dummy coinsview instance (base of the hierarchy). */
+ CoinsViewBottom bottom;
+ /** Real CCoinsViewCache objects. */
+ std::vector<std::unique_ptr<CCoinsViewCache>> caches;
+ /** Simulated cache data (sim_caches[0] matches bottom, sim_caches[i+1] matches caches[i]). */
+ CacheLevel sim_caches[MAX_CACHES + 1];
+ /** Current height in the simulation. */
+ uint32_t current_height = 1U;
+
+ // Initialize bottom simulated cache.
+ sim_caches[0].Wipe();
+
+ /** Helper lookup function in the simulated cache stack. */
+ auto lookup = [&](uint32_t outpointidx, int sim_idx = -1) -> std::optional<std::pair<coinidx_type, uint32_t>> {
+ uint32_t cache_idx = sim_idx == -1 ? caches.size() : sim_idx;
+ while (true) {
+ const auto& entry = sim_caches[cache_idx].entry[outpointidx];
+ if (entry.entrytype == EntryType::UNSPENT) {
+ return {{entry.coinidx, entry.height}};
+ } else if (entry.entrytype == EntryType::SPENT) {
+ return std::nullopt;
+ };
+ if (cache_idx == 0) break;
+ --cache_idx;
+ }
+ return std::nullopt;
+ };
+
+ /** Flush changes in top cache to the one below. */
+ auto flush = [&]() {
+ assert(caches.size() >= 1);
+ auto& cache = sim_caches[caches.size()];
+ auto& prev_cache = sim_caches[caches.size() - 1];
+ for (uint32_t outpointidx = 0; outpointidx < NUM_OUTPOINTS; ++outpointidx) {
+ if (cache.entry[outpointidx].entrytype != EntryType::NONE) {
+ prev_cache.entry[outpointidx] = cache.entry[outpointidx];
+ cache.entry[outpointidx].entrytype = EntryType::NONE;
+ }
+ }
+ };
+
+ // Main simulation loop: read commands from the fuzzer input, and apply them
+ // to both the real cache stack and the simulation.
+ FuzzedDataProvider provider(buffer.data(), buffer.size());
+ LIMITED_WHILE(provider.remaining_bytes(), 10000) {
+ // Every operation (except "Change height") moves current height forward,
+ // so it functions as a kind of epoch, making ~all UTXOs unique.
+ ++current_height;
+ // Make sure there is always at least one CCoinsViewCache.
+ if (caches.empty()) {
+ caches.emplace_back(new CCoinsViewCache(&bottom, /*deterministic=*/true));
+ sim_caches[caches.size()].Wipe();
+ }
+
+ // Execute command.
+ CallOneOf(
+ provider,
+
+ [&]() { // GetCoin
+ uint32_t outpointidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_OUTPOINTS - 1);
+ // Look up in simulation data.
+ auto sim = lookup(outpointidx);
+ // Look up in real caches.
+ Coin realcoin;
+ auto real = caches.back()->GetCoin(data.outpoints[outpointidx], realcoin);
+ // Compare results.
+ if (!sim.has_value()) {
+ assert(!real || realcoin.IsSpent());
+ } else {
+ assert(real && !realcoin.IsSpent());
+ const auto& simcoin = data.coins[sim->first];
+ assert(realcoin.out == simcoin.out);
+ assert(realcoin.fCoinBase == simcoin.fCoinBase);
+ assert(realcoin.nHeight == sim->second);
+ }
+ },
+
+ [&]() { // HaveCoin
+ uint32_t outpointidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_OUTPOINTS - 1);
+ // Look up in simulation data.
+ auto sim = lookup(outpointidx);
+ // Look up in real caches.
+ auto real = caches.back()->HaveCoin(data.outpoints[outpointidx]);
+ // Compare results.
+ assert(sim.has_value() == real);
+ },
+
+ [&]() { // HaveCoinInCache
+ uint32_t outpointidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_OUTPOINTS - 1);
+ // Invoke on real cache (there is no equivalent in simulation, so nothing to compare result with).
+ (void)caches.back()->HaveCoinInCache(data.outpoints[outpointidx]);
+ },
+
+ [&]() { // AccessCoin
+ uint32_t outpointidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_OUTPOINTS - 1);
+ // Look up in simulation data.
+ auto sim = lookup(outpointidx);
+ // Look up in real caches.
+ const auto& realcoin = caches.back()->AccessCoin(data.outpoints[outpointidx]);
+ // Compare results.
+ if (!sim.has_value()) {
+ assert(realcoin.IsSpent());
+ } else {
+ assert(!realcoin.IsSpent());
+ const auto& simcoin = data.coins[sim->first];
+ assert(simcoin.out == realcoin.out);
+ assert(simcoin.fCoinBase == realcoin.fCoinBase);
+ assert(realcoin.nHeight == sim->second);
+ }
+ },
+
+ [&]() { // AddCoin (only possible_overwrite if necessary)
+ uint32_t outpointidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_OUTPOINTS - 1);
+ uint32_t coinidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_COINS - 1);
+ // Look up in simulation data (to know whether we must set possible_overwrite or not).
+ auto sim = lookup(outpointidx);
+ // Invoke on real caches.
+ Coin coin = data.coins[coinidx];
+ coin.nHeight = current_height;
+ caches.back()->AddCoin(data.outpoints[outpointidx], std::move(coin), sim.has_value());
+ // Apply to simulation data.
+ auto& entry = sim_caches[caches.size()].entry[outpointidx];
+ entry.entrytype = EntryType::UNSPENT;
+ entry.coinidx = coinidx;
+ entry.height = current_height;
+ },
+
+ [&]() { // AddCoin (always possible_overwrite)
+ uint32_t outpointidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_OUTPOINTS - 1);
+ uint32_t coinidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_COINS - 1);
+ // Invoke on real caches.
+ Coin coin = data.coins[coinidx];
+ coin.nHeight = current_height;
+ caches.back()->AddCoin(data.outpoints[outpointidx], std::move(coin), true);
+ // Apply to simulation data.
+ auto& entry = sim_caches[caches.size()].entry[outpointidx];
+ entry.entrytype = EntryType::UNSPENT;
+ entry.coinidx = coinidx;
+ entry.height = current_height;
+ },
+
+ [&]() { // SpendCoin (moveto = nullptr)
+ uint32_t outpointidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_OUTPOINTS - 1);
+ // Invoke on real caches.
+ caches.back()->SpendCoin(data.outpoints[outpointidx], nullptr);
+ // Apply to simulation data.
+ sim_caches[caches.size()].entry[outpointidx].entrytype = EntryType::SPENT;
+ },
+
+ [&]() { // SpendCoin (with moveto)
+ uint32_t outpointidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_OUTPOINTS - 1);
+ // Look up in simulation data (to compare the returned *moveto with).
+ auto sim = lookup(outpointidx);
+ // Invoke on real caches.
+ Coin realcoin;
+ caches.back()->SpendCoin(data.outpoints[outpointidx], &realcoin);
+ // Apply to simulation data.
+ sim_caches[caches.size()].entry[outpointidx].entrytype = EntryType::SPENT;
+ // Compare *moveto with the value expected based on simulation data.
+ if (!sim.has_value()) {
+ assert(realcoin.IsSpent());
+ } else {
+ assert(!realcoin.IsSpent());
+ const auto& simcoin = data.coins[sim->first];
+ assert(simcoin.out == realcoin.out);
+ assert(simcoin.fCoinBase == realcoin.fCoinBase);
+ assert(realcoin.nHeight == sim->second);
+ }
+ },
+
+ [&]() { // Uncache
+ uint32_t outpointidx = provider.ConsumeIntegralInRange<uint32_t>(0, NUM_OUTPOINTS - 1);
+ // Apply to real caches (there is no equivalent in our simulation).
+ caches.back()->Uncache(data.outpoints[outpointidx]);
+ },
+
+ [&]() { // Add a cache level (if not already at the max).
+ if (caches.size() != MAX_CACHES) {
+ // Apply to real caches.
+ caches.emplace_back(new CCoinsViewCache(&*caches.back(), /*deterministic=*/true));
+ // Apply to simulation data.
+ sim_caches[caches.size()].Wipe();
+ }
+ },
+
+ [&]() { // Remove a cache level.
+ // Apply to real caches (this reduces caches.size(), implicitly doing the same on the simulation data).
+ caches.back()->SanityCheck();
+ caches.pop_back();
+ },
+
+ [&]() { // Flush.
+ // Apply to simulation data.
+ flush();
+ // Apply to real caches.
+ caches.back()->Flush();
+ },
+
+ [&]() { // Sync.
+ // Apply to simulation data (note that in our simulation, syncing and flushing is the same thing).
+ flush();
+ // Apply to real caches.
+ caches.back()->Sync();
+ },
+
+ [&]() { // Flush + ReallocateCache.
+ // Apply to simulation data.
+ flush();
+ // Apply to real caches.
+ caches.back()->Flush();
+ caches.back()->ReallocateCache();
+ },
+
+ [&]() { // GetCacheSize
+ (void)caches.back()->GetCacheSize();
+ },
+
+ [&]() { // DynamicMemoryUsage
+ (void)caches.back()->DynamicMemoryUsage();
+ },
+
+ [&]() { // Change height
+ current_height = provider.ConsumeIntegralInRange<uint32_t>(1, current_height - 1);
+ }
+ );
+ }
+
+ // Sanity check all the remaining caches
+ for (const auto& cache : caches) {
+ cache->SanityCheck();
+ }
+
+ // Full comparison between caches and simulation data, from bottom to top,
+ // as AccessCoin on a higher cache may affect caches below it.
+ for (unsigned sim_idx = 1; sim_idx <= caches.size(); ++sim_idx) {
+ auto& cache = *caches[sim_idx - 1];
+ size_t cache_size = 0;
+
+ for (uint32_t outpointidx = 0; outpointidx < NUM_OUTPOINTS; ++outpointidx) {
+ cache_size += cache.HaveCoinInCache(data.outpoints[outpointidx]);
+ const auto& real = cache.AccessCoin(data.outpoints[outpointidx]);
+ auto sim = lookup(outpointidx, sim_idx);
+ if (!sim.has_value()) {
+ assert(real.IsSpent());
+ } else {
+ assert(!real.IsSpent());
+ assert(real.out == data.coins[sim->first].out);
+ assert(real.fCoinBase == data.coins[sim->first].fCoinBase);
+ assert(real.nHeight == sim->second);
+ }
+ }
+
+ // HaveCoinInCache ignores spent coins, so GetCacheSize() may exceed it. */
+ assert(cache.GetCacheSize() >= cache_size);
+ }
+
+ // Compare the bottom coinsview (not a CCoinsViewCache) with sim_cache[0].
+ for (uint32_t outpointidx = 0; outpointidx < NUM_OUTPOINTS; ++outpointidx) {
+ Coin realcoin;
+ bool real = bottom.GetCoin(data.outpoints[outpointidx], realcoin);
+ auto sim = lookup(outpointidx, 0);
+ if (!sim.has_value()) {
+ assert(!real || realcoin.IsSpent());
+ } else {
+ assert(real && !realcoin.IsSpent());
+ assert(realcoin.out == data.coins[sim->first].out);
+ assert(realcoin.fCoinBase == data.coins[sim->first].fCoinBase);
+ assert(realcoin.nHeight == sim->second);
+ }
+ }
+}
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 4406779015..798c14030c 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
#include <util/system.h>
#include <util/translation.h>
diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp
index 3f552a8cda..3fa445096a 100644
--- a/src/test/fuzz/crypto_chacha20.cpp
+++ b/src/test/fuzz/crypto_chacha20.cpp
@@ -6,6 +6,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/xoroshiro128plusplus.h>
#include <cstdint>
#include <vector>
@@ -16,21 +17,21 @@ FUZZ_TARGET(crypto_chacha20)
ChaCha20 chacha20;
if (fuzzed_data_provider.ConsumeBool()) {
- const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32));
- chacha20 = ChaCha20{key.data(), key.size()};
+ const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
+ chacha20 = ChaCha20{key.data()};
}
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
CallOneOf(
fuzzed_data_provider,
[&] {
- const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32));
- chacha20.SetKey(key.data(), key.size());
+ std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
+ chacha20.SetKey32(key.data());
},
[&] {
chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
},
[&] {
- chacha20.Seek(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ chacha20.Seek64(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
},
[&] {
std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
@@ -43,3 +44,110 @@ FUZZ_TARGET(crypto_chacha20)
});
}
}
+
+namespace
+{
+
+/** Fuzzer that invokes ChaCha20::Crypt() or ChaCha20::Keystream multiple times:
+ once for a large block at once, and then the same data in chunks, comparing
+ the outcome.
+
+ If UseCrypt, seeded Xoroshiro128++ output is used as input to Crypt().
+ If not, Keystream() is used directly, or sequences of 0x00 are encrypted.
+*/
+template<bool UseCrypt>
+void ChaCha20SplitFuzz(FuzzedDataProvider& provider)
+{
+ // Determine key, iv, start position, length.
+ unsigned char key[32] = {0};
+ auto key_bytes = provider.ConsumeBytes<unsigned char>(32);
+ std::copy(key_bytes.begin(), key_bytes.end(), key);
+ uint64_t iv = provider.ConsumeIntegral<uint64_t>();
+ uint64_t total_bytes = provider.ConsumeIntegralInRange<uint64_t>(0, 1000000);
+ /* ~x = 2^64 - 1 - x, so ~(total_bytes >> 6) is the maximal seek position. */
+ uint64_t seek = provider.ConsumeIntegralInRange<uint64_t>(0, ~(total_bytes >> 6));
+
+ // Initialize two ChaCha20 ciphers, with the same key/iv/position.
+ ChaCha20 crypt1(key);
+ ChaCha20 crypt2(key);
+ crypt1.SetIV(iv);
+ crypt1.Seek64(seek);
+ crypt2.SetIV(iv);
+ crypt2.Seek64(seek);
+
+ // Construct vectors with data.
+ std::vector<unsigned char> data1, data2;
+ data1.resize(total_bytes);
+ data2.resize(total_bytes);
+
+ // If using Crypt(), initialize data1 and data2 with the same Xoroshiro128++ based
+ // stream.
+ if constexpr (UseCrypt) {
+ uint64_t seed = provider.ConsumeIntegral<uint64_t>();
+ XoRoShiRo128PlusPlus rng(seed);
+ uint64_t bytes = 0;
+ while (bytes < (total_bytes & ~uint64_t{7})) {
+ uint64_t val = rng();
+ WriteLE64(data1.data() + bytes, val);
+ WriteLE64(data2.data() + bytes, val);
+ bytes += 8;
+ }
+ if (bytes < total_bytes) {
+ unsigned char valbytes[8];
+ uint64_t val = rng();
+ WriteLE64(valbytes, val);
+ std::copy(valbytes, valbytes + (total_bytes - bytes), data1.data() + bytes);
+ std::copy(valbytes, valbytes + (total_bytes - bytes), data2.data() + bytes);
+ }
+ }
+
+ // Whether UseCrypt is used or not, the two byte arrays must match.
+ assert(data1 == data2);
+
+ // Encrypt data1, the whole array at once.
+ if constexpr (UseCrypt) {
+ crypt1.Crypt(data1.data(), data1.data(), total_bytes);
+ } else {
+ crypt1.Keystream(data1.data(), total_bytes);
+ }
+
+ // Encrypt data2, in at most 256 chunks.
+ uint64_t bytes2 = 0;
+ int iter = 0;
+ while (true) {
+ bool is_last = (iter == 255) || (bytes2 == total_bytes) || provider.ConsumeBool();
+ ++iter;
+ // Determine how many bytes to encrypt in this chunk: a fuzzer-determined
+ // amount for all but the last chunk (which processes all remaining bytes).
+ uint64_t now = is_last ? total_bytes - bytes2 :
+ provider.ConsumeIntegralInRange<uint64_t>(0, total_bytes - bytes2);
+ // For each chunk, consider using Crypt() even when UseCrypt is false.
+ // This tests that Keystream() has the same behavior as Crypt() applied
+ // to 0x00 input bytes.
+ if (UseCrypt || provider.ConsumeBool()) {
+ crypt2.Crypt(data2.data() + bytes2, data2.data() + bytes2, now);
+ } else {
+ crypt2.Keystream(data2.data() + bytes2, now);
+ }
+ bytes2 += now;
+ if (is_last) break;
+ }
+ // We should have processed everything now.
+ assert(bytes2 == total_bytes);
+ // And the result should match.
+ assert(data1 == data2);
+}
+
+} // namespace
+
+FUZZ_TARGET(chacha20_split_crypt)
+{
+ FuzzedDataProvider provider{buffer.data(), buffer.size()};
+ ChaCha20SplitFuzz<true>(provider);
+}
+
+FUZZ_TARGET(chacha20_split_keystream)
+{
+ FuzzedDataProvider provider{buffer.data(), buffer.size()};
+ ChaCha20SplitFuzz<false>(provider);
+}
diff --git a/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp b/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp
index 1b89d55773..78fee48de6 100644
--- a/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp
+++ b/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp
@@ -267,32 +267,33 @@ void ECRYPT_keystream_bytes(ECRYPT_ctx* x, u8* stream, u32 bytes)
FUZZ_TARGET(crypto_diff_fuzz_chacha20)
{
+ static const unsigned char ZEROKEY[32] = {0};
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
ChaCha20 chacha20;
ECRYPT_ctx ctx;
- // D. J. Bernstein doesn't initialise ctx to 0 while Bitcoin Core initialises chacha20 to 0 in the constructor
- for (int i = 0; i < 16; i++) {
- ctx.input[i] = 0;
- }
if (fuzzed_data_provider.ConsumeBool()) {
- const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32));
- chacha20 = ChaCha20{key.data(), key.size()};
+ const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
+ chacha20 = ChaCha20{key.data()};
ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0);
- // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey() does
- uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
- ECRYPT_ivsetup(&ctx, iv);
+ } else {
+ // The default ChaCha20 constructor is equivalent to using the all-0 key.
+ ECRYPT_keysetup(&ctx, ZEROKEY, 256, 0);
}
+ // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey32() does
+ static const uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ ECRYPT_ivsetup(&ctx, iv);
+
LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 3000) {
CallOneOf(
fuzzed_data_provider,
[&] {
- const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32));
- chacha20.SetKey(key.data(), key.size());
+ const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
+ chacha20.SetKey32(key.data());
ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0);
- // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey() does
+ // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey32() does
uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
ECRYPT_ivsetup(&ctx, iv);
},
@@ -304,26 +305,32 @@ FUZZ_TARGET(crypto_diff_fuzz_chacha20)
},
[&] {
uint64_t counter = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
- chacha20.Seek(counter);
+ chacha20.Seek64(counter);
ctx.input[12] = counter;
ctx.input[13] = counter >> 32;
},
[&] {
uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
+ // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that.
+ uint64_t pos = ctx.input[12] + (((uint64_t)ctx.input[13]) << 32) + ((integralInRange + 63) >> 6);
std::vector<uint8_t> output(integralInRange);
chacha20.Keystream(output.data(), output.size());
std::vector<uint8_t> djb_output(integralInRange);
ECRYPT_keystream_bytes(&ctx, djb_output.data(), djb_output.size());
assert(output == djb_output);
+ chacha20.Seek64(pos);
},
[&] {
uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
+ // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that.
+ uint64_t pos = ctx.input[12] + (((uint64_t)ctx.input[13]) << 32) + ((integralInRange + 63) >> 6);
std::vector<uint8_t> output(integralInRange);
const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size());
chacha20.Crypt(input.data(), output.data(), input.size());
std::vector<uint8_t> djb_output(integralInRange);
ECRYPT_encrypt_bytes(&ctx, input.data(), djb_output.data(), input.size());
assert(output == djb_output);
+ chacha20.Seek64(pos);
});
}
}
diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp
index f5f86a574a..1f5601ca9f 100644
--- a/src/test/fuzz/descriptor_parse.cpp
+++ b/src/test/fuzz/descriptor_parse.cpp
@@ -9,7 +9,6 @@
void initialize_descriptor_parse()
{
- static const ECCVerifyHandle verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::MAIN);
}
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index 0a7d0c55bd..7cd78e0461 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -46,9 +46,6 @@ void initialize_deserialize()
{
static const auto testing_setup = MakeNoLogFileContext<>();
g_setup = testing_setup.get();
-
- // Fuzzers using pubkey must hold an ECCVerifyHandle.
- static const ECCVerifyHandle verify_handle;
}
#define FUZZ_TARGET_DESERIALIZE(name, code) \
diff --git a/src/test/fuzz/eval_script.cpp b/src/test/fuzz/eval_script.cpp
index e7c49c2dbc..d762676c3c 100644
--- a/src/test/fuzz/eval_script.cpp
+++ b/src/test/fuzz/eval_script.cpp
@@ -9,12 +9,7 @@
#include <limits>
-void initialize_eval_script()
-{
- static const ECCVerifyHandle verify_handle;
-}
-
-FUZZ_TARGET_INIT(eval_script, initialize_eval_script)
+FUZZ_TARGET(eval_script)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp
index 24ae34bd9e..9683f32d84 100644
--- a/src/test/fuzz/fuzz.cpp
+++ b/src/test/fuzz/fuzz.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/golomb_rice.cpp b/src/test/fuzz/golomb_rice.cpp
index b4bb4c6dc6..1a1225b635 100644
--- a/src/test/fuzz/golomb_rice.cpp
+++ b/src/test/fuzz/golomb_rice.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/hex.cpp b/src/test/fuzz/hex.cpp
index e637975b48..f67b820d11 100644
--- a/src/test/fuzz/hex.cpp
+++ b/src/test/fuzz/hex.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,12 +16,7 @@
#include <string>
#include <vector>
-void initialize_hex()
-{
- static const ECCVerifyHandle verify_handle;
-}
-
-FUZZ_TARGET_INIT(hex, initialize_hex)
+FUZZ_TARGET(hex)
{
const std::string random_hex_string(buffer.begin(), buffer.end());
const std::vector<unsigned char> data = ParseHex(random_hex_string);
diff --git a/src/test/fuzz/http_request.cpp b/src/test/fuzz/http_request.cpp
index 0fe18abaa9..9928c4a1ab 100644
--- a/src/test/fuzz/http_request.cpp
+++ b/src/test/fuzz/http_request.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -59,7 +59,7 @@ FUZZ_TARGET(http_request)
const std::string body = http_request.ReadBody();
assert(body.empty());
const CService service = http_request.GetPeer();
- assert(service.ToString() == "[::]:0");
+ assert(service.ToStringAddrPort() == "[::]:0");
evbuffer_free(evbuf);
evhttp_request_free(evreq);
diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp
index fb6d23aca5..6c2321cd68 100644
--- a/src/test/fuzz/i2p.cpp
+++ b/src/test/fuzz/i2p.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,9 +8,10 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
-#include <threadinterrupt.h>
#include <util/system.h>
+#include <util/threadinterrupt.h>
void initialize_i2p()
{
diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp
index f05248ab47..c0aefe6067 100644
--- a/src/test/fuzz/integer.cpp
+++ b/src/test/fuzz/integer.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -152,7 +152,7 @@ FUZZ_TARGET_INIT(integer, initialize_integer)
const CScriptID script_id{u160};
{
- CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION);
+ DataStream stream{};
uint256 deserialized_u256;
stream << u256;
@@ -217,7 +217,7 @@ FUZZ_TARGET_INIT(integer, initialize_integer)
}
{
- CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION);
+ DataStream stream{};
ser_writedata64(stream, u64);
const uint64_t deserialized_u64 = ser_readdata64(stream);
@@ -245,7 +245,7 @@ FUZZ_TARGET_INIT(integer, initialize_integer)
}
{
- CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION);
+ DataStream stream{};
WriteCompactSize(stream, u64);
try {
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index a76901e473..ea6883c08d 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -27,7 +27,6 @@
void initialize_key()
{
- static const ECCVerifyHandle ecc_verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::REGTEST);
}
@@ -112,7 +111,7 @@ FUZZ_TARGET_INIT(key, initialize_key)
}
{
- CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION};
+ DataStream data_stream{};
pubkey.Serialize(data_stream);
CPubKey pubkey_deserialized;
diff --git a/src/test/fuzz/key_io.cpp b/src/test/fuzz/key_io.cpp
index 32a81c2e17..29c6996365 100644
--- a/src/test/fuzz/key_io.cpp
+++ b/src/test/fuzz/key_io.cpp
@@ -13,7 +13,6 @@
void initialize_key_io()
{
- static const ECCVerifyHandle verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::MAIN);
}
diff --git a/src/test/fuzz/message.cpp b/src/test/fuzz/message.cpp
index 06cd0afe2a..63e24aacdd 100644
--- a/src/test/fuzz/message.cpp
+++ b/src/test/fuzz/message.cpp
@@ -18,7 +18,6 @@
void initialize_message()
{
- static const ECCVerifyHandle ecc_verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::REGTEST);
}
diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp
index 6be75322b4..6ea8a3f185 100644
--- a/src/test/fuzz/miniscript.cpp
+++ b/src/test/fuzz/miniscript.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,14 +14,25 @@
namespace {
-//! Some pre-computed data for more efficient string roundtrips.
+//! Some pre-computed data for more efficient string roundtrips and to simulate challenges.
struct TestData {
typedef CPubKey Key;
- // Precomputed public keys.
+ // Precomputed public keys, and a dummy signature for each of them.
std::vector<Key> dummy_keys;
std::map<Key, int> dummy_key_idx_map;
std::map<CKeyID, Key> dummy_keys_map;
+ std::map<Key, std::pair<std::vector<unsigned char>, bool>> dummy_sigs;
+
+ // Precomputed hashes of each kind.
+ std::vector<std::vector<unsigned char>> sha256;
+ std::vector<std::vector<unsigned char>> ripemd160;
+ std::vector<std::vector<unsigned char>> hash256;
+ std::vector<std::vector<unsigned char>> hash160;
+ std::map<std::vector<unsigned char>, std::vector<unsigned char>> sha256_preimages;
+ std::map<std::vector<unsigned char>, std::vector<unsigned char>> ripemd160_preimages;
+ std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash256_preimages;
+ std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash160_preimages;
//! Set the precomputed data.
void Init() {
@@ -35,6 +46,28 @@ struct TestData {
dummy_keys.push_back(pubkey);
dummy_key_idx_map.emplace(pubkey, i);
dummy_keys_map.insert({pubkey.GetID(), pubkey});
+
+ std::vector<unsigned char> sig;
+ privkey.Sign(uint256S(""), sig);
+ sig.push_back(1); // SIGHASH_ALL
+ dummy_sigs.insert({pubkey, {sig, i & 1}});
+
+ std::vector<unsigned char> hash;
+ hash.resize(32);
+ CSHA256().Write(keydata, 32).Finalize(hash.data());
+ sha256.push_back(hash);
+ if (i & 1) sha256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
+ CHash256().Write(keydata).Finalize(hash);
+ hash256.push_back(hash);
+ if (i & 1) hash256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
+ hash.resize(20);
+ CRIPEMD160().Write(keydata, 32).Finalize(hash.data());
+ assert(hash.size() == 20);
+ ripemd160.push_back(hash);
+ if (i & 1) ripemd160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
+ CHash160().Write(keydata).Finalize(hash);
+ hash160.push_back(hash);
+ if (i & 1) hash160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
}
}
} TEST_DATA;
@@ -59,6 +92,17 @@ struct ParserContext {
return HexStr(Span{&idx, 1});
}
+ std::vector<unsigned char> ToPKBytes(const Key& key) const
+ {
+ return {key.begin(), key.end()};
+ }
+
+ std::vector<unsigned char> ToPKHBytes(const Key& key) const
+ {
+ const auto h = Hash160(key);
+ return {h.begin(), h.end()};
+ }
+
template<typename I>
std::optional<Key> FromString(I first, I last) const {
if (last - first != 2) return {};
@@ -69,7 +113,7 @@ struct ParserContext {
template<typename I>
std::optional<Key> FromPKBytes(I first, I last) const {
- Key key;
+ CPubKey key;
key.Set(first, last);
if (!key.IsValid()) return {};
return key;
@@ -104,7 +148,7 @@ struct ScriptParserContext {
return key.data;
}
- const std::vector<unsigned char> ToPKHBytes(const Key& key) const
+ std::vector<unsigned char> ToPKHBytes(const Key& key) const
{
if (key.is_hash) return key.data;
const auto h = Hash160(key.data);
@@ -130,6 +174,877 @@ struct ScriptParserContext {
}
} SCRIPT_PARSER_CONTEXT;
+//! Context to produce a satisfaction for a Miniscript node using the pre-computed data.
+struct SatisfierContext: ParserContext {
+ // Timelock challenges satisfaction. Make the value (deterministically) vary to explore different
+ // paths.
+ bool CheckAfter(uint32_t value) const { return value % 2; }
+ bool CheckOlder(uint32_t value) const { return value % 2; }
+
+ // Signature challenges fulfilled with a dummy signature, if it was one of our dummy keys.
+ miniscript::Availability Sign(const CPubKey& key, std::vector<unsigned char>& sig) const {
+ const auto it = TEST_DATA.dummy_sigs.find(key);
+ if (it == TEST_DATA.dummy_sigs.end()) return miniscript::Availability::NO;
+ if (it->second.second) {
+ // Key is "available"
+ sig = it->second.first;
+ return miniscript::Availability::YES;
+ } else {
+ return miniscript::Availability::NO;
+ }
+ }
+
+ //! Lookup generalization for all the hash satisfactions below
+ miniscript::Availability LookupHash(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage,
+ const std::map<std::vector<unsigned char>, std::vector<unsigned char>>& map) const
+ {
+ const auto it = map.find(hash);
+ if (it == map.end()) return miniscript::Availability::NO;
+ preimage = it->second;
+ return miniscript::Availability::YES;
+ }
+ miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
+ return LookupHash(hash, preimage, TEST_DATA.sha256_preimages);
+ }
+ miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
+ return LookupHash(hash, preimage, TEST_DATA.ripemd160_preimages);
+ }
+ miniscript::Availability SatHASH256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
+ return LookupHash(hash, preimage, TEST_DATA.hash256_preimages);
+ }
+ miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
+ return LookupHash(hash, preimage, TEST_DATA.hash160_preimages);
+ }
+} SATISFIER_CTX;
+
+//! Context to check a satisfaction against the pre-computed data.
+struct CheckerContext: BaseSignatureChecker {
+ TestData *test_data;
+
+ // Signature checker methods. Checks the right dummy signature is used.
+ bool CheckECDSASignature(const std::vector<unsigned char>& sig, const std::vector<unsigned char>& vchPubKey,
+ const CScript& scriptCode, SigVersion sigversion) const override
+ {
+ const CPubKey key{vchPubKey};
+ const auto it = TEST_DATA.dummy_sigs.find(key);
+ if (it == TEST_DATA.dummy_sigs.end()) return false;
+ return it->second.first == sig;
+ }
+ bool CheckLockTime(const CScriptNum& nLockTime) const override { return nLockTime.GetInt64() & 1; }
+ bool CheckSequence(const CScriptNum& nSequence) const override { return nSequence.GetInt64() & 1; }
+} CHECKER_CTX;
+
+//! Context to check for duplicates when instancing a Node.
+struct KeyComparator {
+ bool KeyCompare(const CPubKey& a, const CPubKey& b) const {
+ return a < b;
+ }
+} KEY_COMP;
+
+// A dummy scriptsig to pass to VerifyScript (we always use Segwit v0).
+const CScript DUMMY_SCRIPTSIG;
+
+using Fragment = miniscript::Fragment;
+using NodeRef = miniscript::NodeRef<CPubKey>;
+using Node = miniscript::Node<CPubKey>;
+using Type = miniscript::Type;
+// https://github.com/llvm/llvm-project/issues/53444
+// NOLINTNEXTLINE(misc-unused-using-decls)
+using miniscript::operator"" _mst;
+
+//! Construct a miniscript node as a shared_ptr.
+template<typename... Args> NodeRef MakeNodeRef(Args&&... args) {
+ return miniscript::MakeNodeRef<CPubKey>(miniscript::internal::NoDupCheck{}, std::forward<Args>(args)...);
+}
+
+/** Information about a yet to be constructed Miniscript node. */
+struct NodeInfo {
+ //! The type of this node
+ Fragment fragment;
+ //! The timelock value for older() and after(), the threshold value for multi() and thresh()
+ uint32_t k;
+ //! Keys for this node, if it has some
+ std::vector<CPubKey> keys;
+ //! The hash value for this node, if it has one
+ std::vector<unsigned char> hash;
+ //! The type requirements for the children of this node.
+ std::vector<Type> subtypes;
+
+ NodeInfo(Fragment frag): fragment(frag), k(0) {}
+ NodeInfo(Fragment frag, CPubKey key): fragment(frag), k(0), keys({key}) {}
+ NodeInfo(Fragment frag, uint32_t _k): fragment(frag), k(_k) {}
+ NodeInfo(Fragment frag, std::vector<unsigned char> h): fragment(frag), k(0), hash(std::move(h)) {}
+ NodeInfo(std::vector<Type> subt, Fragment frag): fragment(frag), k(0), subtypes(std::move(subt)) {}
+ NodeInfo(std::vector<Type> subt, Fragment frag, uint32_t _k): fragment(frag), k(_k), subtypes(std::move(subt)) {}
+ NodeInfo(Fragment frag, uint32_t _k, std::vector<CPubKey> _keys): fragment(frag), k(_k), keys(std::move(_keys)) {}
+};
+
+/** Pick an index in a collection from a single byte in the fuzzer's output. */
+template<typename T, typename A>
+T ConsumeIndex(FuzzedDataProvider& provider, A& col) {
+ const uint8_t i = provider.ConsumeIntegral<uint8_t>();
+ return col[i];
+}
+
+CPubKey ConsumePubKey(FuzzedDataProvider& provider) {
+ return ConsumeIndex<CPubKey>(provider, TEST_DATA.dummy_keys);
+}
+
+std::vector<unsigned char> ConsumeSha256(FuzzedDataProvider& provider) {
+ return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.sha256);
+}
+
+std::vector<unsigned char> ConsumeHash256(FuzzedDataProvider& provider) {
+ return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.hash256);
+}
+
+std::vector<unsigned char> ConsumeRipemd160(FuzzedDataProvider& provider) {
+ return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.ripemd160);
+}
+
+std::vector<unsigned char> ConsumeHash160(FuzzedDataProvider& provider) {
+ return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.hash160);
+}
+
+std::optional<uint32_t> ConsumeTimeLock(FuzzedDataProvider& provider) {
+ const uint32_t k = provider.ConsumeIntegral<uint32_t>();
+ if (k == 0 || k >= 0x80000000) return {};
+ return k;
+}
+
+/**
+ * Consume a Miniscript node from the fuzzer's output.
+ *
+ * This version is intended to have a fixed, stable, encoding for Miniscript nodes:
+ * - The first byte sets the type of the fragment. 0, 1 and all non-leaf fragments but thresh() are a
+ * single byte.
+ * - For the other leaf fragments, the following bytes depend on their type.
+ * - For older() and after(), the next 4 bytes define the timelock value.
+ * - For pk_k(), pk_h(), and all hashes, the next byte defines the index of the value in the test data.
+ * - For multi(), the next 2 bytes define respectively the threshold and the number of keys. Then as many
+ * bytes as the number of keys define the index of each key in the test data.
+ * - For thresh(), the next byte defines the threshold value and the following one the number of subs.
+ */
+std::optional<NodeInfo> ConsumeNodeStable(FuzzedDataProvider& provider, Type type_needed) {
+ bool allow_B = (type_needed == ""_mst) || (type_needed << "B"_mst);
+ bool allow_K = (type_needed == ""_mst) || (type_needed << "K"_mst);
+ bool allow_V = (type_needed == ""_mst) || (type_needed << "V"_mst);
+ bool allow_W = (type_needed == ""_mst) || (type_needed << "W"_mst);
+
+ switch (provider.ConsumeIntegral<uint8_t>()) {
+ case 0:
+ if (!allow_B) return {};
+ return {{Fragment::JUST_0}};
+ case 1:
+ if (!allow_B) return {};
+ return {{Fragment::JUST_1}};
+ case 2:
+ if (!allow_K) return {};
+ return {{Fragment::PK_K, ConsumePubKey(provider)}};
+ case 3:
+ if (!allow_K) return {};
+ return {{Fragment::PK_H, ConsumePubKey(provider)}};
+ case 4: {
+ if (!allow_B) return {};
+ const auto k = ConsumeTimeLock(provider);
+ if (!k) return {};
+ return {{Fragment::OLDER, *k}};
+ }
+ case 5: {
+ if (!allow_B) return {};
+ const auto k = ConsumeTimeLock(provider);
+ if (!k) return {};
+ return {{Fragment::AFTER, *k}};
+ }
+ case 6:
+ if (!allow_B) return {};
+ return {{Fragment::SHA256, ConsumeSha256(provider)}};
+ case 7:
+ if (!allow_B) return {};
+ return {{Fragment::HASH256, ConsumeHash256(provider)}};
+ case 8:
+ if (!allow_B) return {};
+ return {{Fragment::RIPEMD160, ConsumeRipemd160(provider)}};
+ case 9:
+ if (!allow_B) return {};
+ return {{Fragment::HASH160, ConsumeHash160(provider)}};
+ case 10: {
+ if (!allow_B) return {};
+ const auto k = provider.ConsumeIntegral<uint8_t>();
+ const auto n_keys = provider.ConsumeIntegral<uint8_t>();
+ if (n_keys > 20 || k == 0 || k > n_keys) return {};
+ std::vector<CPubKey> keys{n_keys};
+ for (auto& key: keys) key = ConsumePubKey(provider);
+ return {{Fragment::MULTI, k, std::move(keys)}};
+ }
+ case 11:
+ if (!(allow_B || allow_K || allow_V)) return {};
+ return {{{"B"_mst, type_needed, type_needed}, Fragment::ANDOR}};
+ case 12:
+ if (!(allow_B || allow_K || allow_V)) return {};
+ return {{{"V"_mst, type_needed}, Fragment::AND_V}};
+ case 13:
+ if (!allow_B) return {};
+ return {{{"B"_mst, "W"_mst}, Fragment::AND_B}};
+ case 15:
+ if (!allow_B) return {};
+ return {{{"B"_mst, "W"_mst}, Fragment::OR_B}};
+ case 16:
+ if (!allow_V) return {};
+ return {{{"B"_mst, "V"_mst}, Fragment::OR_C}};
+ case 17:
+ if (!allow_B) return {};
+ return {{{"B"_mst, "B"_mst}, Fragment::OR_D}};
+ case 18:
+ if (!(allow_B || allow_K || allow_V)) return {};
+ return {{{type_needed, type_needed}, Fragment::OR_I}};
+ case 19: {
+ if (!allow_B) return {};
+ auto k = provider.ConsumeIntegral<uint8_t>();
+ auto n_subs = provider.ConsumeIntegral<uint8_t>();
+ if (k == 0 || k > n_subs) return {};
+ std::vector<Type> subtypes;
+ subtypes.reserve(n_subs);
+ subtypes.emplace_back("B"_mst);
+ for (size_t i = 1; i < n_subs; ++i) subtypes.emplace_back("W"_mst);
+ return {{std::move(subtypes), Fragment::THRESH, k}};
+ }
+ case 20:
+ if (!allow_W) return {};
+ return {{{"B"_mst}, Fragment::WRAP_A}};
+ case 21:
+ if (!allow_W) return {};
+ return {{{"B"_mst}, Fragment::WRAP_S}};
+ case 22:
+ if (!allow_B) return {};
+ return {{{"K"_mst}, Fragment::WRAP_C}};
+ case 23:
+ if (!allow_B) return {};
+ return {{{"V"_mst}, Fragment::WRAP_D}};
+ case 24:
+ if (!allow_V) return {};
+ return {{{"B"_mst}, Fragment::WRAP_V}};
+ case 25:
+ if (!allow_B) return {};
+ return {{{"B"_mst}, Fragment::WRAP_J}};
+ case 26:
+ if (!allow_B) return {};
+ return {{{"B"_mst}, Fragment::WRAP_N}};
+ default:
+ break;
+ }
+ return {};
+}
+
+/* This structure contains a table which for each "target" Type a list of recipes
+ * to construct it, automatically inferred from the behavior of ComputeType.
+ * Note that the Types here are not the final types of the constructed Nodes, but
+ * just the subset that are required. For example, a recipe for the "Bo" type
+ * might construct a "Bondu" sha256() NodeInfo, but cannot construct a "Bz" older().
+ * Each recipe is a Fragment together with a list of required types for its subnodes.
+ */
+struct SmartInfo
+{
+ using recipe = std::pair<Fragment, std::vector<Type>>;
+ std::map<Type, std::vector<recipe>> table;
+
+ void Init()
+ {
+ /* Construct a set of interesting type requirements to reason with (sections of BKVWzondu). */
+ std::vector<Type> types;
+ for (int base = 0; base < 4; ++base) { /* select from B,K,V,W */
+ Type type_base = base == 0 ? "B"_mst : base == 1 ? "K"_mst : base == 2 ? "V"_mst : "W"_mst;
+ for (int zo = 0; zo < 3; ++zo) { /* select from z,o,(none) */
+ Type type_zo = zo == 0 ? "z"_mst : zo == 1 ? "o"_mst : ""_mst;
+ for (int n = 0; n < 2; ++n) { /* select from (none),n */
+ if (zo == 0 && n == 1) continue; /* z conflicts with n */
+ if (base == 3 && n == 1) continue; /* W conflicts with n */
+ Type type_n = n == 0 ? ""_mst : "n"_mst;
+ for (int d = 0; d < 2; ++d) { /* select from (none),d */
+ if (base == 2 && d == 1) continue; /* V conflicts with d */
+ Type type_d = d == 0 ? ""_mst : "d"_mst;
+ for (int u = 0; u < 2; ++u) { /* select from (none),u */
+ if (base == 2 && u == 1) continue; /* V conflicts with u */
+ Type type_u = u == 0 ? ""_mst : "u"_mst;
+ Type type = type_base | type_zo | type_n | type_d | type_u;
+ types.push_back(type);
+ }
+ }
+ }
+ }
+ }
+
+ /* We define a recipe a to be a super-recipe of recipe b if they use the same
+ * fragment, the same number of subexpressions, and each of a's subexpression
+ * types is a supertype of the corresponding subexpression type of b.
+ * Within the set of recipes for the construction of a given type requirement,
+ * no recipe should be a super-recipe of another (as the super-recipe is
+ * applicable in every place the sub-recipe is, the sub-recipe is redundant). */
+ auto is_super_of = [](const recipe& a, const recipe& b) {
+ if (a.first != b.first) return false;
+ if (a.second.size() != b.second.size()) return false;
+ for (size_t i = 0; i < a.second.size(); ++i) {
+ if (!(b.second[i] << a.second[i])) return false;
+ }
+ return true;
+ };
+
+ /* Sort the type requirements. Subtypes will always sort later (e.g. Bondu will
+ * sort after Bo or Bu). As we'll be constructing recipes using these types, in
+ * order, in what follows, we'll construct super-recipes before sub-recipes.
+ * That means we never need to go back and delete a sub-recipe because a
+ * super-recipe got added. */
+ std::sort(types.begin(), types.end());
+
+ // Iterate over all possible fragments.
+ for (int fragidx = 0; fragidx <= int(Fragment::MULTI); ++fragidx) {
+ int sub_count = 0; //!< The minimum number of child nodes this recipe has.
+ int sub_range = 1; //!< The maximum number of child nodes for this recipe is sub_count+sub_range-1.
+ size_t data_size = 0;
+ size_t n_keys = 0;
+ uint32_t k = 0;
+ Fragment frag{fragidx};
+
+ // Based on the fragment, determine #subs/data/k/keys to pass to ComputeType. */
+ switch (frag) {
+ case Fragment::PK_K:
+ case Fragment::PK_H:
+ n_keys = 1;
+ break;
+ case Fragment::MULTI:
+ n_keys = 1;
+ k = 1;
+ break;
+ case Fragment::OLDER:
+ case Fragment::AFTER:
+ k = 1;
+ break;
+ case Fragment::SHA256:
+ case Fragment::HASH256:
+ data_size = 32;
+ break;
+ case Fragment::RIPEMD160:
+ case Fragment::HASH160:
+ data_size = 20;
+ break;
+ case Fragment::JUST_0:
+ case Fragment::JUST_1:
+ break;
+ case Fragment::WRAP_A:
+ case Fragment::WRAP_S:
+ case Fragment::WRAP_C:
+ case Fragment::WRAP_D:
+ case Fragment::WRAP_V:
+ case Fragment::WRAP_J:
+ case Fragment::WRAP_N:
+ sub_count = 1;
+ break;
+ case Fragment::AND_V:
+ case Fragment::AND_B:
+ case Fragment::OR_B:
+ case Fragment::OR_C:
+ case Fragment::OR_D:
+ case Fragment::OR_I:
+ sub_count = 2;
+ break;
+ case Fragment::ANDOR:
+ sub_count = 3;
+ break;
+ case Fragment::THRESH:
+ // Thresh logic is executed for 1 and 2 arguments. Larger numbers use ad-hoc code to extend.
+ sub_count = 1;
+ sub_range = 2;
+ k = 1;
+ break;
+ }
+
+ // Iterate over the number of subnodes (sub_count...sub_count+sub_range-1).
+ std::vector<Type> subt;
+ for (int subs = sub_count; subs < sub_count + sub_range; ++subs) {
+ // Iterate over the possible subnode types (at most 3).
+ for (Type x : types) {
+ for (Type y : types) {
+ for (Type z : types) {
+ // Compute the resulting type of a node with the selected fragment / subnode types.
+ subt.clear();
+ if (subs > 0) subt.push_back(x);
+ if (subs > 1) subt.push_back(y);
+ if (subs > 2) subt.push_back(z);
+ Type res = miniscript::internal::ComputeType(frag, x, y, z, subt, k, data_size, subs, n_keys);
+ // Continue if the result is not a valid node.
+ if ((res << "K"_mst) + (res << "V"_mst) + (res << "B"_mst) + (res << "W"_mst) != 1) continue;
+
+ recipe entry{frag, subt};
+ auto super_of_entry = [&](const recipe& rec) { return is_super_of(rec, entry); };
+ // Iterate over all supertypes of res (because if e.g. our selected fragment/subnodes result
+ // in a Bondu, they can form a recipe that is also applicable for constructing a B, Bou, Bdu, ...).
+ for (Type s : types) {
+ if ((res & "BKVWzondu"_mst) << s) {
+ auto& recipes = table[s];
+ // If we don't already have a super-recipe to the new one, add it.
+ if (!std::any_of(recipes.begin(), recipes.end(), super_of_entry)) {
+ recipes.push_back(entry);
+ }
+ }
+ }
+
+ if (subs <= 2) break;
+ }
+ if (subs <= 1) break;
+ }
+ if (subs <= 0) break;
+ }
+ }
+ }
+
+ /* Find which types are useful. The fuzzer logic only cares about constructing
+ * B,V,K,W nodes, so any type that isn't needed in any recipe (directly or
+ * indirectly) for the construction of those is uninteresting. */
+ std::set<Type> useful_types{"B"_mst, "V"_mst, "K"_mst, "W"_mst};
+ // Find the transitive closure by adding types until the set of types does not change.
+ while (true) {
+ size_t set_size = useful_types.size();
+ for (const auto& [type, recipes] : table) {
+ if (useful_types.count(type) != 0) {
+ for (const auto& [_, subtypes] : recipes) {
+ for (auto subtype : subtypes) useful_types.insert(subtype);
+ }
+ }
+ }
+ if (useful_types.size() == set_size) break;
+ }
+ // Remove all rules that construct uninteresting types.
+ for (auto type_it = table.begin(); type_it != table.end();) {
+ if (useful_types.count(type_it->first) == 0) {
+ type_it = table.erase(type_it);
+ } else {
+ ++type_it;
+ }
+ }
+
+ /* Find which types are constructible. A type is constructible if there is a leaf
+ * node recipe for constructing it, or a recipe whose subnodes are all constructible.
+ * Types can be non-constructible because they have no recipes to begin with,
+ * because they can only be constructed using recipes that involve otherwise
+ * non-constructible types, or because they require infinite recursion. */
+ std::set<Type> constructible_types{};
+ auto known_constructible = [&](Type type) { return constructible_types.count(type) != 0; };
+ // Find the transitive closure by adding types until the set of types does not change.
+ while (true) {
+ size_t set_size = constructible_types.size();
+ // Iterate over all types we have recipes for.
+ for (const auto& [type, recipes] : table) {
+ if (!known_constructible(type)) {
+ // For not (yet known to be) constructible types, iterate over their recipes.
+ for (const auto& [_, subt] : recipes) {
+ // If any recipe involves only (already known to be) constructible types,
+ // add the recipe's type to the set.
+ if (std::all_of(subt.begin(), subt.end(), known_constructible)) {
+ constructible_types.insert(type);
+ break;
+ }
+ }
+ }
+ }
+ if (constructible_types.size() == set_size) break;
+ }
+ for (auto type_it = table.begin(); type_it != table.end();) {
+ // Remove all recipes which involve non-constructible types.
+ type_it->second.erase(std::remove_if(type_it->second.begin(), type_it->second.end(),
+ [&](const recipe& rec) {
+ return !std::all_of(rec.second.begin(), rec.second.end(), known_constructible);
+ }), type_it->second.end());
+ // Delete types entirely which have no recipes left.
+ if (type_it->second.empty()) {
+ type_it = table.erase(type_it);
+ } else {
+ ++type_it;
+ }
+ }
+
+ for (auto& [type, recipes] : table) {
+ // Sort recipes for determinism, and place those using fewer subnodes first.
+ // This avoids runaway expansion (when reaching the end of the fuzz input,
+ // all zeroes are read, resulting in the first available recipe being picked).
+ std::sort(recipes.begin(), recipes.end(),
+ [](const recipe& a, const recipe& b) {
+ if (a.second.size() < b.second.size()) return true;
+ if (a.second.size() > b.second.size()) return false;
+ return a < b;
+ }
+ );
+ }
+ }
+} SMARTINFO;
+
+/**
+ * Consume a Miniscript node from the fuzzer's output.
+ *
+ * This is similar to ConsumeNodeStable, but uses a precomputed table with permitted
+ * fragments/subnode type for each required type. It is intended to more quickly explore
+ * interesting miniscripts, at the cost of higher implementation complexity (which could
+ * cause it miss things if incorrect), and with less regard for stability of the seeds
+ * (as improvements to the tables or changes to the typing rules could invalidate
+ * everything).
+ */
+std::optional<NodeInfo> ConsumeNodeSmart(FuzzedDataProvider& provider, Type type_needed) {
+ /** Table entry for the requested type. */
+ auto recipes_it = SMARTINFO.table.find(type_needed);
+ assert(recipes_it != SMARTINFO.table.end());
+ /** Pick one recipe from the available ones for that type. */
+ const auto& [frag, subt] = PickValue(provider, recipes_it->second);
+
+ // Based on the fragment the recipe uses, fill in other data (k, keys, data).
+ switch (frag) {
+ case Fragment::PK_K:
+ case Fragment::PK_H:
+ return {{frag, ConsumePubKey(provider)}};
+ case Fragment::MULTI: {
+ const auto n_keys = provider.ConsumeIntegralInRange<uint8_t>(1, 20);
+ const auto k = provider.ConsumeIntegralInRange<uint8_t>(1, n_keys);
+ std::vector<CPubKey> keys{n_keys};
+ for (auto& key: keys) key = ConsumePubKey(provider);
+ return {{frag, k, std::move(keys)}};
+ }
+ case Fragment::OLDER:
+ case Fragment::AFTER:
+ return {{frag, provider.ConsumeIntegralInRange<uint32_t>(1, 0x7FFFFFF)}};
+ case Fragment::SHA256:
+ return {{frag, PickValue(provider, TEST_DATA.sha256)}};
+ case Fragment::HASH256:
+ return {{frag, PickValue(provider, TEST_DATA.hash256)}};
+ case Fragment::RIPEMD160:
+ return {{frag, PickValue(provider, TEST_DATA.ripemd160)}};
+ case Fragment::HASH160:
+ return {{frag, PickValue(provider, TEST_DATA.hash160)}};
+ case Fragment::JUST_0:
+ case Fragment::JUST_1:
+ case Fragment::WRAP_A:
+ case Fragment::WRAP_S:
+ case Fragment::WRAP_C:
+ case Fragment::WRAP_D:
+ case Fragment::WRAP_V:
+ case Fragment::WRAP_J:
+ case Fragment::WRAP_N:
+ case Fragment::AND_V:
+ case Fragment::AND_B:
+ case Fragment::OR_B:
+ case Fragment::OR_C:
+ case Fragment::OR_D:
+ case Fragment::OR_I:
+ case Fragment::ANDOR:
+ return {{subt, frag}};
+ case Fragment::THRESH: {
+ uint32_t children;
+ if (subt.size() < 2) {
+ children = subt.size();
+ } else {
+ // If we hit a thresh with 2 subnodes, artificially extend it to any number
+ // (2 or larger) by replicating the type of the last subnode.
+ children = provider.ConsumeIntegralInRange<uint32_t>(2, MAX_OPS_PER_SCRIPT / 2);
+ }
+ auto k = provider.ConsumeIntegralInRange<uint32_t>(1, children);
+ std::vector<Type> subs = subt;
+ while (subs.size() < children) subs.push_back(subs.back());
+ return {{std::move(subs), frag, k}};
+ }
+ }
+
+ assert(false);
+}
+
+/**
+ * Generate a Miniscript node based on the fuzzer's input.
+ *
+ * - ConsumeNode is a function object taking a Type, and returning an std::optional<NodeInfo>.
+ * - root_type is the required type properties of the constructed NodeRef.
+ * - strict_valid sets whether ConsumeNode is expected to guarantee a NodeInfo that results in
+ * a NodeRef whose Type() matches the type fed to ConsumeNode.
+ */
+template<typename F>
+NodeRef GenNode(F ConsumeNode, Type root_type, bool strict_valid = false) {
+ /** A stack of miniscript Nodes being built up. */
+ std::vector<NodeRef> stack;
+ /** The queue of instructions. */
+ std::vector<std::pair<Type, std::optional<NodeInfo>>> todo{{root_type, {}}};
+ /** Predict the number of (static) script ops. */
+ uint32_t ops{0};
+ /** Predict the total script size (every unexplored subnode is counted as one, as every leaf is
+ * at least one script byte). */
+ uint32_t scriptsize{1};
+
+ while (!todo.empty()) {
+ // The expected type we have to construct.
+ auto type_needed = todo.back().first;
+ if (!todo.back().second) {
+ // Fragment/children have not been decided yet. Decide them.
+ auto node_info = ConsumeNode(type_needed);
+ if (!node_info) return {};
+ // Update predicted resource limits. Since every leaf Miniscript node is at least one
+ // byte long, we move one byte from each child to their parent. A similar technique is
+ // used in the miniscript::internal::Parse function to prevent runaway string parsing.
+ scriptsize += miniscript::internal::ComputeScriptLen(node_info->fragment, ""_mst, node_info->subtypes.size(), node_info->k, node_info->subtypes.size(), node_info->keys.size()) - 1;
+ if (scriptsize > MAX_STANDARD_P2WSH_SCRIPT_SIZE) return {};
+ switch (node_info->fragment) {
+ case Fragment::JUST_0:
+ case Fragment::JUST_1:
+ break;
+ case Fragment::PK_K:
+ break;
+ case Fragment::PK_H:
+ ops += 3;
+ break;
+ case Fragment::OLDER:
+ case Fragment::AFTER:
+ ops += 1;
+ break;
+ case Fragment::RIPEMD160:
+ case Fragment::SHA256:
+ case Fragment::HASH160:
+ case Fragment::HASH256:
+ ops += 4;
+ break;
+ case Fragment::ANDOR:
+ ops += 3;
+ break;
+ case Fragment::AND_V:
+ break;
+ case Fragment::AND_B:
+ case Fragment::OR_B:
+ ops += 1;
+ break;
+ case Fragment::OR_C:
+ ops += 2;
+ break;
+ case Fragment::OR_D:
+ ops += 3;
+ break;
+ case Fragment::OR_I:
+ ops += 3;
+ break;
+ case Fragment::THRESH:
+ ops += node_info->subtypes.size();
+ break;
+ case Fragment::MULTI:
+ ops += 1;
+ break;
+ case Fragment::WRAP_A:
+ ops += 2;
+ break;
+ case Fragment::WRAP_S:
+ ops += 1;
+ break;
+ case Fragment::WRAP_C:
+ ops += 1;
+ break;
+ case Fragment::WRAP_D:
+ ops += 3;
+ break;
+ case Fragment::WRAP_V:
+ // We don't account for OP_VERIFY here; that will be corrected for when the actual
+ // node is constructed below.
+ break;
+ case Fragment::WRAP_J:
+ ops += 4;
+ break;
+ case Fragment::WRAP_N:
+ ops += 1;
+ break;
+ }
+ if (ops > MAX_OPS_PER_SCRIPT) return {};
+ auto subtypes = node_info->subtypes;
+ todo.back().second = std::move(node_info);
+ todo.reserve(todo.size() + subtypes.size());
+ // As elements on the todo stack are processed back to front, construct
+ // them in reverse order (so that the first subnode is generated first).
+ for (size_t i = 0; i < subtypes.size(); ++i) {
+ todo.emplace_back(*(subtypes.rbegin() + i), std::nullopt);
+ }
+ } else {
+ // The back of todo has fragment and number of children decided, and
+ // those children have been constructed at the back of stack. Pop
+ // that entry off todo, and use it to construct a new NodeRef on
+ // stack.
+ NodeInfo& info = *todo.back().second;
+ // Gather children from the back of stack.
+ std::vector<NodeRef> sub;
+ sub.reserve(info.subtypes.size());
+ for (size_t i = 0; i < info.subtypes.size(); ++i) {
+ sub.push_back(std::move(*(stack.end() - info.subtypes.size() + i)));
+ }
+ stack.erase(stack.end() - info.subtypes.size(), stack.end());
+ // Construct new NodeRef.
+ NodeRef node;
+ if (info.keys.empty()) {
+ node = MakeNodeRef(info.fragment, std::move(sub), std::move(info.hash), info.k);
+ } else {
+ assert(sub.empty());
+ assert(info.hash.empty());
+ node = MakeNodeRef(info.fragment, std::move(info.keys), info.k);
+ }
+ // Verify acceptability.
+ if (!node || (node->GetType() & "KVWB"_mst) == ""_mst) {
+ assert(!strict_valid);
+ return {};
+ }
+ if (!(type_needed == ""_mst)) {
+ assert(node->GetType() << type_needed);
+ }
+ if (!node->IsValid()) return {};
+ // Update resource predictions.
+ if (node->fragment == Fragment::WRAP_V && node->subs[0]->GetType() << "x"_mst) {
+ ops += 1;
+ scriptsize += 1;
+ }
+ if (ops > MAX_OPS_PER_SCRIPT) return {};
+ if (scriptsize > MAX_STANDARD_P2WSH_SCRIPT_SIZE) return {};
+ // Move it to the stack.
+ stack.push_back(std::move(node));
+ todo.pop_back();
+ }
+ }
+ assert(stack.size() == 1);
+ assert(stack[0]->GetStaticOps() == ops);
+ assert(stack[0]->ScriptSize() == scriptsize);
+ stack[0]->DuplicateKeyCheck(KEY_COMP);
+ return std::move(stack[0]);
+}
+
+/** Perform various applicable tests on a miniscript Node. */
+void TestNode(const NodeRef& node, FuzzedDataProvider& provider)
+{
+ if (!node) return;
+
+ // Check that it roundtrips to text representation
+ std::optional<std::string> str{node->ToString(PARSER_CTX)};
+ assert(str);
+ auto parsed = miniscript::FromString(*str, PARSER_CTX);
+ assert(parsed);
+ assert(*parsed == *node);
+
+ // Check consistency between script size estimation and real size.
+ auto script = node->ToScript(PARSER_CTX);
+ assert(node->ScriptSize() == script.size());
+
+ // Check consistency of "x" property with the script (type K is excluded, because it can end
+ // with a push of a key, which could match these opcodes).
+ if (!(node->GetType() << "K"_mst)) {
+ bool ends_in_verify = !(node->GetType() << "x"_mst);
+ assert(ends_in_verify == (script.back() == OP_CHECKSIG || script.back() == OP_CHECKMULTISIG || script.back() == OP_EQUAL));
+ }
+
+ // The rest of the checks only apply when testing a valid top-level script.
+ if (!node->IsValidTopLevel()) return;
+
+ // Check roundtrip to script
+ auto decoded = miniscript::FromScript(script, PARSER_CTX);
+ assert(decoded);
+ // Note we can't use *decoded == *node because the miniscript representation may differ, so we check that:
+ // - The script corresponding to that decoded form matches exactly
+ // - The type matches exactly
+ assert(decoded->ToScript(PARSER_CTX) == script);
+ assert(decoded->GetType() == node->GetType());
+
+ if (provider.ConsumeBool() && node->GetOps() < MAX_OPS_PER_SCRIPT && node->ScriptSize() < MAX_STANDARD_P2WSH_SCRIPT_SIZE) {
+ // Optionally pad the script with OP_NOPs to max op the ops limit of the constructed script.
+ // This makes the script obviously not actually miniscript-compatible anymore, but the
+ // signatures constructed in this test don't commit to the script anyway, so the same
+ // miniscript satisfier will work. This increases the sensitivity of the test to the ops
+ // counting logic being too low, especially for simple scripts.
+ // Do this optionally because we're not solely interested in cases where the number of ops is
+ // maximal.
+ // Do not pad more than what would cause MAX_STANDARD_P2WSH_SCRIPT_SIZE to be reached, however,
+ // as that also invalidates scripts.
+ int add = std::min<int>(
+ MAX_OPS_PER_SCRIPT - node->GetOps(),
+ MAX_STANDARD_P2WSH_SCRIPT_SIZE - node->ScriptSize());
+ for (int i = 0; i < add; ++i) script.push_back(OP_NOP);
+ }
+
+ // Run malleable satisfaction algorithm.
+ const CScript script_pubkey = CScript() << OP_0 << WitnessV0ScriptHash(script);
+ CScriptWitness witness_mal;
+ const bool mal_success = node->Satisfy(SATISFIER_CTX, witness_mal.stack, false) == miniscript::Availability::YES;
+ witness_mal.stack.push_back(std::vector<unsigned char>(script.begin(), script.end()));
+
+ // Run non-malleable satisfaction algorithm.
+ CScriptWitness witness_nonmal;
+ const bool nonmal_success = node->Satisfy(SATISFIER_CTX, witness_nonmal.stack, true) == miniscript::Availability::YES;
+ witness_nonmal.stack.push_back(std::vector<unsigned char>(script.begin(), script.end()));
+
+ if (nonmal_success) {
+ // Non-malleable satisfactions are bounded by GetStackSize().
+ assert(witness_nonmal.stack.size() <= node->GetStackSize());
+ // If a non-malleable satisfaction exists, the malleable one must also exist, and be identical to it.
+ assert(mal_success);
+ assert(witness_nonmal.stack == witness_mal.stack);
+
+ // Test non-malleable satisfaction.
+ ScriptError serror;
+ bool res = VerifyScript(DUMMY_SCRIPTSIG, script_pubkey, &witness_nonmal, STANDARD_SCRIPT_VERIFY_FLAGS, CHECKER_CTX, &serror);
+ // Non-malleable satisfactions are guaranteed to be valid if ValidSatisfactions().
+ if (node->ValidSatisfactions()) assert(res);
+ // More detailed: non-malleable satisfactions must be valid, or could fail with ops count error (if CheckOpsLimit failed),
+ // or with a stack size error (if CheckStackSize check failed).
+ assert(res ||
+ (!node->CheckOpsLimit() && serror == ScriptError::SCRIPT_ERR_OP_COUNT) ||
+ (!node->CheckStackSize() && serror == ScriptError::SCRIPT_ERR_STACK_SIZE));
+ }
+
+ if (mal_success && (!nonmal_success || witness_mal.stack != witness_nonmal.stack)) {
+ // Test malleable satisfaction only if it's different from the non-malleable one.
+ ScriptError serror;
+ bool res = VerifyScript(DUMMY_SCRIPTSIG, script_pubkey, &witness_mal, STANDARD_SCRIPT_VERIFY_FLAGS, CHECKER_CTX, &serror);
+ // Malleable satisfactions are not guaranteed to be valid under any conditions, but they can only
+ // fail due to stack or ops limits.
+ assert(res || serror == ScriptError::SCRIPT_ERR_OP_COUNT || serror == ScriptError::SCRIPT_ERR_STACK_SIZE);
+ }
+
+ if (node->IsSane()) {
+ // For sane nodes, the two algorithms behave identically.
+ assert(mal_success == nonmal_success);
+ }
+
+ // Verify that if a node is policy-satisfiable, the malleable satisfaction
+ // algorithm succeeds. Given that under IsSane() both satisfactions
+ // are identical, this implies that for such nodes, the non-malleable
+ // satisfaction will also match the expected policy.
+ bool satisfiable = node->IsSatisfiable([](const Node& node) -> bool {
+ switch (node.fragment) {
+ case Fragment::PK_K:
+ case Fragment::PK_H: {
+ auto it = TEST_DATA.dummy_sigs.find(node.keys[0]);
+ assert(it != TEST_DATA.dummy_sigs.end());
+ return it->second.second;
+ }
+ case Fragment::MULTI: {
+ size_t sats = 0;
+ for (const auto& key : node.keys) {
+ auto it = TEST_DATA.dummy_sigs.find(key);
+ assert(it != TEST_DATA.dummy_sigs.end());
+ sats += it->second.second;
+ }
+ return sats >= node.k;
+ }
+ case Fragment::OLDER:
+ case Fragment::AFTER:
+ return node.k & 1;
+ case Fragment::SHA256:
+ return TEST_DATA.sha256_preimages.count(node.data);
+ case Fragment::HASH256:
+ return TEST_DATA.hash256_preimages.count(node.data);
+ case Fragment::RIPEMD160:
+ return TEST_DATA.ripemd160_preimages.count(node.data);
+ case Fragment::HASH160:
+ return TEST_DATA.hash160_preimages.count(node.data);
+ default:
+ assert(false);
+ }
+ return false;
+ });
+ assert(mal_success == satisfiable);
+}
+
} // namespace
void FuzzInit()
@@ -138,6 +1053,33 @@ void FuzzInit()
TEST_DATA.Init();
}
+void FuzzInitSmart()
+{
+ FuzzInit();
+ SMARTINFO.Init();
+}
+
+/** Fuzz target that runs TestNode on nodes generated using ConsumeNodeStable. */
+FUZZ_TARGET_INIT(miniscript_stable, FuzzInit)
+{
+ FuzzedDataProvider provider(buffer.data(), buffer.size());
+ TestNode(GenNode([&](Type needed_type) {
+ return ConsumeNodeStable(provider, needed_type);
+ }, ""_mst), provider);
+}
+
+/** Fuzz target that runs TestNode on nodes generated using ConsumeNodeSmart. */
+FUZZ_TARGET_INIT(miniscript_smart, FuzzInitSmart)
+{
+ /** The set of types we aim to construct nodes for. Together they cover all. */
+ static constexpr std::array<Type, 4> BASE_TYPES{"B"_mst, "V"_mst, "K"_mst, "W"_mst};
+
+ FuzzedDataProvider provider(buffer.data(), buffer.size());
+ TestNode(GenNode([&](Type needed_type) {
+ return ConsumeNodeSmart(provider, needed_type);
+ }, PickValue(provider, BASE_TYPES), true), provider);
+}
+
/* Fuzz tests that test parsing from a string, and roundtripping via string. */
FUZZ_TARGET_INIT(miniscript_string, FuzzInit)
{
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index 741810f6a2..13b4638688 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,6 +12,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <util/asmap.h>
diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp
index e62fe0328e..ae343602e9 100644
--- a/src/test/fuzz/net_permissions.cpp
+++ b/src/test/fuzz/net_permissions.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,6 +6,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <util/translation.h>
#include <cassert>
diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp
index 35e6688c61..049ae02f4d 100644
--- a/src/test/fuzz/netaddress.cpp
+++ b/src/test/fuzz/netaddress.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 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 <netaddress.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
-#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <cassert>
#include <cstdint>
@@ -70,8 +70,7 @@ FUZZ_TARGET(netaddress)
assert(net_addr.GetNetwork() == Network::NET_ONION);
}
(void)net_addr.IsValid();
- (void)net_addr.ToString();
- (void)net_addr.ToStringIP();
+ (void)net_addr.ToStringAddr();
const CSubNet sub_net{net_addr, fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
(void)sub_net.IsValid();
@@ -80,9 +79,7 @@ FUZZ_TARGET(netaddress)
const CService service{net_addr, fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
(void)service.GetKey();
(void)service.GetPort();
- (void)service.ToString();
- (void)service.ToStringIPPort();
- (void)service.ToStringPort();
+ (void)service.ToStringAddrPort();
(void)CServiceHash()(service);
(void)CServiceHash(0, 0)(service);
diff --git a/src/test/fuzz/netbase_dns_lookup.cpp b/src/test/fuzz/netbase_dns_lookup.cpp
index 31ea31744a..81e216b358 100644
--- a/src/test/fuzz/netbase_dns_lookup.cpp
+++ b/src/test/fuzz/netbase_dns_lookup.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,7 +6,7 @@
#include <netbase.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
-#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <cstdint>
#include <string>
diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp
index e27b254580..e47432600c 100644
--- a/src/test/fuzz/node_eviction.cpp
+++ b/src/test/fuzz/node_eviction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,6 +7,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <algorithm>
#include <cassert>
diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp
index 88c22ca305..96254aa222 100644
--- a/src/test/fuzz/p2p_transport_serialization.cpp
+++ b/src/test/fuzz/p2p_transport_serialization.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -24,7 +24,7 @@ void initialize_p2p_transport_serialization()
FUZZ_TARGET_INIT(p2p_transport_serialization, initialize_p2p_transport_serialization)
{
// Construct deserializer, with a dummy NodeId
- V1TransportDeserializer deserializer{Params(), (NodeId)0, SER_NETWORK, INIT_PROTO_VERSION};
+ V1TransportDeserializer deserializer{Params(), NodeId{0}, SER_NETWORK, INIT_PROTO_VERSION};
V1TransportSerializer serializer{};
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp
index 0cc210f26f..16486f6b96 100644
--- a/src/test/fuzz/parse_univalue.cpp
+++ b/src/test/fuzz/parse_univalue.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,7 +13,6 @@
void initialize_parse_univalue()
{
- static const ECCVerifyHandle verify_handle;
SelectParams(CBaseChainParams::REGTEST);
}
diff --git a/src/test/fuzz/partially_downloaded_block.cpp b/src/test/fuzz/partially_downloaded_block.cpp
new file mode 100644
index 0000000000..f8ba4f08d9
--- /dev/null
+++ b/src/test/fuzz/partially_downloaded_block.cpp
@@ -0,0 +1,142 @@
+#include <blockencodings.h>
+#include <consensus/merkle.h>
+#include <consensus/validation.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/fuzz/util/mempool.h>
+#include <test/util/setup_common.h>
+#include <test/util/txmempool.h>
+#include <txmempool.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <optional>
+#include <set>
+#include <vector>
+
+namespace {
+const TestingSetup* g_setup;
+} // namespace
+
+void initialize_pdb()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
+}
+
+PartiallyDownloadedBlock::CheckBlockFn FuzzedCheckBlock(std::optional<BlockValidationResult> result)
+{
+ return [result](const CBlock&, BlockValidationState& state, const Consensus::Params&, bool, bool) {
+ if (result) {
+ return state.Invalid(*result);
+ }
+
+ return true;
+ };
+}
+
+FUZZ_TARGET_INIT(partially_downloaded_block, initialize_pdb)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+
+ auto block{ConsumeDeserializable<CBlock>(fuzzed_data_provider)};
+ if (!block || block->vtx.size() == 0 ||
+ block->vtx.size() >= std::numeric_limits<uint16_t>::max()) {
+ return;
+ }
+
+ CBlockHeaderAndShortTxIDs cmpctblock{*block};
+
+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
+ PartiallyDownloadedBlock pdb{&pool};
+
+ // Set of available transactions (mempool or extra_txn)
+ std::set<uint16_t> available;
+ // The coinbase is always available
+ available.insert(0);
+
+ std::vector<std::pair<uint256, CTransactionRef>> extra_txn;
+ for (size_t i = 1; i < block->vtx.size(); ++i) {
+ auto tx{block->vtx[i]};
+
+ bool add_to_extra_txn{fuzzed_data_provider.ConsumeBool()};
+ bool add_to_mempool{fuzzed_data_provider.ConsumeBool()};
+
+ if (add_to_extra_txn) {
+ extra_txn.emplace_back(tx->GetWitnessHash(), tx);
+ available.insert(i);
+ }
+
+ if (add_to_mempool) {
+ LOCK2(cs_main, pool.cs);
+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, *tx));
+ available.insert(i);
+ }
+ }
+
+ auto init_status{pdb.InitData(cmpctblock, extra_txn)};
+
+ std::vector<CTransactionRef> missing;
+ // Whether we skipped a transaction that should be included in `missing`.
+ // FillBlock should never return READ_STATUS_OK if that is the case.
+ bool skipped_missing{false};
+ for (size_t i = 0; i < cmpctblock.BlockTxCount(); i++) {
+ // If init_status == READ_STATUS_OK then a available transaction in the
+ // compact block (i.e. IsTxAvailable(i) == true) implies that we marked
+ // that transaction as available above (i.e. available.count(i) > 0).
+ // The reverse is not true, due to possible compact block short id
+ // collisions (i.e. available.count(i) > 0 does not imply
+ // IsTxAvailable(i) == true).
+ if (init_status == READ_STATUS_OK) {
+ assert(!pdb.IsTxAvailable(i) || available.count(i) > 0);
+ }
+
+ bool skip{fuzzed_data_provider.ConsumeBool()};
+ if (!pdb.IsTxAvailable(i) && !skip) {
+ missing.push_back(block->vtx[i]);
+ }
+
+ skipped_missing |= (!pdb.IsTxAvailable(i) && skip);
+ }
+
+ // Mock CheckBlock
+ bool fail_check_block{fuzzed_data_provider.ConsumeBool()};
+ auto validation_result =
+ fuzzed_data_provider.PickValueInArray(
+ {BlockValidationResult::BLOCK_RESULT_UNSET,
+ BlockValidationResult::BLOCK_CONSENSUS,
+ BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE,
+ BlockValidationResult::BLOCK_CACHED_INVALID,
+ BlockValidationResult::BLOCK_INVALID_HEADER,
+ BlockValidationResult::BLOCK_MUTATED,
+ BlockValidationResult::BLOCK_MISSING_PREV,
+ BlockValidationResult::BLOCK_INVALID_PREV,
+ BlockValidationResult::BLOCK_TIME_FUTURE,
+ BlockValidationResult::BLOCK_CHECKPOINT,
+ BlockValidationResult::BLOCK_HEADER_LOW_WORK});
+ pdb.m_check_block_mock = FuzzedCheckBlock(
+ fail_check_block ?
+ std::optional<BlockValidationResult>{validation_result} :
+ std::nullopt);
+
+ CBlock reconstructed_block;
+ auto fill_status{pdb.FillBlock(reconstructed_block, missing)};
+ switch (fill_status) {
+ case READ_STATUS_OK:
+ assert(!skipped_missing);
+ assert(!fail_check_block);
+ assert(block->GetHash() == reconstructed_block.GetHash());
+ break;
+ case READ_STATUS_CHECKBLOCK_FAILED: [[fallthrough]];
+ case READ_STATUS_FAILED:
+ assert(fail_check_block);
+ break;
+ case READ_STATUS_INVALID:
+ break;
+ }
+}
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index a3d57dbdd5..116fbd9015 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -1,7 +1,8 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 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 <kernel/mempool_entry.h>
#include <policy/fees.h>
#include <policy/fees_args.h>
#include <primitives/transaction.h>
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 436873c955..7c3289cd26 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index eba03da773..e5a3a6e68a 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,6 +9,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <util/check.h>
#include <util/overflow.h>
#include <cstdint>
@@ -25,7 +26,7 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const Consensus::Params& consensus_params = Params().GetConsensus();
- std::vector<CBlockIndex> blocks;
+ std::vector<std::unique_ptr<CBlockIndex>> blocks;
const uint32_t fixed_time = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
const uint32_t fixed_bits = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
LIMITED_WHILE(fuzzed_data_provider.remaining_bytes() > 0, 10000) {
@@ -33,9 +34,10 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
if (!block_header) {
continue;
}
- CBlockIndex current_block{*block_header};
+ CBlockIndex& current_block{
+ *blocks.emplace_back(std::make_unique<CBlockIndex>(*block_header))};
{
- CBlockIndex* previous_block = blocks.empty() ? nullptr : &PickValue(fuzzed_data_provider, blocks);
+ CBlockIndex* previous_block = blocks.empty() ? nullptr : PickValue(fuzzed_data_provider, blocks).get();
const int current_height = (previous_block != nullptr && previous_block->nHeight != std::numeric_limits<int>::max()) ? previous_block->nHeight + 1 : 0;
if (fuzzed_data_provider.ConsumeBool()) {
current_block.pprev = previous_block;
@@ -57,7 +59,6 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
} else {
current_block.nChainWork = ConsumeArithUInt256(fuzzed_data_provider);
}
- blocks.push_back(current_block);
}
{
(void)GetBlockProof(current_block);
@@ -67,9 +68,9 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
}
}
{
- const CBlockIndex* to = &PickValue(fuzzed_data_provider, blocks);
- const CBlockIndex* from = &PickValue(fuzzed_data_provider, blocks);
- const CBlockIndex* tip = &PickValue(fuzzed_data_provider, blocks);
+ const auto& to = PickValue(fuzzed_data_provider, blocks);
+ const auto& from = PickValue(fuzzed_data_provider, blocks);
+ const auto& tip = PickValue(fuzzed_data_provider, blocks);
try {
(void)GetBlockProofEquivalentTime(*to, *from, *tip, consensus_params);
} catch (const uint_error&) {
diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp
index e2d65a4796..9cea32e304 100644
--- a/src/test/fuzz/prevector.cpp
+++ b/src/test/fuzz/prevector.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -59,8 +59,8 @@ public:
--pos;
assert(v == real_vector[pos]);
}
- CDataStream ss1(SER_DISK, 0);
- CDataStream ss2(SER_DISK, 0);
+ DataStream ss1{};
+ DataStream ss2{};
ss1 << real_vector;
ss2 << pre_vector;
assert(ss1.size() == ss2.size());
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index f6a35da4fc..0a7924f226 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,11 +14,11 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <test/util/mining.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
-#include <txorphanage.h>
#include <validationinterface.h>
#include <version.h>
@@ -56,7 +56,9 @@ void initialize_process_message()
{
Assert(GetNumMsgTypes() == getAllNetMessageTypes().size()); // If this fails, add or remove the message type below
- static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(
+ /*chain_name=*/CBaseChainParams::REGTEST,
+ /*extra_args=*/{"-txreconciliation"});
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
@@ -130,6 +132,7 @@ FUZZ_TARGET_MSG(pong);
FUZZ_TARGET_MSG(sendaddrv2);
FUZZ_TARGET_MSG(sendcmpct);
FUZZ_TARGET_MSG(sendheaders);
+FUZZ_TARGET_MSG(sendtxrcncl);
FUZZ_TARGET_MSG(tx);
FUZZ_TARGET_MSG(verack);
FUZZ_TARGET_MSG(version);
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index 1df1717ec3..96339743ba 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,11 +9,11 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <test/util/mining.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
-#include <txorphanage.h>
#include <validation.h>
#include <validationinterface.h>
@@ -23,7 +23,9 @@ const TestingSetup* g_setup;
void initialize_process_messages()
{
- static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(
+ /*chain_name=*/CBaseChainParams::REGTEST,
+ /*extra_args=*/{"-txreconciliation"});
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp
index baa64bba0f..825ed67ec1 100644
--- a/src/test/fuzz/psbt.cpp
+++ b/src/test/fuzz/psbt.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,12 +22,7 @@ using node::AnalyzePSBT;
using node::PSBTAnalysis;
using node::PSBTInputAnalysis;
-void initialize_psbt()
-{
- static const ECCVerifyHandle verify_handle;
-}
-
-FUZZ_TARGET_INIT(psbt, initialize_psbt)
+FUZZ_TARGET(psbt)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
PartiallySignedTransaction psbt_mut;
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index e06e57d919..57a9a15a85 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@
#include <test/fuzz/util.h>
#include <test/fuzz/util/mempool.h>
#include <test/util/setup_common.h>
+#include <test/util/txmempool.h>
#include <txmempool.h>
#include <cstdint>
diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp
index 26913a41d2..2578137471 100644
--- a/src/test/fuzz/rpc.cpp
+++ b/src/test/fuzz/rpc.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -151,6 +151,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"preciousblock",
"pruneblockchain",
"reconsiderblock",
+ "scanblocks",
"scantxoutset",
"sendrawtransaction",
"setmocktime",
@@ -252,7 +253,7 @@ std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
if (!opt_block_header) {
return;
}
- CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION};
+ DataStream data_stream{};
data_stream << *opt_block_header;
r = HexStr(data_stream);
},
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index 00d7b7e29a..1037dd934a 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -32,9 +32,6 @@
void initialize_script()
{
- // Fuzzers using pubkey must hold an ECCVerifyHandle.
- static const ECCVerifyHandle verify_handle;
-
SelectParams(CBaseChainParams::REGTEST);
}
diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp
index 35d7246ed8..206d219afe 100644
--- a/src/test/fuzz/script_assets_test_minimizer.cpp
+++ b/src/test/fuzz/script_assets_test_minimizer.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -184,10 +184,7 @@ void Test(const std::string& str)
}
}
-void test_init()
-{
- static ECCVerifyHandle handle;
-}
+void test_init() {}
FUZZ_TARGET_INIT_HIDDEN(script_assets_test_minimizer, test_init, /*hidden=*/true)
{
diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp
index 8dc99ee069..f8594fc233 100644
--- a/src/test/fuzz/script_flags.cpp
+++ b/src/test/fuzz/script_flags.cpp
@@ -11,12 +11,7 @@
#include <test/fuzz/fuzz.h>
-void initialize_script_flags()
-{
- static const ECCVerifyHandle verify_handle;
-}
-
-FUZZ_TARGET_INIT(script_flags, initialize_script_flags)
+FUZZ_TARGET(script_flags)
{
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
try {
diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp
index f6af7947df..de895cc69c 100644
--- a/src/test/fuzz/script_sigcache.cpp
+++ b/src/test/fuzz/script_sigcache.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp
index 3ddb30d870..c78c22e6cc 100644
--- a/src/test/fuzz/script_sign.cpp
+++ b/src/test/fuzz/script_sign.cpp
@@ -26,7 +26,6 @@
void initialize_script_sign()
{
- static const ECCVerifyHandle ecc_verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::REGTEST);
}
@@ -109,10 +108,12 @@ FUZZ_TARGET_INIT(script_sign, initialize_script_sign)
CMutableTransaction script_tx_to = tx_to;
CMutableTransaction sign_transaction_tx_to = tx_to;
if (n_in < tx_to.vin.size() && tx_to.vin[n_in].prevout.n < tx_from.vout.size()) {
- (void)SignSignature(provider, tx_from, tx_to, n_in, fuzzed_data_provider.ConsumeIntegral<int>());
+ SignatureData empty;
+ (void)SignSignature(provider, tx_from, tx_to, n_in, fuzzed_data_provider.ConsumeIntegral<int>(), empty);
}
if (n_in < script_tx_to.vin.size()) {
- (void)SignSignature(provider, ConsumeScript(fuzzed_data_provider), script_tx_to, n_in, ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int>());
+ SignatureData empty;
+ (void)SignSignature(provider, ConsumeScript(fuzzed_data_provider), script_tx_to, n_in, ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int>(), empty);
MutableTransactionSignatureCreator signature_creator{tx_to, n_in, ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int>()};
std::vector<unsigned char> vch_sig;
CKeyID address;
diff --git a/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp
index f437d53b57..74ef6bfd4e 100644
--- a/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp
+++ b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp
@@ -12,7 +12,7 @@
#include <vector>
bool SigHasLowR(const secp256k1_ecdsa_signature* sig);
-int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char* input, size_t inputlen);
+int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned char* input, size_t inputlen);
FUZZ_TARGET(secp256k1_ecdsa_signature_parse_der_lax)
{
@@ -21,13 +21,11 @@ FUZZ_TARGET(secp256k1_ecdsa_signature_parse_der_lax)
if (signature_bytes.data() == nullptr) {
return;
}
- secp256k1_context* secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_ecdsa_signature sig_der_lax;
- const bool parsed_der_lax = ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig_der_lax, signature_bytes.data(), signature_bytes.size()) == 1;
+ const bool parsed_der_lax = ecdsa_signature_parse_der_lax(&sig_der_lax, signature_bytes.data(), signature_bytes.size()) == 1;
if (parsed_der_lax) {
ECC_Start();
(void)SigHasLowR(&sig_der_lax);
ECC_Stop();
}
- secp256k1_context_destroy(secp256k1_context_verify);
}
diff --git a/src/test/fuzz/signature_checker.cpp b/src/test/fuzz/signature_checker.cpp
index a585680de1..59f4792961 100644
--- a/src/test/fuzz/signature_checker.cpp
+++ b/src/test/fuzz/signature_checker.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,11 +14,6 @@
#include <string>
#include <vector>
-void initialize_signature_checker()
-{
- static const auto verify_handle = std::make_unique<ECCVerifyHandle>();
-}
-
namespace {
class FuzzedSignatureChecker : public BaseSignatureChecker
{
@@ -53,7 +48,7 @@ public:
};
} // namespace
-FUZZ_TARGET_INIT(signature_checker, initialize_signature_checker)
+FUZZ_TARGET(signature_checker)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp
index c3a6eed089..97f643db49 100644
--- a/src/test/fuzz/socks5.cpp
+++ b/src/test/fuzz/socks5.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,6 +7,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
#include <cstdint>
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index 94399faf04..9890e4c0e5 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <blockfilter.h>
#include <clientversion.h>
+#include <common/url.h>
#include <logging.h>
#include <netaddress.h>
#include <netbase.h>
@@ -27,7 +28,6 @@
#include <util/string.h>
#include <util/system.h>
#include <util/translation.h>
-#include <util/url.h>
#include <version.h>
#include <cstdint>
@@ -196,7 +196,7 @@ FUZZ_TARGET(string)
}
{
- CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION};
+ DataStream data_stream{};
std::string s;
auto limited_string = LIMITED_STRING(s, 10);
data_stream << random_string_1;
@@ -212,7 +212,7 @@ FUZZ_TARGET(string)
}
}
{
- CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION};
+ DataStream data_stream{};
const auto limited_string = LIMITED_STRING(random_string_1, 10);
data_stream << limited_string;
std::string deserialized_string;
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 7fa4523800..bacb178b44 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/tx_in.cpp b/src/test/fuzz/tx_in.cpp
index f8247c1fa4..fc16f80cde 100644
--- a/src/test/fuzz/tx_in.cpp
+++ b/src/test/fuzz/tx_in.cpp
@@ -14,12 +14,9 @@
FUZZ_TARGET(tx_in)
{
- CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
+ DataStream ds{buffer};
CTxIn tx_in;
try {
- int version;
- ds >> version;
- ds.SetVersion(version);
ds >> tx_in;
} catch (const std::ios_base::failure&) {
return;
diff --git a/src/test/fuzz/tx_out.cpp b/src/test/fuzz/tx_out.cpp
index a2421ff582..806216fbf5 100644
--- a/src/test/fuzz/tx_out.cpp
+++ b/src/test/fuzz/tx_out.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,12 +13,9 @@
FUZZ_TARGET(tx_out)
{
- CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
+ DataStream ds{buffer};
CTxOut tx_out;
try {
- int version;
- ds >> version;
- ds.SetVersion(version);
ds >> tx_out;
} catch (const std::ios_base::failure&) {
return;
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index a34e501fcc..0cabaf323b 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,6 +13,7 @@
#include <test/util/mining.h>
#include <test/util/script.h>
#include <test/util/setup_common.h>
+#include <test/util/txmempool.h>
#include <util/rbf.h>
#include <validation.h>
#include <validationinterface.h>
@@ -210,7 +211,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
for (int i = 0; i < num_out; ++i) {
tx_mut.vout.emplace_back(amount_out, P2WSH_OP_TRUE);
}
- const auto tx = MakeTransactionRef(tx_mut);
+ auto tx = MakeTransactionRef(tx_mut);
// Restore previously removed outpoints
for (const auto& in : tx->vin) {
Assert(outpoints_rbf.insert(in.prevout).second);
@@ -310,7 +311,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const auto& node = g_setup->m_node;
- auto& chainstate = node.chainman->ActiveChainstate();
+ auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
MockTime(fuzzed_data_provider, chainstate);
@@ -328,6 +329,8 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
+ chainstate.SetMempool(&tx_pool);
+
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
{
const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp
index 55060f31cf..ed55e3fad5 100644
--- a/src/test/fuzz/txorphan.cpp
+++ b/src/test/fuzz/txorphan.cpp
@@ -36,7 +36,6 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
SetMockTime(ConsumeTime(fuzzed_data_provider));
TxOrphanage orphanage;
- std::set<uint256> orphan_work_set;
std::vector<COutPoint> outpoints;
// initial outpoints used to construct transactions later
for (uint8_t i = 0; i < 4; i++) {
@@ -70,7 +69,7 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
for (auto& in : tx_mut.vin) {
outpoints.push_back(in.prevout);
}
- const auto new_tx = MakeTransactionRef(tx_mut);
+ auto new_tx = MakeTransactionRef(tx_mut);
// add newly constructed transaction to outpoints
for (uint32_t i = 0; i < num_out; i++) {
outpoints.emplace_back(new_tx->GetHash(), i);
@@ -86,15 +85,15 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
CallOneOf(
fuzzed_data_provider,
[&] {
- LOCK(g_cs_orphans);
- orphanage.AddChildrenToWorkSet(*tx, orphan_work_set);
+ orphanage.AddChildrenToWorkSet(*tx);
},
[&] {
- bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
{
- LOCK(g_cs_orphans);
- bool get_tx = orphanage.GetTx(tx->GetHash()).first != nullptr;
- Assert(have_tx == get_tx);
+ CTransactionRef ref = orphanage.GetTxToReconsider(peer_id);
+ if (ref) {
+ bool have_tx = orphanage.HaveTx(GenTxid::Txid(ref->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(ref->GetHash()));
+ Assert(have_tx);
+ }
}
},
[&] {
@@ -102,14 +101,12 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
// AddTx should return false if tx is too big or already have it
// tx weight is unknown, we only check when tx is already in orphanage
{
- LOCK(g_cs_orphans);
bool add_tx = orphanage.AddTx(tx, peer_id);
// have_tx == true -> add_tx == false
Assert(!have_tx || !add_tx);
}
have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
{
- LOCK(g_cs_orphans);
bool add_tx = orphanage.AddTx(tx, peer_id);
// if have_tx is still false, it must be too big
Assert(!have_tx == (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT));
@@ -120,25 +117,22 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
// EraseTx should return 0 if m_orphans doesn't have the tx
{
- LOCK(g_cs_orphans);
Assert(have_tx == orphanage.EraseTx(tx->GetHash()));
}
have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
// have_tx should be false and EraseTx should fail
{
- LOCK(g_cs_orphans);
Assert(!have_tx && !orphanage.EraseTx(tx->GetHash()));
}
},
[&] {
- LOCK(g_cs_orphans);
orphanage.EraseForPeer(peer_id);
},
[&] {
// test mocktime and expiry
SetMockTime(ConsumeTime(fuzzed_data_provider));
auto limit = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
- WITH_LOCK(g_cs_orphans, orphanage.LimitOrphans(limit));
+ orphanage.LimitOrphans(limit);
Assert(orphanage.Size() <= limit);
});
}
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index 0080b1e56e..9da84fe90e 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -1,13 +1,12 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 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 <consensus/amount.h>
-#include <net_processing.h>
-#include <netmessagemaker.h>
#include <pubkey.h>
#include <test/fuzz/util.h>
#include <test/util/script.h>
+#include <util/check.h>
#include <util/overflow.h>
#include <util/rbf.h>
#include <util/time.h>
@@ -15,290 +14,6 @@
#include <memory>
-FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider)
- : m_fuzzed_data_provider{fuzzed_data_provider}
-{
- m_socket = fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET);
-}
-
-FuzzedSock::~FuzzedSock()
-{
- // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
- // close(m_socket) if m_socket is not INVALID_SOCKET.
- // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
- // theoretically may concide with a real opened file descriptor).
- m_socket = INVALID_SOCKET;
-}
-
-FuzzedSock& FuzzedSock::operator=(Sock&& other)
-{
- assert(false && "Move of Sock into FuzzedSock not allowed.");
- return *this;
-}
-
-ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
-{
- constexpr std::array send_errnos{
- EACCES,
- EAGAIN,
- EALREADY,
- EBADF,
- ECONNRESET,
- EDESTADDRREQ,
- EFAULT,
- EINTR,
- EINVAL,
- EISCONN,
- EMSGSIZE,
- ENOBUFS,
- ENOMEM,
- ENOTCONN,
- ENOTSOCK,
- EOPNOTSUPP,
- EPIPE,
- EWOULDBLOCK,
- };
- if (m_fuzzed_data_provider.ConsumeBool()) {
- return len;
- }
- const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
- if (r == -1) {
- SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos);
- }
- return r;
-}
-
-ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
-{
- // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
- // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
- // returning -1 and setting errno to EAGAIN repeatedly.
- constexpr std::array recv_errnos{
- ECONNREFUSED,
- EAGAIN,
- EBADF,
- EFAULT,
- EINTR,
- EINVAL,
- ENOMEM,
- ENOTCONN,
- ENOTSOCK,
- EWOULDBLOCK,
- };
- assert(buf != nullptr || len == 0);
- if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
- const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
- if (r == -1) {
- SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
- }
- return r;
- }
- std::vector<uint8_t> random_bytes;
- bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()};
- if (m_peek_data.has_value()) {
- // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`.
- random_bytes.assign({m_peek_data.value()});
- if ((flags & MSG_PEEK) == 0) {
- m_peek_data.reset();
- }
- pad_to_len_bytes = false;
- } else if ((flags & MSG_PEEK) != 0) {
- // New call with `MSG_PEEK`.
- random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1);
- if (!random_bytes.empty()) {
- m_peek_data = random_bytes[0];
- pad_to_len_bytes = false;
- }
- } else {
- random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
- m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len));
- }
- if (random_bytes.empty()) {
- const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
- if (r == -1) {
- SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
- }
- return r;
- }
- std::memcpy(buf, random_bytes.data(), random_bytes.size());
- if (pad_to_len_bytes) {
- if (len > random_bytes.size()) {
- std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size());
- }
- return len;
- }
- if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
- std::this_thread::sleep_for(std::chrono::milliseconds{2});
- }
- return random_bytes.size();
-}
-
-int FuzzedSock::Connect(const sockaddr*, socklen_t) const
-{
- // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
- // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
- // returning -1 and setting errno to EAGAIN repeatedly.
- constexpr std::array connect_errnos{
- ECONNREFUSED,
- EAGAIN,
- ECONNRESET,
- EHOSTUNREACH,
- EINPROGRESS,
- EINTR,
- ENETUNREACH,
- ETIMEDOUT,
- };
- if (m_fuzzed_data_provider.ConsumeBool()) {
- SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
- return -1;
- }
- return 0;
-}
-
-int FuzzedSock::Bind(const sockaddr*, socklen_t) const
-{
- // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
- // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
- // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
- // repeatedly because proper code should retry on temporary errors, leading to an
- // infinite loop.
- constexpr std::array bind_errnos{
- EACCES,
- EADDRINUSE,
- EADDRNOTAVAIL,
- EAGAIN,
- };
- if (m_fuzzed_data_provider.ConsumeBool()) {
- SetFuzzedErrNo(m_fuzzed_data_provider, bind_errnos);
- return -1;
- }
- return 0;
-}
-
-int FuzzedSock::Listen(int) const
-{
- // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
- // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
- // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
- // repeatedly because proper code should retry on temporary errors, leading to an
- // infinite loop.
- constexpr std::array listen_errnos{
- EADDRINUSE,
- EINVAL,
- EOPNOTSUPP,
- };
- if (m_fuzzed_data_provider.ConsumeBool()) {
- SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos);
- return -1;
- }
- return 0;
-}
-
-std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
-{
- constexpr std::array accept_errnos{
- ECONNABORTED,
- EINTR,
- ENOMEM,
- };
- if (m_fuzzed_data_provider.ConsumeBool()) {
- SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
- return std::unique_ptr<FuzzedSock>();
- }
- return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
-}
-
-int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
-{
- constexpr std::array getsockopt_errnos{
- ENOMEM,
- ENOBUFS,
- };
- if (m_fuzzed_data_provider.ConsumeBool()) {
- SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
- return -1;
- }
- if (opt_val == nullptr) {
- return 0;
- }
- std::memcpy(opt_val,
- ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(),
- *opt_len);
- return 0;
-}
-
-int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
-{
- constexpr std::array setsockopt_errnos{
- ENOMEM,
- ENOBUFS,
- };
- if (m_fuzzed_data_provider.ConsumeBool()) {
- SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
- return -1;
- }
- return 0;
-}
-
-int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
-{
- constexpr std::array getsockname_errnos{
- ECONNRESET,
- ENOBUFS,
- };
- if (m_fuzzed_data_provider.ConsumeBool()) {
- SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
- return -1;
- }
- *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len);
- return 0;
-}
-
-bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
-{
- constexpr std::array wait_errnos{
- EBADF,
- EINTR,
- EINVAL,
- };
- if (m_fuzzed_data_provider.ConsumeBool()) {
- SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos);
- return false;
- }
- if (occurred != nullptr) {
- *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0;
- }
- return true;
-}
-
-bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
-{
- for (auto& [sock, events] : events_per_sock) {
- (void)sock;
- events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0;
- }
- return true;
-}
-
-bool FuzzedSock::IsConnected(std::string& errmsg) const
-{
- if (m_fuzzed_data_provider.ConsumeBool()) {
- return true;
- }
- errmsg = "disconnected at random by the fuzzer";
- return false;
-}
-
-void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
-{
- connman.Handshake(node,
- /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
- /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
- /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
- /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
- /*relay_txs=*/fuzzed_data_provider.ConsumeBool());
-}
-
CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max) noexcept
{
return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, max.value_or(MAX_MONEY));
@@ -489,33 +204,6 @@ bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) n
return false;
}
-CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
- CNetAddr net_addr;
- if (network == Network::NET_IPV4) {
- in_addr v4_addr = {};
- v4_addr.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
- net_addr = CNetAddr{v4_addr};
- } else if (network == Network::NET_IPV6) {
- if (fuzzed_data_provider.remaining_bytes() >= 16) {
- in6_addr v6_addr = {};
- memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
- net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
- }
- } else if (network == Network::NET_INTERNAL) {
- net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
- } else if (network == Network::NET_ONION) {
- net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
- }
- return net_addr;
-}
-
-CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};
-}
-
FILE* FuzzedFileProvider::open()
{
SetFuzzedErrNo(m_fuzzed_data_provider);
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index a354df2bf7..c14f633029 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,9 +12,6 @@
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <merkleblock.h>
-#include <net.h>
-#include <netaddress.h>
-#include <netbase.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/standard.h>
@@ -22,7 +19,6 @@
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
-#include <test/util/net.h>
#include <uint256.h>
#include <version.h>
@@ -36,54 +32,6 @@
class PeerManager;
-class FuzzedSock : public Sock
-{
- FuzzedDataProvider& m_fuzzed_data_provider;
-
- /**
- * Data to return when `MSG_PEEK` is used as a `Recv()` flag.
- * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next
- * `Recv()` call we must return the same data, thus we remember it here.
- */
- mutable std::optional<uint8_t> m_peek_data;
-
-public:
- explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider);
-
- ~FuzzedSock() override;
-
- FuzzedSock& operator=(Sock&& other) override;
-
- ssize_t Send(const void* data, size_t len, int flags) const override;
-
- ssize_t Recv(void* buf, size_t len, int flags) const override;
-
- int Connect(const sockaddr*, socklen_t) const override;
-
- int Bind(const sockaddr*, socklen_t) const override;
-
- int Listen(int backlog) const override;
-
- std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override;
-
- int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
-
- int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override;
-
- int GetSockName(sockaddr* name, socklen_t* name_len) const override;
-
- bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
-
- bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;
-
- bool IsConnected(std::string& errmsg) const override;
-};
-
-[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
-{
- return FuzzedSock{fuzzed_data_provider};
-}
-
template <typename... Callables>
size_t CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables)
{
@@ -99,7 +47,7 @@ size_t CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callable
template <typename Collection>
auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, Collection& col)
{
- const auto sz = col.size();
+ auto sz{col.size()};
assert(sz >= 1);
auto it = col.begin();
std::advance(it, fuzzed_data_provider.ConsumeIntegralInRange<decltype(sz)>(0, sz - 1));
@@ -272,61 +220,6 @@ inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept
return result;
}
-CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept;
-
-inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
-}
-
-inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
-}
-
-CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
-
-template <bool ReturnUniquePtr = false>
-auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
-{
- const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max()));
- const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
- const CAddress address = ConsumeAddress(fuzzed_data_provider);
- const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
- const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
- const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
- const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
- const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
- const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
- NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
- if constexpr (ReturnUniquePtr) {
- return std::make_unique<CNode>(node_id,
- sock,
- address,
- keyed_net_group,
- local_host_nonce,
- addr_bind,
- addr_name,
- conn_type,
- inbound_onion,
- CNodeOptions{ .permission_flags = permission_flags });
- } else {
- return CNode{node_id,
- sock,
- address,
- keyed_net_group,
- local_host_nonce,
- addr_bind,
- addr_name,
- conn_type,
- inbound_onion,
- CNodeOptions{ .permission_flags = permission_flags }};
- }
-}
-inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
-
-void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex);
-
class FuzzedFileProvider
{
FuzzedDataProvider& m_fuzzed_data_provider;
diff --git a/src/test/fuzz/util/mempool.cpp b/src/test/fuzz/util/mempool.cpp
index d0053f77d2..4baca5ec77 100644
--- a/src/test/fuzz/util/mempool.cpp
+++ b/src/test/fuzz/util/mempool.cpp
@@ -3,12 +3,15 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/amount.h>
+#include <consensus/consensus.h>
+#include <kernel/mempool_entry.h>
#include <primitives/transaction.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/util.h>
#include <test/fuzz/util/mempool.h>
-#include <txmempool.h>
+#include <cassert>
+#include <cstdint>
#include <limits>
CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
diff --git a/src/test/fuzz/util/mempool.h b/src/test/fuzz/util/mempool.h
index 4304e5294e..31b578dc4b 100644
--- a/src/test/fuzz/util/mempool.h
+++ b/src/test/fuzz/util/mempool.h
@@ -5,11 +5,13 @@
#ifndef BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H
#define BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H
-#include <primitives/transaction.h>
-#include <test/fuzz/FuzzedDataProvider.h>
-#include <txmempool.h>
+#include <kernel/mempool_entry.h>
#include <validation.h>
+class CTransaction;
+class CTxMemPool;
+class FuzzedDataProvider;
+
class DummyChainState final : public Chainstate
{
public:
diff --git a/src/test/fuzz/util/net.cpp b/src/test/fuzz/util/net.cpp
new file mode 100644
index 0000000000..65bc336297
--- /dev/null
+++ b/src/test/fuzz/util/net.cpp
@@ -0,0 +1,358 @@
+// Copyright (c) 2009-2022 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/util/net.h>
+
+#include <compat/compat.h>
+#include <netaddress.h>
+#include <protocol.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/util.h>
+#include <test/util/net.h>
+#include <util/sock.h>
+#include <util/time.h>
+#include <version.h>
+
+#include <array>
+#include <cassert>
+#include <cerrno>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <thread>
+#include <vector>
+
+class CNode;
+
+CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
+ CNetAddr net_addr;
+ if (network == Network::NET_IPV4) {
+ in_addr v4_addr = {};
+ v4_addr.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ net_addr = CNetAddr{v4_addr};
+ } else if (network == Network::NET_IPV6) {
+ if (fuzzed_data_provider.remaining_bytes() >= 16) {
+ in6_addr v6_addr = {};
+ memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
+ net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
+ }
+ } else if (network == Network::NET_INTERNAL) {
+ net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
+ } else if (network == Network::NET_ONION) {
+ auto pub_key{fuzzed_data_provider.ConsumeBytes<uint8_t>(ADDR_TORV3_SIZE)};
+ pub_key.resize(ADDR_TORV3_SIZE);
+ const bool ok{net_addr.SetSpecial(OnionToString(pub_key))};
+ assert(ok);
+ }
+ return net_addr;
+}
+
+CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};
+}
+
+FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider)
+ : m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()}
+{
+ m_socket = fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET);
+}
+
+FuzzedSock::~FuzzedSock()
+{
+ // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
+ // close(m_socket) if m_socket is not INVALID_SOCKET.
+ // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
+ // theoretically may concide with a real opened file descriptor).
+ m_socket = INVALID_SOCKET;
+}
+
+FuzzedSock& FuzzedSock::operator=(Sock&& other)
+{
+ assert(false && "Move of Sock into FuzzedSock not allowed.");
+ return *this;
+}
+
+ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
+{
+ constexpr std::array send_errnos{
+ EACCES,
+ EAGAIN,
+ EALREADY,
+ EBADF,
+ ECONNRESET,
+ EDESTADDRREQ,
+ EFAULT,
+ EINTR,
+ EINVAL,
+ EISCONN,
+ EMSGSIZE,
+ ENOBUFS,
+ ENOMEM,
+ ENOTCONN,
+ ENOTSOCK,
+ EOPNOTSUPP,
+ EPIPE,
+ EWOULDBLOCK,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ return len;
+ }
+ const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
+ if (r == -1) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos);
+ }
+ return r;
+}
+
+ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
+{
+ // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
+ // returning -1 and setting errno to EAGAIN repeatedly.
+ constexpr std::array recv_errnos{
+ ECONNREFUSED,
+ EAGAIN,
+ EBADF,
+ EFAULT,
+ EINTR,
+ EINVAL,
+ ENOMEM,
+ ENOTCONN,
+ ENOTSOCK,
+ EWOULDBLOCK,
+ };
+ assert(buf != nullptr || len == 0);
+ if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
+ const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+ if (r == -1) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
+ }
+ return r;
+ }
+ std::vector<uint8_t> random_bytes;
+ bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()};
+ if (m_peek_data.has_value()) {
+ // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`.
+ random_bytes.assign({m_peek_data.value()});
+ if ((flags & MSG_PEEK) == 0) {
+ m_peek_data.reset();
+ }
+ pad_to_len_bytes = false;
+ } else if ((flags & MSG_PEEK) != 0) {
+ // New call with `MSG_PEEK`.
+ random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1);
+ if (!random_bytes.empty()) {
+ m_peek_data = random_bytes[0];
+ pad_to_len_bytes = false;
+ }
+ } else {
+ random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
+ m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len));
+ }
+ if (random_bytes.empty()) {
+ const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+ if (r == -1) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
+ }
+ return r;
+ }
+ std::memcpy(buf, random_bytes.data(), random_bytes.size());
+ if (pad_to_len_bytes) {
+ if (len > random_bytes.size()) {
+ std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size());
+ }
+ return len;
+ }
+ if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
+ std::this_thread::sleep_for(std::chrono::milliseconds{2});
+ }
+ return random_bytes.size();
+}
+
+int FuzzedSock::Connect(const sockaddr*, socklen_t) const
+{
+ // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
+ // returning -1 and setting errno to EAGAIN repeatedly.
+ constexpr std::array connect_errnos{
+ ECONNREFUSED,
+ EAGAIN,
+ ECONNRESET,
+ EHOSTUNREACH,
+ EINPROGRESS,
+ EINTR,
+ ENETUNREACH,
+ ETIMEDOUT,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
+ return -1;
+ }
+ return 0;
+}
+
+int FuzzedSock::Bind(const sockaddr*, socklen_t) const
+{
+ // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
+ // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
+ // repeatedly because proper code should retry on temporary errors, leading to an
+ // infinite loop.
+ constexpr std::array bind_errnos{
+ EACCES,
+ EADDRINUSE,
+ EADDRNOTAVAIL,
+ EAGAIN,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, bind_errnos);
+ return -1;
+ }
+ return 0;
+}
+
+int FuzzedSock::Listen(int) const
+{
+ // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
+ // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
+ // repeatedly because proper code should retry on temporary errors, leading to an
+ // infinite loop.
+ constexpr std::array listen_errnos{
+ EADDRINUSE,
+ EINVAL,
+ EOPNOTSUPP,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos);
+ return -1;
+ }
+ return 0;
+}
+
+std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
+{
+ constexpr std::array accept_errnos{
+ ECONNABORTED,
+ EINTR,
+ ENOMEM,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
+ return std::unique_ptr<FuzzedSock>();
+ }
+ return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
+}
+
+int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
+{
+ constexpr std::array getsockopt_errnos{
+ ENOMEM,
+ ENOBUFS,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
+ return -1;
+ }
+ if (opt_val == nullptr) {
+ return 0;
+ }
+ std::memcpy(opt_val,
+ ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(),
+ *opt_len);
+ return 0;
+}
+
+int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
+{
+ constexpr std::array setsockopt_errnos{
+ ENOMEM,
+ ENOBUFS,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
+ return -1;
+ }
+ return 0;
+}
+
+int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
+{
+ constexpr std::array getsockname_errnos{
+ ECONNRESET,
+ ENOBUFS,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
+ return -1;
+ }
+ *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len);
+ return 0;
+}
+
+bool FuzzedSock::SetNonBlocking() const
+{
+ constexpr std::array setnonblocking_errnos{
+ EBADF,
+ EPERM,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
+ return false;
+ }
+ return true;
+}
+
+bool FuzzedSock::IsSelectable() const
+{
+ return m_selectable;
+}
+
+bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
+{
+ constexpr std::array wait_errnos{
+ EBADF,
+ EINTR,
+ EINVAL,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos);
+ return false;
+ }
+ if (occurred != nullptr) {
+ *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0;
+ }
+ return true;
+}
+
+bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
+{
+ for (auto& [sock, events] : events_per_sock) {
+ (void)sock;
+ events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0;
+ }
+ return true;
+}
+
+bool FuzzedSock::IsConnected(std::string& errmsg) const
+{
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ return true;
+ }
+ errmsg = "disconnected at random by the fuzzer";
+ return false;
+}
+
+void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
+{
+ connman.Handshake(node,
+ /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
+ /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
+ /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
+ /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
+ /*relay_txs=*/fuzzed_data_provider.ConsumeBool());
+}
diff --git a/src/test/fuzz/util/net.h b/src/test/fuzz/util/net.h
new file mode 100644
index 0000000000..47e4a2fac0
--- /dev/null
+++ b/src/test/fuzz/util/net.h
@@ -0,0 +1,141 @@
+// Copyright (c) 2009-2022 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_UTIL_NET_H
+#define BITCOIN_TEST_FUZZ_UTIL_NET_H
+
+#include <net.h>
+#include <net_permissions.h>
+#include <netaddress.h>
+#include <node/connection_types.h>
+#include <node/eviction.h>
+#include <protocol.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/util.h>
+#include <test/util/net.h>
+#include <threadsafety.h>
+#include <util/sock.h>
+
+#include <chrono>
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <optional>
+#include <string>
+
+CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept;
+
+class FuzzedSock : public Sock
+{
+ FuzzedDataProvider& m_fuzzed_data_provider;
+
+ /**
+ * Data to return when `MSG_PEEK` is used as a `Recv()` flag.
+ * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next
+ * `Recv()` call we must return the same data, thus we remember it here.
+ */
+ mutable std::optional<uint8_t> m_peek_data;
+
+ /**
+ * Whether to pretend that the socket is select(2)-able. This is randomly set in the
+ * constructor. It should remain constant so that repeated calls to `IsSelectable()`
+ * return the same value.
+ */
+ const bool m_selectable;
+
+public:
+ explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider);
+
+ ~FuzzedSock() override;
+
+ FuzzedSock& operator=(Sock&& other) override;
+
+ ssize_t Send(const void* data, size_t len, int flags) const override;
+
+ ssize_t Recv(void* buf, size_t len, int flags) const override;
+
+ int Connect(const sockaddr*, socklen_t) const override;
+
+ int Bind(const sockaddr*, socklen_t) const override;
+
+ int Listen(int backlog) const override;
+
+ std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override;
+
+ int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
+
+ int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override;
+
+ int GetSockName(sockaddr* name, socklen_t* name_len) const override;
+
+ bool SetNonBlocking() const override;
+
+ bool IsSelectable() const override;
+
+ bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
+
+ bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;
+
+ bool IsConnected(std::string& errmsg) const override;
+};
+
+[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
+{
+ return FuzzedSock{fuzzed_data_provider};
+}
+
+inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
+}
+
+inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
+}
+
+CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
+
+template <bool ReturnUniquePtr = false>
+auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
+{
+ const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max()));
+ const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
+ const CAddress address = ConsumeAddress(fuzzed_data_provider);
+ const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
+ const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
+ const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
+ const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
+ const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
+ const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
+ NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
+ if constexpr (ReturnUniquePtr) {
+ return std::make_unique<CNode>(node_id,
+ sock,
+ address,
+ keyed_net_group,
+ local_host_nonce,
+ addr_bind,
+ addr_name,
+ conn_type,
+ inbound_onion,
+ CNodeOptions{ .permission_flags = permission_flags });
+ } else {
+ return CNode{node_id,
+ sock,
+ address,
+ keyed_net_group,
+ local_host_nonce,
+ addr_bind,
+ addr_name,
+ conn_type,
+ inbound_onion,
+ CNodeOptions{ .permission_flags = permission_flags }};
+ }
+}
+inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
+
+void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex);
+
+#endif // BITCOIN_TEST_FUZZ_UTIL_NET_H
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 8abb943266..7119643b45 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
index d96609416b..817593cf6e 100644
--- a/src/test/fuzz/validation_load_mempool.cpp
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,6 +12,7 @@
#include <test/fuzz/util.h>
#include <test/fuzz/util/mempool.h>
#include <test/util/setup_common.h>
+#include <test/util/txmempool.h>
#include <txmempool.h>
#include <util/time.h>
#include <validation.h>
diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp
index 95eb71099d..143027662f 100644
--- a/src/test/fuzz/versionbits.cpp
+++ b/src/test/fuzz/versionbits.cpp
@@ -55,7 +55,7 @@ public:
bool Condition(int32_t version) const
{
- uint32_t mask = ((uint32_t)1) << m_bit;
+ uint32_t mask = (uint32_t{1}) << m_bit;
return (((version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (version & mask) != 0);
}
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 70dd137e22..9c2d8a4dad 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -429,7 +429,7 @@ BOOST_AUTO_TEST_CASE(logargs)
const auto okaylog = std::make_pair("-okaylog", ArgsManager::ALLOW_ANY);
const auto dontlog = std::make_pair("-dontlog", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE);
SetupArgs(local_args, {okaylog_bool, okaylog_negbool, okaylog, dontlog});
- ResetArgs(local_args, "-okaylog-bool -nookaylog-negbool -okaylog=public -dontlog=private");
+ ResetArgs(local_args, "-okaylog-bool -nookaylog-negbool -okaylog=public -dontlog=private42");
// Everything logged to debug.log will also append to str
std::string str;
@@ -447,7 +447,7 @@ BOOST_AUTO_TEST_CASE(logargs)
BOOST_CHECK(str.find("Command-line arg: okaylog-negbool=false") != std::string::npos);
BOOST_CHECK(str.find("Command-line arg: okaylog=\"public\"") != std::string::npos);
BOOST_CHECK(str.find("dontlog=****") != std::string::npos);
- BOOST_CHECK(str.find("private") == std::string::npos);
+ BOOST_CHECK(str.find("private42") == std::string::npos);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index 5b5158884a..f1f435591b 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -5,6 +5,7 @@
#include <clientversion.h>
#include <crypto/siphash.h>
#include <hash.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <util/strencodings.h>
diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp
index 9da1ee11f9..3e20b527b5 100644
--- a/src/test/i2p_tests.cpp
+++ b/src/test/i2p_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021-2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,8 +8,8 @@
#include <test/util/logging.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
-#include <threadinterrupt.h>
#include <util/system.h>
+#include <util/threadinterrupt.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/interfaces_tests.cpp b/src/test/interfaces_tests.cpp
index cb901b2259..d37fe35a11 100644
--- a/src/test/interfaces_tests.cpp
+++ b/src/test/interfaces_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp
index 1eac68de14..a400afee71 100644
--- a/src/test/key_io_tests.cpp
+++ b/src/test/key_io_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,6 +8,7 @@
#include <key.h>
#include <key_io.h>
#include <script/script.h>
+#include <test/util/json.h>
#include <test/util/setup_common.h>
#include <util/strencodings.h>
@@ -15,8 +16,6 @@
#include <univalue.h>
-UniValue read_json(const std::string& jsondata);
-
BOOST_FIXTURE_TEST_SUITE(key_io_tests, BasicTestingSetup)
// Goal: check that parsed keys match test payload
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 8cb0515a8a..ea5b94f3a5 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,6 +6,7 @@
#include <key_io.h>
#include <streams.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <uint256.h>
#include <util/strencodings.h>
@@ -205,8 +206,7 @@ BOOST_AUTO_TEST_CASE(key_key_negation)
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
GetRandBytes(rnd);
- uint256 hash;
- CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
+ uint256 hash{Hash(str, rnd)};
// import the static test key
CKey key = DecodeSecret(strSecret1C);
@@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(key_key_negation)
static CPubKey UnserializePubkey(const std::vector<uint8_t>& data)
{
- CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
+ DataStream stream{};
stream << data;
CPubKey pubkey;
stream >> pubkey;
@@ -251,7 +251,7 @@ static unsigned int GetLen(unsigned char chHeader)
static void CmpSerializationPubkey(const CPubKey& pubkey)
{
- CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
+ DataStream stream{};
stream << pubkey;
CPubKey pubkey2;
stream >> pubkey2;
diff --git a/src/test/logging_tests.cpp b/src/test/logging_tests.cpp
index a6f3a62c71..beb9398c74 100644
--- a/src/test/logging_tests.cpp
+++ b/src/test/logging_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -75,20 +75,9 @@ struct LogSetup : public BasicTestingSetup {
BOOST_AUTO_TEST_CASE(logging_timer)
{
- SetMockTime(1);
auto micro_timer = BCLog::Timer<std::chrono::microseconds>("tests", "end_msg");
- SetMockTime(2);
- BOOST_CHECK_EQUAL(micro_timer.LogMsg("test micros"), "tests: test micros (1000000μs)");
-
- SetMockTime(1);
- auto ms_timer = BCLog::Timer<std::chrono::milliseconds>("tests", "end_msg");
- SetMockTime(2);
- BOOST_CHECK_EQUAL(ms_timer.LogMsg("test ms"), "tests: test ms (1000.00ms)");
-
- SetMockTime(1);
- auto sec_timer = BCLog::Timer<std::chrono::seconds>("tests", "end_msg");
- SetMockTime(2);
- BOOST_CHECK_EQUAL(sec_timer.LogMsg("test secs"), "tests: test secs (1.00s)");
+ const std::string_view result_prefix{"tests: msg ("};
+ BOOST_CHECK_EQUAL(micro_timer.LogMsg("msg").substr(0, result_prefix.size()), result_prefix);
}
BOOST_FIXTURE_TEST_CASE(logging_LogPrintf_, LogSetup)
diff --git a/src/test/main.cpp b/src/test/main.cpp
index 73bb331e21..0809f83c93 100644
--- a/src/test/main.cpp
+++ b/src/test/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 8c745b07b9..94e553a304 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -1,8 +1,9 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 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 <policy/policy.h>
+#include <test/util/txmempool.h>
#include <txmempool.h>
#include <util/system.h>
#include <util/time.h>
@@ -63,7 +64,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
CTxMemPool& testPool = *Assert(m_node.mempool);
- LOCK2(cs_main, testPool.cs);
+ LOCK2(::cs_main, testPool.cs);
// Nothing in pool, remove should do nothing:
unsigned int poolSize = testPool.size();
@@ -164,7 +165,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx5.vout.resize(1);
tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx5.vout[0].nValue = 11 * COIN;
- entry.nTime = 1;
+ entry.time = NodeSeconds{1s};
pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5));
BOOST_CHECK_EQUAL(pool.size(), 5U);
@@ -201,10 +202,9 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx7.vout[1].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx7.vout[1].nValue = 1 * COIN;
- CTxMemPool::setEntries setAncestorsCalculated;
- std::string dummy;
- BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
- BOOST_CHECK(setAncestorsCalculated == setAncestors);
+ auto ancestors_calculated{pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), CTxMemPool::Limits::NoLimits())};
+ BOOST_REQUIRE(ancestors_calculated.has_value());
+ BOOST_CHECK(*ancestors_calculated == setAncestors);
pool.addUnchecked(entry.FromTx(tx7), setAncestors);
BOOST_CHECK_EQUAL(pool.size(), 7U);
@@ -224,7 +224,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx8.vout[0].nValue = 10 * COIN;
setAncestors.insert(pool.mapTx.find(tx7.GetHash()));
- pool.addUnchecked(entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors);
+ pool.addUnchecked(entry.Fee(0LL).Time(NodeSeconds{2s}).FromTx(tx8), setAncestors);
// Now tx8 should be sorted low, but tx6/tx both high
sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString());
@@ -238,7 +238,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx9.vout.resize(1);
tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx9.vout[0].nValue = 1 * COIN;
- pool.addUnchecked(entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors);
+ pool.addUnchecked(entry.Fee(0LL).Time(NodeSeconds{3s}).FromTx(tx9), setAncestors);
// tx9 should be sorted low
BOOST_CHECK_EQUAL(pool.size(), 9U);
@@ -260,9 +260,9 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx10.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx10.vout[0].nValue = 10 * COIN;
- setAncestorsCalculated.clear();
- BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
- BOOST_CHECK(setAncestorsCalculated == setAncestors);
+ ancestors_calculated = pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(NodeSeconds{4s}).FromTx(tx10), CTxMemPool::Limits::NoLimits());
+ BOOST_REQUIRE(ancestors_calculated);
+ BOOST_CHECK(*ancestors_calculated == setAncestors);
pool.addUnchecked(entry.FromTx(tx10), setAncestors);
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index 942d54ede8..66f7be3c4e 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/merkle.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
@@ -50,7 +51,7 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
// For each of the lower bits in count that are 0, do 1 step. Each
// corresponds to an inner value that existed before processing the
// current leaf, and each needs a hash to combine it.
- for (level = 0; !(count & (((uint32_t)1) << level)); level++) {
+ for (level = 0; !(count & ((uint32_t{1}) << level)); level++) {
if (pbranch) {
if (matchh) {
pbranch->push_back(inner[level]);
@@ -60,7 +61,7 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
}
}
mutated |= (inner[level] == h);
- CHash256().Write(inner[level]).Write(h).Finalize(h);
+ h = Hash(inner[level], h);
}
// Store the resulting hash at inner position level.
inner[level] = h;
@@ -74,25 +75,25 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
int level = 0;
// As long as bit number level in count is zero, skip it. It means there
// is nothing left at this level.
- while (!(count & (((uint32_t)1) << level))) {
+ while (!(count & ((uint32_t{1}) << level))) {
level++;
}
uint256 h = inner[level];
bool matchh = matchlevel == level;
- while (count != (((uint32_t)1) << level)) {
+ while (count != ((uint32_t{1}) << level)) {
// If we reach this point, h is an inner value that is not the top.
// We combine it with itself (Bitcoin's special rule for odd levels in
// the tree) to produce a higher level one.
if (pbranch && matchh) {
pbranch->push_back(h);
}
- CHash256().Write(h).Write(h).Finalize(h);
+ h = Hash(h, h);
// Increment count to the value it would have if two entries at this
// level had existed.
- count += (((uint32_t)1) << level);
+ count += ((uint32_t{1}) << level);
level++;
// And propagate the result upwards accordingly.
- while (!(count & (((uint32_t)1) << level))) {
+ while (!(count & ((uint32_t{1}) << level))) {
if (pbranch) {
if (matchh) {
pbranch->push_back(inner[level]);
@@ -101,7 +102,7 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
matchh = true;
}
}
- CHash256().Write(inner[level]).Write(h).Finalize(h);
+ h = Hash(inner[level], h);
level++;
}
}
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index c7ce998f2d..cfab762307 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -1,8 +1,7 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 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 <chainparams.h>
#include <coins.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
@@ -10,6 +9,8 @@
#include <node/miner.h>
#include <policy/policy.h>
#include <script/standard.h>
+#include <test/util/random.h>
+#include <test/util/txmempool.h>
#include <timedata.h>
#include <txmempool.h>
#include <uint256.h>
@@ -30,15 +31,26 @@ using node::CBlockTemplate;
namespace miner_tests {
struct MinerTestingSetup : public TestingSetup {
- void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
- void TestBasicMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
- void TestPrioritisedMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
- bool TestSequenceLocks(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs)
+ void TestPackageSelection(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ void TestBasicMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ void TestPrioritisedMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ bool TestSequenceLocks(const CTransaction& tx, CTxMemPool& tx_mempool) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
- CCoinsViewMemPool view_mempool(&m_node.chainman->ActiveChainstate().CoinsTip(), *m_node.mempool);
- return CheckSequenceLocksAtTip(m_node.chainman->ActiveChain().Tip(), view_mempool, tx);
+ CCoinsViewMemPool view_mempool{&m_node.chainman->ActiveChainstate().CoinsTip(), tx_mempool};
+ CBlockIndex* tip{m_node.chainman->ActiveChain().Tip()};
+ const std::optional<LockPoints> lock_points{CalculateLockPointsAtTip(tip, view_mempool, tx)};
+ return lock_points.has_value() && CheckSequenceLocksAtTip(tip, *lock_points);
}
- BlockAssembler AssemblerForTest(const CChainParams& params);
+ CTxMemPool& MakeMempool()
+ {
+ // Delete the previous mempool to ensure with valgrind that the old
+ // pointer is not accessed, when the new one should be accessed
+ // instead.
+ m_node.mempool.reset();
+ m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node));
+ return *m_node.mempool;
+ }
+ BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool);
};
} // namespace miner_tests
@@ -46,13 +58,13 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup)
static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
-BlockAssembler MinerTestingSetup::AssemblerForTest(const CChainParams& params)
+BlockAssembler MinerTestingSetup::AssemblerForTest(CTxMemPool& tx_mempool)
{
BlockAssembler::Options options;
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
options.blockMinFeeRate = blockMinFeeRate;
- return BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options};
+ return BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options};
}
constexpr static struct {
@@ -78,19 +90,21 @@ constexpr static struct {
{0, 792342903}, {6, 678455063}, {6, 773251385}, {5, 186617471}, {6, 883189502}, {7, 396077336},
{8, 254702874}, {0, 455592851}};
-static CBlockIndex CreateBlockIndex(int nHeight, CBlockIndex* active_chain_tip) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static std::unique_ptr<CBlockIndex> CreateBlockIndex(int nHeight, CBlockIndex* active_chain_tip) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- CBlockIndex index;
- index.nHeight = nHeight;
- index.pprev = active_chain_tip;
+ auto index{std::make_unique<CBlockIndex>()};
+ index->nHeight = nHeight;
+ index->pprev = active_chain_tip;
return index;
}
// Test suite for ancestor feerate transaction selection.
// Implemented as an additional function, rather than a separate test case,
// to allow reusing the blockchain created in CreateNewBlock_validity.
-void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
+void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
{
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
// Test the ancestor feerate transaction selection.
TestMemPoolEntryHelper entry;
@@ -105,21 +119,21 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue = 5000000000LL - 1000;
// This tx has a low fee: 1000 satoshis
uint256 hashParentTx = tx.GetHash(); // save this txid for later use
- m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
// This tx has a medium fee: 10000 satoshis
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vout[0].nValue = 5000000000LL - 10000;
uint256 hashMediumFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
// This tx has a high fee, but depends on the first transaction
tx.vin[0].prevout.hash = hashParentTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee
uint256 hashHighFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
- std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U);
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx);
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx);
@@ -129,7 +143,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vin[0].prevout.hash = hashHighFeeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee
uint256 hashFreeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(0).FromTx(tx));
size_t freeTxSize = ::GetSerializeSize(tx, PROTOCOL_VERSION);
// Calculate a fee on child transaction that will put the package just
@@ -139,8 +153,8 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vin[0].prevout.hash = hashFreeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
uint256 hashLowFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ tx_mempool.addUnchecked(entry.Fee(feeToUse).FromTx(tx));
+ pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
// Verify that the free tx and the low fee tx didn't get selected
for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx);
@@ -150,11 +164,11 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
// Test that packages above the min relay fee do get included, even if one
// of the transactions is below the min relay fee
// Remove the low fee transaction and replace with a higher fee transaction
- m_node.mempool->removeRecursive(CTransaction(tx), MemPoolRemovalReason::REPLACED);
+ tx_mempool.removeRecursive(CTransaction(tx), MemPoolRemovalReason::REPLACED);
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
hashLowFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(feeToUse+2).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ tx_mempool.addUnchecked(entry.Fee(feeToUse + 2).FromTx(tx));
+ pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx);
@@ -167,7 +181,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue = 5000000000LL - 100000000;
tx.vout[1].nValue = 100000000; // 1BTC output
uint256 hashFreeTx2 = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
// This tx can't be mined by itself
tx.vin[0].prevout.hash = hashFreeTx2;
@@ -175,8 +189,8 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
feeToUse = blockMinFeeRate.GetFee(freeTxSize);
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
uint256 hashLowFeeTx2 = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ tx_mempool.addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
+ pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
// Verify that this tx isn't selected.
for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
@@ -188,13 +202,13 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
// as well.
tx.vin[0].prevout.n = 1;
tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee
- m_node.mempool->addUnchecked(entry.Fee(10000).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ tx_mempool.addUnchecked(entry.Fee(10000).FromTx(tx));
+ pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 9U);
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
}
-void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight)
+void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight)
{
uint256 hash;
CMutableTransaction tx;
@@ -202,172 +216,205 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
entry.nFee = 11;
entry.nHeight = 11;
- // Just to make sure we can still make simple blocks
- auto pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
- BOOST_CHECK(pblocktemplate);
-
- const CAmount BLOCKSUBSIDY = 50*COIN;
+ const CAmount BLOCKSUBSIDY = 50 * COIN;
const CAmount LOWFEE = CENT;
const CAmount HIGHFEE = COIN;
- const CAmount HIGHERFEE = 4*COIN;
+ const CAmount HIGHERFEE = 4 * COIN;
- // block sigops > limit: 1000 CHECKMULTISIG + 1
- tx.vin.resize(1);
- // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG
- tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1;
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vin[0].prevout.n = 0;
- tx.vout.resize(1);
- tx.vout[0].nValue = BLOCKSUBSIDY;
- for (unsigned int i = 0; i < 1001; ++i)
{
- tx.vout[0].nValue -= LOWFEE;
- hash = tx.GetHash();
- bool spendsCoinbase = i == 0; // only first tx spends coinbase
- // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // Just to make sure we can still make simple blocks
+ auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
+ BOOST_CHECK(pblocktemplate);
+
+ // block sigops > limit: 1000 CHECKMULTISIG + 1
+ tx.vin.resize(1);
+ // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG
+ tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1;
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = BLOCKSUBSIDY;
+ for (unsigned int i = 0; i < 1001; ++i) {
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ bool spendsCoinbase = i == 0; // only first tx spends coinbase
+ // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ }
+
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
}
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
- m_node.mempool->clear();
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vout[0].nValue = BLOCKSUBSIDY;
+ for (unsigned int i = 0; i < 1001; ++i) {
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ bool spendsCoinbase = i == 0; // only first tx spends coinbase
+ // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ }
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ }
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vout[0].nValue = BLOCKSUBSIDY;
- for (unsigned int i = 0; i < 1001; ++i)
{
- tx.vout[0].nValue -= LOWFEE;
- hash = tx.GetHash();
- bool spendsCoinbase = i == 0; // only first tx spends coinbase
- // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // block size > limit
+ tx.vin[0].scriptSig = CScript();
+ // 18 * (520char + DROP) + OP_1 = 9433 bytes
+ std::vector<unsigned char> vchData(520);
+ for (unsigned int i = 0; i < 18; ++i) {
+ tx.vin[0].scriptSig << vchData << OP_DROP;
+ }
+ tx.vin[0].scriptSig << OP_1;
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vout[0].nValue = BLOCKSUBSIDY;
+ for (unsigned int i = 0; i < 128; ++i) {
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ bool spendsCoinbase = i == 0; // only first tx spends coinbase
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ }
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- m_node.mempool->clear();
-
- // block size > limit
- tx.vin[0].scriptSig = CScript();
- // 18 * (520char + DROP) + OP_1 = 9433 bytes
- std::vector<unsigned char> vchData(520);
- for (unsigned int i = 0; i < 18; ++i)
- tx.vin[0].scriptSig << vchData << OP_DROP;
- tx.vin[0].scriptSig << OP_1;
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vout[0].nValue = BLOCKSUBSIDY;
- for (unsigned int i = 0; i < 128; ++i)
+
{
- tx.vout[0].nValue -= LOWFEE;
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // orphan in tx_mempool, template creation fails
hash = tx.GetHash();
- bool spendsCoinbase = i == 0; // only first tx spends coinbase
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).FromTx(tx));
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- m_node.mempool->clear();
- // orphan in *m_node.mempool, template creation fails
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
- m_node.mempool->clear();
-
- // child with higher feerate than parent
- tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vin[0].prevout.hash = txFirst[1]->GetHash();
- tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
- tx.vin.resize(2);
- tx.vin[1].scriptSig = CScript() << OP_1;
- tx.vin[1].prevout.hash = txFirst[0]->GetHash();
- tx.vin[1].prevout.n = 0;
- tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- m_node.mempool->clear();
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
- // coinbase in *m_node.mempool, template creation fails
- tx.vin.resize(1);
- tx.vin[0].prevout.SetNull();
- tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
- tx.vout[0].nValue = 0;
- hash = tx.GetHash();
- // give it a fee so it'll get mined
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- // Should throw bad-cb-multiple
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
- m_node.mempool->clear();
+ // child with higher feerate than parent
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vin[0].prevout.hash = txFirst[1]->GetHash();
+ tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ tx.vin.resize(2);
+ tx.vin[1].scriptSig = CScript() << OP_1;
+ tx.vin[1].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[1].prevout.n = 0;
+ tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; // First txn output + fresh coinbase - new txn fee
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(HIGHERFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ }
- // double spend txn pair in *m_node.mempool, template creation fails
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
- tx.vout[0].scriptPubKey = CScript() << OP_1;
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- tx.vout[0].scriptPubKey = CScript() << OP_2;
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
- m_node.mempool->clear();
-
- // subsidy changing
- int nHeight = m_node.chainman->ActiveChain().Height();
- // Create an actual 209999-long block chain (without valid blocks).
- while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) {
- CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
- CBlockIndex* next = new CBlockIndex();
- next->phashBlock = new uint256(InsecureRand256());
- m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
- next->pprev = prev;
- next->nHeight = prev->nHeight + 1;
- next->BuildSkip();
- m_node.chainman->ActiveChain().SetTip(*next);
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // coinbase in tx_mempool, template creation fails
+ tx.vin.resize(1);
+ tx.vin[0].prevout.SetNull();
+ tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
+ tx.vout[0].nValue = 0;
+ hash = tx.GetHash();
+ // give it a fee so it'll get mined
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
+ // Should throw bad-cb-multiple
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- // Extend to a 210000-long block chain.
- while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) {
- CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
- CBlockIndex* next = new CBlockIndex();
- next->phashBlock = new uint256(InsecureRand256());
- m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
- next->pprev = prev;
- next->nHeight = prev->nHeight + 1;
- next->BuildSkip();
- m_node.chainman->ActiveChain().SetTip(*next);
+
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // double spend txn pair in tx_mempool, template creation fails
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
+ tx.vout[0].scriptPubKey = CScript() << OP_1;
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
+ tx.vout[0].scriptPubKey = CScript() << OP_2;
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- // invalid p2sh txn in *m_node.mempool, template creation fails
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vin[0].prevout.n = 0;
- tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
- CScript script = CScript() << OP_0;
- tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
- tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
- tx.vout[0].nValue -= LOWFEE;
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- // Should throw block-validation-failed
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
- m_node.mempool->clear();
-
- // Delete the dummy blocks again.
- while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) {
- CBlockIndex* del = m_node.chainman->ActiveChain().Tip();
- m_node.chainman->ActiveChain().SetTip(*Assert(del->pprev));
- m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(del->pprev->GetBlockHash());
- delete del->phashBlock;
- delete del;
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // subsidy changing
+ int nHeight = m_node.chainman->ActiveChain().Height();
+ // Create an actual 209999-long block chain (without valid blocks).
+ while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) {
+ CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
+ CBlockIndex* next = new CBlockIndex();
+ next->phashBlock = new uint256(InsecureRand256());
+ m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
+ next->pprev = prev;
+ next->nHeight = prev->nHeight + 1;
+ next->BuildSkip();
+ m_node.chainman->ActiveChain().SetTip(*next);
+ }
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ // Extend to a 210000-long block chain.
+ while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) {
+ CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
+ CBlockIndex* next = new CBlockIndex();
+ next->phashBlock = new uint256(InsecureRand256());
+ m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
+ next->pprev = prev;
+ next->nHeight = prev->nHeight + 1;
+ next->BuildSkip();
+ m_node.chainman->ActiveChain().SetTip(*next);
+ }
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+
+ // invalid p2sh txn in tx_mempool, template creation fails
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE;
+ CScript script = CScript() << OP_0;
+ tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
+ // Should throw block-validation-failed
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
+
+ // Delete the dummy blocks again.
+ while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) {
+ CBlockIndex* del = m_node.chainman->ActiveChain().Tip();
+ m_node.chainman->ActiveChain().SetTip(*Assert(del->pprev));
+ m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(del->pprev->GetBlockHash());
+ delete del->phashBlock;
+ delete del;
+ }
}
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
// non-final txs in mempool
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1);
const int flags{LOCKTIME_VERIFY_SEQUENCE};
@@ -388,13 +435,13 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
tx.vout[0].scriptPubKey = CScript() << OP_1;
tx.nLockTime = 0;
hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes
- BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
+ BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
{
CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip();
- BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 2, active_chain_tip))); // Sequence locks pass on 2nd block
+ BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, *CreateBlockIndex(active_chain_tip->nHeight + 2, active_chain_tip))); // Sequence locks pass on 2nd block
}
// relative time locked
@@ -402,16 +449,16 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((m_node.chainman->ActiveChain().Tip()->GetMedianTimePast()+1-m_node.chainman->ActiveChain()[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block
prevheights[0] = baseheight + 2;
hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Time(Now<NodeSeconds>()).FromTx(tx));
BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes
- BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
+ BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
const int SEQUENCE_LOCK_TIME = 512; // Sequence locks pass 512 seconds later
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i)
m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime += SEQUENCE_LOCK_TIME; // Trick the MedianTimePast
{
CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip();
- BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 1, active_chain_tip)));
+ BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, *CreateBlockIndex(active_chain_tip->nHeight + 1, active_chain_tip)));
}
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i) {
@@ -425,9 +472,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
prevheights[0] = baseheight + 3;
tx.nLockTime = m_node.chainman->ActiveChain().Tip()->nHeight + 1;
hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Time(Now<NodeSeconds>()).FromTx(tx));
BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails
- BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
+ BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass
BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block
// absolute time locked
@@ -436,9 +483,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
prevheights.resize(1);
prevheights[0] = baseheight + 4;
hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Time(Now<NodeSeconds>()).FromTx(tx));
BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails
- BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
+ BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass
BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later
// mempool-dependent transactions (not added)
@@ -447,15 +494,16 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
tx.nLockTime = 0;
tx.vin[0].nSequence = 0;
BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes
- BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
+ BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass
tx.vin[0].nSequence = 1;
- BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
+ BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG;
- BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
+ BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
- BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
+ BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
+ BOOST_CHECK(pblocktemplate);
// None of the of the absolute height/time locked tx should have made
// it into the template because we still check IsFinalTx in CreateNewBlock,
@@ -470,12 +518,15 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
m_node.chainman->ActiveChain().Tip()->nHeight++;
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1);
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
}
-void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
+void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
{
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
TestMemPoolEntryHelper entry;
// Test that a tx below min fee but prioritised is included
@@ -487,29 +538,29 @@ void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, c
tx.vout.resize(1);
tx.vout[0].nValue = 5000000000LL; // 0 fee
uint256 hashFreePrioritisedTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(0).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN);
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vin[0].prevout.n = 0;
tx.vout[0].nValue = 5000000000LL - 1000;
// This tx has a low fee: 1000 satoshis
uint256 hashParentTx = tx.GetHash(); // save this txid for later use
- m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
// This tx has a medium fee: 10000 satoshis
tx.vin[0].prevout.hash = txFirst[2]->GetHash();
tx.vout[0].nValue = 5000000000LL - 10000;
uint256 hashMediumFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashMediumFeeTx, -5 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashMediumFeeTx, -5 * COIN);
// This tx also has a low fee, but is prioritised
tx.vin[0].prevout.hash = hashParentTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 1000; // 1000 satoshi fee
uint256 hashPrioritsedChild = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashPrioritsedChild, 2 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashPrioritsedChild, 2 * COIN);
// Test that transaction selection properly updates ancestor fee calculations as prioritised
// parents get included in a block. Create a transaction with two prioritised ancestors, each
@@ -520,21 +571,21 @@ void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, c
tx.vin[0].prevout.hash = txFirst[3]->GetHash();
tx.vout[0].nValue = 5000000000LL; // 0 fee
uint256 hashFreeParent = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashFreeParent, 10 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashFreeParent, 10 * COIN);
tx.vin[0].prevout.hash = hashFreeParent;
tx.vout[0].nValue = 5000000000LL; // 0 fee
uint256 hashFreeChild = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashFreeChild, 1 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashFreeChild, 1 * COIN);
tx.vin[0].prevout.hash = hashFreeChild;
tx.vout[0].nValue = 5000000000LL; // 0 fee
uint256 hashFreeGrandchild = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
- auto pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashFreeParent);
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashFreePrioritisedTx);
@@ -553,13 +604,12 @@ void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, c
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
// Note that by default, these tests run with size accounting enabled.
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
- const CChainParams& chainparams = *chainParams;
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
std::unique_ptr<CBlockTemplate> pblocktemplate;
+ CTxMemPool& tx_mempool{*m_node.mempool};
// Simple block creation, nothing special yet:
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
// We can't make transactions until we have inputs
// Therefore, load 110 blocks :)
@@ -591,21 +641,18 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
}
LOCK(cs_main);
- LOCK(m_node.mempool->cs);
- TestBasicMining(chainparams, scriptPubKey, txFirst, baseheight);
+ TestBasicMining(scriptPubKey, txFirst, baseheight);
m_node.chainman->ActiveChain().Tip()->nHeight--;
SetMockTime(0);
- m_node.mempool->clear();
- TestPackageSelection(chainparams, scriptPubKey, txFirst);
+ TestPackageSelection(scriptPubKey, txFirst);
m_node.chainman->ActiveChain().Tip()->nHeight--;
SetMockTime(0);
- m_node.mempool->clear();
- TestPrioritisedMining(chainparams, scriptPubKey, txFirst);
+ TestPrioritisedMining(scriptPubKey, txFirst);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp
index 9387c01e73..655d6d7828 100644
--- a/src/test/miniscript_tests.cpp
+++ b/src/test/miniscript_tests.cpp
@@ -1,19 +1,24 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2022 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 <stdint.h>
#include <string>
+#include <vector>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
+#include <core_io.h>
#include <hash.h>
#include <pubkey.h>
#include <uint256.h>
#include <crypto/ripemd160.h>
#include <crypto/sha256.h>
+#include <script/interpreter.h>
#include <script/miniscript.h>
+#include <script/standard.h>
+#include <script/script_error.h>
namespace {
@@ -24,15 +29,22 @@ struct TestData {
//! A map from the public keys to their CKeyIDs (faster than hashing every time).
std::map<CPubKey, CKeyID> pkhashes;
std::map<CKeyID, CPubKey> pkmap;
+ std::map<CPubKey, std::vector<unsigned char>> signatures;
// Various precomputed hashes
std::vector<std::vector<unsigned char>> sha256;
std::vector<std::vector<unsigned char>> ripemd160;
std::vector<std::vector<unsigned char>> hash256;
std::vector<std::vector<unsigned char>> hash160;
+ std::map<std::vector<unsigned char>, std::vector<unsigned char>> sha256_preimages;
+ std::map<std::vector<unsigned char>, std::vector<unsigned char>> ripemd160_preimages;
+ std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash256_preimages;
+ std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash160_preimages;
TestData()
{
+ // All our signatures sign (and are required to sign) this constant message.
+ auto const MESSAGE_HASH = uint256S("f5cd94e18b6fe77dd7aca9e35c2b0c9cbd86356c80a71065");
// We generate 255 public keys and 255 hashes of each type.
for (int i = 1; i <= 255; ++i) {
// This 32-byte array functions as both private key data and hash preimage (31 zero bytes plus any nonzero byte).
@@ -48,18 +60,28 @@ struct TestData {
pkhashes.emplace(pubkey, keyid);
pkmap.emplace(keyid, pubkey);
+ // Compute ECDSA signatures on MESSAGE_HASH with the private keys.
+ std::vector<unsigned char> sig;
+ BOOST_CHECK(key.Sign(MESSAGE_HASH, sig));
+ sig.push_back(1); // sighash byte
+ signatures.emplace(pubkey, sig);
+
// Compute various hashes
std::vector<unsigned char> hash;
hash.resize(32);
CSHA256().Write(keydata, 32).Finalize(hash.data());
sha256.push_back(hash);
+ sha256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
CHash256().Write(keydata).Finalize(hash);
hash256.push_back(hash);
+ hash256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
hash.resize(20);
CRIPEMD160().Write(keydata, 32).Finalize(hash.data());
ripemd160.push_back(hash);
+ ripemd160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
CHash160().Write(keydata).Finalize(hash);
hash160.push_back(hash);
+ hash160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
}
}
};
@@ -67,7 +89,27 @@ struct TestData {
//! Global TestData object
std::unique_ptr<const TestData> g_testdata;
-/** A class encapsulating conversion routing for CPubKey. */
+//! A classification of leaf conditions in miniscripts (excluding true/false).
+enum class ChallengeType {
+ SHA256,
+ RIPEMD160,
+ HASH256,
+ HASH160,
+ OLDER,
+ AFTER,
+ PK
+};
+
+/* With each leaf condition we associate a challenge number.
+ * For hashes it's just the first 4 bytes of the hash. For pubkeys, it's the last 4 bytes.
+ */
+uint32_t ChallengeNumber(const CPubKey& pubkey) { return ReadLE32(pubkey.data() + 29); }
+uint32_t ChallengeNumber(const std::vector<unsigned char>& hash) { return ReadLE32(hash.data()); }
+
+//! A Challenge is a combination of type of leaf condition and its challenge number.
+typedef std::pair<ChallengeType, uint32_t> Challenge;
+
+/** A class encapulating conversion routing for CPubKey. */
struct KeyConverter {
typedef CPubKey Key;
@@ -117,12 +159,197 @@ struct KeyConverter {
}
};
+/** A class that encapsulates all signing/hash revealing operations. */
+struct Satisfier : public KeyConverter {
+ //! Which keys/timelocks/hash preimages are available.
+ std::set<Challenge> supported;
+
+ //! Implement simplified CLTV logic: stack value must exactly match an entry in `supported`.
+ bool CheckAfter(uint32_t value) const {
+ return supported.count(Challenge(ChallengeType::AFTER, value));
+ }
+
+ //! Implement simplified CSV logic: stack value must exactly match an entry in `supported`.
+ bool CheckOlder(uint32_t value) const {
+ return supported.count(Challenge(ChallengeType::OLDER, value));
+ }
+
+ //! Produce a signature for the given key.
+ miniscript::Availability Sign(const CPubKey& key, std::vector<unsigned char>& sig) const {
+ if (supported.count(Challenge(ChallengeType::PK, ChallengeNumber(key)))) {
+ auto it = g_testdata->signatures.find(key);
+ if (it == g_testdata->signatures.end()) return miniscript::Availability::NO;
+ sig = it->second;
+ return miniscript::Availability::YES;
+ }
+ return miniscript::Availability::NO;
+ }
+
+ //! Helper function for the various hash based satisfactions.
+ miniscript::Availability SatHash(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage, ChallengeType chtype) const {
+ if (!supported.count(Challenge(chtype, ChallengeNumber(hash)))) return miniscript::Availability::NO;
+ const auto& m =
+ chtype == ChallengeType::SHA256 ? g_testdata->sha256_preimages :
+ chtype == ChallengeType::HASH256 ? g_testdata->hash256_preimages :
+ chtype == ChallengeType::RIPEMD160 ? g_testdata->ripemd160_preimages :
+ g_testdata->hash160_preimages;
+ auto it = m.find(hash);
+ if (it == m.end()) return miniscript::Availability::NO;
+ preimage = it->second;
+ return miniscript::Availability::YES;
+ }
+
+ // Functions that produce the preimage for hashes of various types.
+ miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::SHA256); }
+ miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::RIPEMD160); }
+ miniscript::Availability SatHASH256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::HASH256); }
+ miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::HASH160); }
+};
+
+/** Mocking signature/timelock checker.
+ *
+ * It holds a pointer to a Satisfier object, to determine which timelocks are supposed to be available.
+ */
+class TestSignatureChecker : public BaseSignatureChecker {
+ const Satisfier& ctx;
+
+public:
+ TestSignatureChecker(const Satisfier& in_ctx LIFETIMEBOUND) : ctx(in_ctx) {}
+
+ bool CheckECDSASignature(const std::vector<unsigned char>& sig, const std::vector<unsigned char>& pubkey, const CScript& scriptcode, SigVersion sigversion) const override {
+ CPubKey pk(pubkey);
+ if (!pk.IsValid()) return false;
+ // Instead of actually running signature validation, check if the signature matches the precomputed one for this key.
+ auto it = g_testdata->signatures.find(pk);
+ if (it == g_testdata->signatures.end()) return false;
+ return sig == it->second;
+ }
+
+ bool CheckLockTime(const CScriptNum& locktime) const override {
+ // Delegate to Satisfier.
+ return ctx.CheckAfter(locktime.GetInt64());
+ }
+
+ bool CheckSequence(const CScriptNum& sequence) const override {
+ // Delegate to Satisfier.
+ return ctx.CheckOlder(sequence.GetInt64());
+ }
+};
+
//! Singleton instance of KeyConverter.
const KeyConverter CONVERTER{};
+using Fragment = miniscript::Fragment;
+using NodeRef = miniscript::NodeRef<CPubKey>;
// https://github.com/llvm/llvm-project/issues/53444
// NOLINTNEXTLINE(misc-unused-using-decls)
using miniscript::operator"" _mst;
+using Node = miniscript::Node<CPubKey>;
+
+/** Compute all challenges (pubkeys, hashes, timelocks) that occur in a given Miniscript. */
+std::set<Challenge> FindChallenges(const NodeRef& ref) {
+ std::set<Challenge> chal;
+ for (const auto& key : ref->keys) {
+ chal.emplace(ChallengeType::PK, ChallengeNumber(key));
+ }
+ if (ref->fragment == miniscript::Fragment::OLDER) {
+ chal.emplace(ChallengeType::OLDER, ref->k);
+ } else if (ref->fragment == miniscript::Fragment::AFTER) {
+ chal.emplace(ChallengeType::AFTER, ref->k);
+ } else if (ref->fragment == miniscript::Fragment::SHA256) {
+ chal.emplace(ChallengeType::SHA256, ChallengeNumber(ref->data));
+ } else if (ref->fragment == miniscript::Fragment::RIPEMD160) {
+ chal.emplace(ChallengeType::RIPEMD160, ChallengeNumber(ref->data));
+ } else if (ref->fragment == miniscript::Fragment::HASH256) {
+ chal.emplace(ChallengeType::HASH256, ChallengeNumber(ref->data));
+ } else if (ref->fragment == miniscript::Fragment::HASH160) {
+ chal.emplace(ChallengeType::HASH160, ChallengeNumber(ref->data));
+ }
+ for (const auto& sub : ref->subs) {
+ auto sub_chal = FindChallenges(sub);
+ chal.insert(sub_chal.begin(), sub_chal.end());
+ }
+ return chal;
+}
+
+/** Run random satisfaction tests. */
+void TestSatisfy(const std::string& testcase, const NodeRef& node) {
+ auto script = node->ToScript(CONVERTER);
+ auto challenges = FindChallenges(node); // Find all challenges in the generated miniscript.
+ std::vector<Challenge> challist(challenges.begin(), challenges.end());
+ for (int iter = 0; iter < 3; ++iter) {
+ Shuffle(challist.begin(), challist.end(), g_insecure_rand_ctx);
+ Satisfier satisfier;
+ TestSignatureChecker checker(satisfier);
+ bool prev_mal_success = false, prev_nonmal_success = false;
+ // Go over all challenges involved in this miniscript in random order.
+ for (int add = -1; add < (int)challist.size(); ++add) {
+ if (add >= 0) satisfier.supported.insert(challist[add]); // The first iteration does not add anything
+
+ // Run malleable satisfaction algorithm.
+ const CScript script_pubkey = CScript() << OP_0 << WitnessV0ScriptHash(script);
+ CScriptWitness witness_mal;
+ const bool mal_success = node->Satisfy(satisfier, witness_mal.stack, false) == miniscript::Availability::YES;
+ witness_mal.stack.push_back(std::vector<unsigned char>(script.begin(), script.end()));
+
+ // Run non-malleable satisfaction algorithm.
+ CScriptWitness witness_nonmal;
+ const bool nonmal_success = node->Satisfy(satisfier, witness_nonmal.stack, true) == miniscript::Availability::YES;
+ witness_nonmal.stack.push_back(std::vector<unsigned char>(script.begin(), script.end()));
+
+ if (nonmal_success) {
+ // Non-malleable satisfactions are bounded by GetStackSize().
+ BOOST_CHECK(witness_nonmal.stack.size() <= node->GetStackSize());
+ // If a non-malleable satisfaction exists, the malleable one must also exist, and be identical to it.
+ BOOST_CHECK(mal_success);
+ BOOST_CHECK(witness_nonmal.stack == witness_mal.stack);
+
+ // Test non-malleable satisfaction.
+ ScriptError serror;
+ bool res = VerifyScript(CScript(), script_pubkey, &witness_nonmal, STANDARD_SCRIPT_VERIFY_FLAGS, checker, &serror);
+ // Non-malleable satisfactions are guaranteed to be valid if ValidSatisfactions().
+ if (node->ValidSatisfactions()) BOOST_CHECK(res);
+ // More detailed: non-malleable satisfactions must be valid, or could fail with ops count error (if CheckOpsLimit failed),
+ // or with a stack size error (if CheckStackSize check fails).
+ BOOST_CHECK(res ||
+ (!node->CheckOpsLimit() && serror == ScriptError::SCRIPT_ERR_OP_COUNT) ||
+ (!node->CheckStackSize() && serror == ScriptError::SCRIPT_ERR_STACK_SIZE));
+ }
+
+ if (mal_success && (!nonmal_success || witness_mal.stack != witness_nonmal.stack)) {
+ // Test malleable satisfaction only if it's different from the non-malleable one.
+ ScriptError serror;
+ bool res = VerifyScript(CScript(), script_pubkey, &witness_mal, STANDARD_SCRIPT_VERIFY_FLAGS, checker, &serror);
+ // Malleable satisfactions are not guaranteed to be valid under any conditions, but they can only
+ // fail due to stack or ops limits.
+ BOOST_CHECK(res || serror == ScriptError::SCRIPT_ERR_OP_COUNT || serror == ScriptError::SCRIPT_ERR_STACK_SIZE);
+ }
+
+ if (node->IsSane()) {
+ // For sane nodes, the two algorithms behave identically.
+ BOOST_CHECK_EQUAL(mal_success, nonmal_success);
+ }
+
+ // Adding more satisfied conditions can never remove our ability to produce a satisfaction.
+ BOOST_CHECK(mal_success >= prev_mal_success);
+ // For nonmalleable solutions this is only true if the added condition is PK;
+ // for other conditions, adding one may make an valid satisfaction become malleable. If the script
+ // is sane, this cannot happen however.
+ if (node->IsSane() || add < 0 || challist[add].first == ChallengeType::PK) {
+ BOOST_CHECK(nonmal_success >= prev_nonmal_success);
+ }
+ // Remember results for the next added challenge.
+ prev_mal_success = mal_success;
+ prev_nonmal_success = nonmal_success;
+ }
+
+ bool satisfiable = node->IsSatisfiable([](const Node&) { return true; });
+ // If the miniscript was satisfiable at all, a satisfaction must be found after all conditions are added.
+ BOOST_CHECK_EQUAL(prev_mal_success, satisfiable);
+ // If the miniscript is sane and satisfiable, a nonmalleable satisfaction must eventually be found.
+ if (node->IsSane()) BOOST_CHECK_EQUAL(prev_nonmal_success, satisfiable);
+ }
+}
enum TestMode : int {
TESTMODE_INVALID = 0,
@@ -152,6 +379,7 @@ void Test(const std::string& ms, const std::string& hexscript, int mode, int ops
BOOST_CHECK_MESSAGE(inferred_miniscript->ToScript(CONVERTER) == computed_script, "Roundtrip failure: miniscript->script != miniscript->script->miniscript->script: " + ms);
if (opslimit != -1) BOOST_CHECK_MESSAGE((int)node->GetOps() == opslimit, "Ops limit mismatch: " << ms << " (" << node->GetOps() << " vs " << opslimit << ")");
if (stacklimit != -1) BOOST_CHECK_MESSAGE((int)node->GetStackSize() == stacklimit, "Stack limit mismatch: " << ms << " (" << node->GetStackSize() << " vs " << stacklimit << ")");
+ TestSatisfy(ms, node);
}
}
} // namespace
diff --git a/src/test/minisketch_tests.cpp b/src/test/minisketch_tests.cpp
index 81f2aad623..10506da783 100644
--- a/src/test/minisketch_tests.cpp
+++ b/src/test/minisketch_tests.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 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 <minisketch.h>
#include <node/minisketchwrapper.h>
#include <random.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index ce23d6013d..7a3e8e3a47 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -217,7 +217,8 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
for (int i = 0; i < 3; i++)
{
- BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
+ SignatureData empty;
+ BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));
}
}
diff --git a/src/test/net_peer_eviction_tests.cpp b/src/test/net_peer_eviction_tests.cpp
index d519a4442f..51d6c4384a 100644
--- a/src/test/net_peer_eviction_tests.cpp
+++ b/src/test/net_peer_eviction_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index f24509dd97..4fbd9b3a6e 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(addr.IsBindAny());
BOOST_CHECK(addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "0.0.0.0");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "0.0.0.0");
// IPv4, INADDR_NONE
BOOST_REQUIRE(LookupHost("255.255.255.255", addr, false));
@@ -150,7 +150,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(!addr.IsBindAny());
BOOST_CHECK(addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "255.255.255.255");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "255.255.255.255");
// IPv4, casual
BOOST_REQUIRE(LookupHost("12.34.56.78", addr, false));
@@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(!addr.IsBindAny());
BOOST_CHECK(addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "12.34.56.78");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "12.34.56.78");
// IPv6, in6addr_any
BOOST_REQUIRE(LookupHost("::", addr, false));
@@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(addr.IsBindAny());
BOOST_CHECK(addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "::");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "::");
// IPv6, casual
BOOST_REQUIRE(LookupHost("1122:3344:5566:7788:9900:aabb:ccdd:eeff", addr, false));
@@ -177,7 +177,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(!addr.IsBindAny());
BOOST_CHECK(addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff");
// IPv6, scoped/link-local. See https://tools.ietf.org/html/rfc4007
// We support non-negative decimal integers (uint32_t) as zone id indices.
@@ -190,14 +190,14 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_REQUIRE(addr.IsValid());
BOOST_REQUIRE(addr.IsIPv6());
BOOST_CHECK(!addr.IsBindAny());
- BOOST_CHECK_EQUAL(addr.ToString(), scoped_addr);
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), scoped_addr);
// Test that the delimiter "%" and default zone id of 0 can be omitted for the default scope.
BOOST_REQUIRE(LookupHost(link_local + "%0", addr, false));
BOOST_REQUIRE(addr.IsValid());
BOOST_REQUIRE(addr.IsIPv6());
BOOST_CHECK(!addr.IsBindAny());
- BOOST_CHECK_EQUAL(addr.ToString(), link_local);
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), link_local);
// TORv2, no longer supported
BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
@@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(!addr.IsI2P());
BOOST_CHECK(!addr.IsBindAny());
BOOST_CHECK(!addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), torv3_addr);
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), torv3_addr);
// TORv3, broken, with wrong checksum
BOOST_CHECK(!addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscsad.onion"));
@@ -238,7 +238,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(!addr.IsTor());
BOOST_CHECK(!addr.IsBindAny());
BOOST_CHECK(!addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), ToLower(i2p_addr));
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), ToLower(i2p_addr));
// I2P, correct length, but decodes to less than the expected number of bytes.
BOOST_CHECK(!addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jn=.b32.i2p"));
@@ -265,7 +265,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(!addr.IsBindAny());
BOOST_CHECK(addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "esffpvrt3wpeaygy.internal");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "esffpvrt3wpeaygy.internal");
// Totally bogus
BOOST_CHECK(!addr.SetSpecial("totally bogus"));
@@ -321,7 +321,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_tostring_canonical_ipv6)
CNetAddr net_addr;
BOOST_REQUIRE(LookupHost(input_address, net_addr, false));
BOOST_REQUIRE(net_addr.IsIPv6());
- BOOST_CHECK_EQUAL(net_addr.ToString(), expected_canonical_representation_output);
+ BOOST_CHECK_EQUAL(net_addr.ToStringAddr(), expected_canonical_representation_output);
}
}
@@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsIPv4());
BOOST_CHECK(addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "1.2.3.4");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "1.2.3.4");
BOOST_REQUIRE(s.empty());
// Invalid IPv4, valid length but address itself is shorter.
@@ -447,7 +447,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsIPv6());
BOOST_CHECK(addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "102:304:506:708:90a:b0c:d0e:f10");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "102:304:506:708:90a:b0c:d0e:f10");
BOOST_REQUIRE(s.empty());
// Valid IPv6, contains embedded "internal".
@@ -459,7 +459,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s >> addr;
BOOST_CHECK(addr.IsInternal());
BOOST_CHECK(addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "zklycewkdo64v6wc.internal");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "zklycewkdo64v6wc.internal");
BOOST_REQUIRE(s.empty());
// Invalid IPv6, with bogus length.
@@ -505,7 +505,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsTor());
BOOST_CHECK(!addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(),
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(),
"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion");
BOOST_REQUIRE(s.empty());
@@ -528,7 +528,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsI2P());
BOOST_CHECK(!addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(),
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(),
"ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq.b32.i2p");
BOOST_REQUIRE(s.empty());
@@ -551,7 +551,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsCJDNS());
BOOST_CHECK(!addr.IsAddrV1Compatible());
- BOOST_CHECK_EQUAL(addr.ToString(), "fc00:1:2:3:4:5:6:7");
+ BOOST_CHECK_EQUAL(addr.ToStringAddr(), "fc00:1:2:3:4:5:6:7");
BOOST_REQUIRE(s.empty());
// Invalid CJDNS, wrong prefix.
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index c2d2fa37b4..7e91819ddc 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -84,12 +84,12 @@ BOOST_AUTO_TEST_CASE(netbase_properties)
}
-bool static TestSplitHost(const std::string& test, const std::string& host, uint16_t port)
+bool static TestSplitHost(const std::string& test, const std::string& host, uint16_t port, bool validPort=true)
{
std::string hostOut;
uint16_t portOut{0};
- SplitHostPort(test, portOut, hostOut);
- return hostOut == host && port == portOut;
+ bool validPortOut = SplitHostPort(test, portOut, hostOut);
+ return hostOut == host && portOut == port && validPortOut == validPort;
}
BOOST_AUTO_TEST_CASE(netbase_splithost)
@@ -109,12 +109,29 @@ BOOST_AUTO_TEST_CASE(netbase_splithost)
BOOST_CHECK(TestSplitHost(":8333", "", 8333));
BOOST_CHECK(TestSplitHost("[]:8333", "", 8333));
BOOST_CHECK(TestSplitHost("", "", 0));
+ BOOST_CHECK(TestSplitHost(":65535", "", 65535));
+ BOOST_CHECK(TestSplitHost(":65536", ":65536", 0, false));
+ BOOST_CHECK(TestSplitHost(":-1", ":-1", 0, false));
+ BOOST_CHECK(TestSplitHost("[]:70001", "[]:70001", 0, false));
+ BOOST_CHECK(TestSplitHost("[]:-1", "[]:-1", 0, false));
+ BOOST_CHECK(TestSplitHost("[]:-0", "[]:-0", 0, false));
+ BOOST_CHECK(TestSplitHost("[]:0", "", 0, false));
+ BOOST_CHECK(TestSplitHost("[]:1/2", "[]:1/2", 0, false));
+ BOOST_CHECK(TestSplitHost("[]:1E2", "[]:1E2", 0, false));
+ BOOST_CHECK(TestSplitHost("127.0.0.1:65536", "127.0.0.1:65536", 0, false));
+ BOOST_CHECK(TestSplitHost("127.0.0.1:0", "127.0.0.1", 0, false));
+ BOOST_CHECK(TestSplitHost("127.0.0.1:", "127.0.0.1:", 0, false));
+ BOOST_CHECK(TestSplitHost("127.0.0.1:1/2", "127.0.0.1:1/2", 0, false));
+ BOOST_CHECK(TestSplitHost("127.0.0.1:1E2", "127.0.0.1:1E2", 0, false));
+ BOOST_CHECK(TestSplitHost("www.bitcoincore.org:65536", "www.bitcoincore.org:65536", 0, false));
+ BOOST_CHECK(TestSplitHost("www.bitcoincore.org:0", "www.bitcoincore.org", 0, false));
+ BOOST_CHECK(TestSplitHost("www.bitcoincore.org:", "www.bitcoincore.org:", 0, false));
}
bool static TestParse(std::string src, std::string canon)
{
CService addr(LookupNumeric(src, 65535));
- return canon == addr.ToString();
+ return canon == addr.ToStringAddrPort();
}
BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
@@ -138,7 +155,7 @@ BOOST_AUTO_TEST_CASE(embedded_test)
CNetAddr addr1(ResolveIP("1.2.3.4"));
CNetAddr addr2(ResolveIP("::FFFF:0102:0304"));
BOOST_CHECK(addr2.IsIPv4());
- BOOST_CHECK_EQUAL(addr1.ToString(), addr2.ToString());
+ BOOST_CHECK_EQUAL(addr1.ToStringAddr(), addr2.ToStringAddr());
}
BOOST_AUTO_TEST_CASE(subnet_test)
@@ -223,7 +240,7 @@ BOOST_AUTO_TEST_CASE(subnet_test)
subnet = CSubNet(tor_addr);
BOOST_CHECK(subnet.IsValid());
- BOOST_CHECK_EQUAL(subnet.ToString(), tor_addr.ToString());
+ BOOST_CHECK_EQUAL(subnet.ToString(), tor_addr.ToStringAddr());
BOOST_CHECK(subnet.Match(tor_addr));
BOOST_CHECK(
!subnet.Match(ResolveIP("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion")));
diff --git a/src/test/orphanage_tests.cpp b/src/test/orphanage_tests.cpp
index 842daa8bd4..a2c4774338 100644
--- a/src/test/orphanage_tests.cpp
+++ b/src/test/orphanage_tests.cpp
@@ -7,6 +7,7 @@
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <txorphanage.h>
@@ -20,13 +21,15 @@ BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup)
class TxOrphanageTest : public TxOrphanage
{
public:
- inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
+ inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
+ LOCK(m_mutex);
return m_orphans.size();
}
- CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
+ CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
+ LOCK(m_mutex);
std::map<uint256, OrphanTx>::iterator it;
it = m_orphans.lower_bound(InsecureRand256());
if (it == m_orphans.end())
@@ -59,8 +62,6 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKey(key));
- LOCK(g_cs_orphans);
-
// 50 orphan transactions:
for (int i = 0; i < 50; i++)
{
@@ -88,7 +89,8 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
- BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL));
+ SignatureData empty;
+ BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty));
orphanage.AddTx(MakeTransactionRef(tx), i);
}
@@ -108,7 +110,8 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vin[j].prevout.n = j;
tx.vin[j].prevout.hash = txPrev->GetHash();
}
- BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL));
+ SignatureData empty;
+ BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty));
// Re-use same signature for other inputs
// (they don't have to be valid for this test)
for (unsigned int j = 1; j < tx.vin.size(); j++)
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 3cbbec92d6..a1e672d174 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2020 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,6 +6,7 @@
#include <merkleblock.h>
#include <serialize.h>
#include <streams.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <uint256.h>
#include <version.h>
@@ -69,7 +70,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
CPartialMerkleTree pmt1(vTxid, vMatch);
// serialize
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ss{};
ss << pmt1;
// verify CPartialMerkleTree's size guarantees
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 3f66a8fc46..75ba9972f6 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Copyright (c) 2011-2022 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 <policy/fees.h>
#include <policy/policy.h>
+#include <test/util/txmempool.h>
#include <txmempool.h>
#include <uint256.h>
#include <util/time.h>
@@ -58,7 +59,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
uint256 hash = tx.GetHash();
- mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
+ mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx));
txHashes[j].push_back(hash);
}
}
@@ -129,7 +130,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
uint256 hash = tx.GetHash();
- mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
+ mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx));
txHashes[j].push_back(hash);
}
}
@@ -164,7 +165,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
uint256 hash = tx.GetHash();
- mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
+ mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx));
CTransactionRef ptx = mpool.get(hash);
if (ptx)
block.push_back(ptx);
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index 3695ea9d16..addc925bab 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 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 <chain.h>
#include <chainparams.h>
#include <pow.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
index 3977a3d548..1559011fcd 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,6 +9,7 @@
#include <serialize.h>
#include <streams.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
@@ -66,8 +67,8 @@ class prevector_tester {
for (const T& v : reverse_iterate(const_pre_vector)) {
local_check(v == real_vector[--pos]);
}
- CDataStream ss1(SER_DISK, 0);
- CDataStream ss2(SER_DISK, 0);
+ DataStream ss1{};
+ DataStream ss2{};
ss1 << real_vector;
ss2 << pre_vector;
local_check_equal(ss1.size(), ss2.size());
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
index d4487cd941..ada61029ee 100644
--- a/src/test/raii_event_tests.cpp
+++ b/src/test/raii_event_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2020 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index 96fb28dc9f..e5cf767614 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2020 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -94,14 +94,14 @@ BOOST_AUTO_TEST_CASE(fastrandom_randbits)
for (int j = 0; j < 1000; ++j) {
uint64_t rangebits = ctx1.randbits(bits);
BOOST_CHECK_EQUAL(rangebits >> bits, 0U);
- uint64_t range = ((uint64_t)1) << bits | rangebits;
+ uint64_t range = (uint64_t{1}) << bits | rangebits;
uint64_t rand = ctx2.randrange(range);
BOOST_CHECK(rand < range);
}
}
}
-/** Does-it-compile test for compatibility with standard C++11 RNG interface. */
+/** Does-it-compile test for compatibility with standard library RNG interface. */
BOOST_AUTO_TEST_CASE(stdrandom_test)
{
FastRandomContext ctx;
diff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp
index c88cd36688..0ec253747b 100644
--- a/src/test/rbf_tests.cpp
+++ b/src/test/rbf_tests.cpp
@@ -1,8 +1,9 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 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 <policy/rbf.h>
#include <random.h>
+#include <test/util/txmempool.h>
#include <txmempool.h>
#include <util/system.h>
#include <util/time.h>
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index a52530e179..791c9ddf31 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,12 +17,49 @@
#include <boost/test/unit_test.hpp>
+static UniValue JSON(std::string_view json)
+{
+ UniValue value;
+ BOOST_CHECK(value.read(json.data(), json.size()));
+ return value;
+}
+
+class HasJSON
+{
+public:
+ explicit HasJSON(std::string json) : m_json(std::move(json)) {}
+ bool operator()(const UniValue& value) const
+ {
+ std::string json{value.write()};
+ BOOST_CHECK_EQUAL(json, m_json);
+ return json == m_json;
+ };
+
+private:
+ const std::string m_json;
+};
+
class RPCTestingSetup : public TestingSetup
{
public:
+ UniValue TransformParams(const UniValue& params, std::vector<std::string> arg_names) const;
UniValue CallRPC(std::string args);
};
+UniValue RPCTestingSetup::TransformParams(const UniValue& params, std::vector<std::string> arg_names) const
+{
+ UniValue transformed_params;
+ CRPCTable table;
+ CRPCCommand command{"category", "method", [&](const JSONRPCRequest& request, UniValue&, bool) -> bool { transformed_params = request.params; return true; }, arg_names, /*unique_id=*/0};
+ table.appendCommand("method", &command);
+ JSONRPCRequest request;
+ request.strMethod = "method";
+ request.params = params;
+ if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
+ table.execute(request);
+ return transformed_params;
+}
+
UniValue RPCTestingSetup::CallRPC(std::string args)
{
std::vector<std::string> vArgs{SplitString(args, ' ')};
@@ -45,6 +82,33 @@ UniValue RPCTestingSetup::CallRPC(std::string args)
BOOST_FIXTURE_TEST_SUITE(rpc_tests, RPCTestingSetup)
+BOOST_AUTO_TEST_CASE(rpc_namedparams)
+{
+ const std::vector<std::string> arg_names{"arg1", "arg2", "arg3", "arg4", "arg5"};
+
+ // Make sure named arguments are transformed into positional arguments in correct places separated by nulls
+ BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg2": 2, "arg4": 4})"), arg_names).write(), "[null,2,null,4]");
+
+ // Make sure named argument specified multiple times raises an exception
+ BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"arg2": 2, "arg2": 4})"), arg_names), UniValue,
+ HasJSON(R"({"code":-8,"message":"Parameter arg2 specified multiple times"})"));
+
+ // Make sure named and positional arguments can be combined.
+ BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg5": 5, "args": [1, 2], "arg4": 4})"), arg_names).write(), "[1,2,null,4,5]");
+
+ // Make sure a unknown named argument raises an exception
+ BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"arg2": 2, "unknown": 6})"), arg_names), UniValue,
+ HasJSON(R"({"code":-8,"message":"Unknown named parameter unknown"})"));
+
+ // Make sure an overlap between a named argument and positional argument raises an exception
+ BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"args": [1,2,3], "arg4": 4, "arg2": 2})"), arg_names), UniValue,
+ HasJSON(R"({"code":-8,"message":"Parameter arg2 specified twice both as positional and named argument"})"));
+
+ // Make sure extra positional arguments can be passed through to the method implementation, as long as they don't overlap with named arguments.
+ BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"args": [1,2,3,4,5,6,7,8,9,10]})"), arg_names).write(), "[1,2,3,4,5,6,7,8,9,10]");
+ BOOST_CHECK_EQUAL(TransformParams(JSON(R"([1,2,3,4,5,6,7,8,9,10])"), arg_names).write(), "[1,2,3,4,5,6,7,8,9,10]");
+}
+
BOOST_AUTO_TEST_CASE(rpc_rawparams)
{
// Test raw transaction API argument handling
@@ -225,6 +289,10 @@ BOOST_AUTO_TEST_CASE(json_parse_errors)
{
// Valid
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0);
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("true").get_bool(), true);
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("[false]")[0].get_bool(), false);
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("{\"a\": true}")["a"].get_bool(), true);
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("{\"1\": \"true\"}")["1"].get_str(), "true");
// Valid, with leading or trailing whitespace
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0);
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0);
@@ -237,6 +305,11 @@ BOOST_AUTO_TEST_CASE(json_parse_errors)
// Invalid, trailing garbage
BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error);
BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error);
+ // Invalid, keys have to be names
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("{1: \"true\"}"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("{true: 1}"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("{[1]: 1}"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("{{\"a\": \"a\"}: 1}"), std::runtime_error);
// BTC addresses should fail parsing
BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error);
BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error);
diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp
index 907a3fd15b..451bc99d44 100644
--- a/src/test/sanity_tests.cpp
+++ b/src/test/sanity_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 7b5dda8114..1301a1b219 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index a02d51eecc..c9f002b324 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -102,7 +102,8 @@ BOOST_AUTO_TEST_CASE(sign)
}
for (int i = 0; i < 8; i++)
{
- BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
+ SignatureData empty;
+ BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));
}
// All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig:
@@ -197,7 +198,8 @@ BOOST_AUTO_TEST_CASE(set)
}
for (int i = 0; i < 4; i++)
{
- BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
+ SignatureData empty;
+ BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(IsStandardTx(CTransaction(txTo[i]), reason), strprintf("txTo[%d].IsStandard", i));
}
}
@@ -334,9 +336,12 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[i].prevout.n = i;
txTo.vin[i].prevout.hash = txFrom.GetHash();
}
- BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL));
- BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 1, SIGHASH_ALL));
- BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 2, SIGHASH_ALL));
+ SignatureData empty;
+ BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, empty));
+ SignatureData empty_b;
+ BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 1, SIGHASH_ALL, empty_b));
+ SignatureData empty_c;
+ BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 2, SIGHASH_ALL, empty_c));
// SignSignature doesn't know how to sign these. We're
// not testing validating signatures, so just create
// dummy signatures that DO include the correct P2SH scripts:
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index 25e47c0fb0..7bebadf224 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -400,12 +400,11 @@ BOOST_AUTO_TEST_CASE(bip341_spk_test_vectors)
for (const auto& vec : vectors.getValues()) {
TaprootBuilder spktest;
- std::map<std::pair<CScript, int>, int> scriptposes;
+ std::map<std::pair<std::vector<unsigned char>, int>, int> scriptposes;
std::function<void (const UniValue&, int)> parse_tree = [&](const UniValue& node, int depth) {
if (node.isNull()) return;
if (node.isObject()) {
- auto script_bytes = ParseHex(node["script"].get_str());
- CScript script(script_bytes.begin(), script_bytes.end());
+ auto script = ParseHex(node["script"].get_str());
int idx = node["id"].getInt<int>();
int leaf_version = node["leafVersion"].getInt<int>();
scriptposes[{script, leaf_version}] = idx;
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 935194057c..45d9f2cf29 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,6 +15,8 @@
#include <script/sign.h>
#include <script/signingprovider.h>
#include <streams.h>
+#include <test/util/json.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <test/util/transaction_utils.h>
#include <util/strencodings.h>
@@ -41,18 +43,6 @@ static const unsigned int gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
unsigned int ParseScriptFlags(std::string strFlags);
std::string FormatScriptFlags(unsigned int flags);
-UniValue read_json(const std::string& jsondata)
-{
- UniValue v;
-
- if (!v.read(jsondata) || !v.isArray())
- {
- BOOST_ERROR("Parse error.");
- return UniValue(UniValue::VARR);
- }
- return v.get_array();
-}
-
struct ScriptErrorDesc
{
ScriptError_t err;
@@ -1191,7 +1181,8 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_CHECK(combined.scriptSig.empty());
// Single signature case:
- BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL)); // changes scriptSig
+ SignatureData dummy;
+ BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy)); // changes scriptSig
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
@@ -1199,7 +1190,8 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
SignatureData scriptSigCopy = scriptSig;
// Signing again will give a different, valid signature:
- BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL));
+ SignatureData dummy_b;
+ BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy_b));
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);
BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);
@@ -1208,14 +1200,16 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
BOOST_CHECK(keystore.AddCScript(pkSingle));
scriptPubKey = GetScriptForDestination(ScriptHash(pkSingle));
- BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL));
+ SignatureData dummy_c;
+ BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy_c));
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
scriptSigCopy = scriptSig;
- BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL));
+ SignatureData dummy_d;
+ BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy_d));
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);
BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);
@@ -1223,7 +1217,8 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
// Hardest case: Multisig 2-of-3
scriptPubKey = GetScriptForMultisig(2, pubkeys);
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL));
+ SignatureData dummy_e;
+ BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy_e));
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
@@ -1817,7 +1812,24 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
}
}
+}
+
+BOOST_AUTO_TEST_CASE(compute_tapbranch)
+{
+ uint256 hash1 = uint256S("8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7");
+ uint256 hash2 = uint256S("f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a");
+ uint256 result = uint256S("a64c5b7b943315f9b805d7a7296bedfcfd08919270a1f7a1466e98f8693d8cd9");
+ BOOST_CHECK_EQUAL(ComputeTapbranchHash(hash1, hash2), result);
+}
+
+BOOST_AUTO_TEST_CASE(compute_tapleaf)
+{
+ const uint8_t script[6] = {'f','o','o','b','a','r'};
+ uint256 tlc0 = uint256S("edbc10c272a1215dcdcc11d605b9027b5ad6ed97cd45521203f136767b5b9c06");
+ uint256 tlc2 = uint256S("8b5c4f90ae6bf76e259dbef5d8a59df06359c391b59263741b25eca76451b27a");
+ BOOST_CHECK_EQUAL(ComputeTapleafHash(0xc0, Span(script)), tlc0);
+ BOOST_CHECK_EQUAL(ComputeTapleafHash(0xc2, Span(script)), tlc2);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/serfloat_tests.cpp b/src/test/serfloat_tests.cpp
index ed1f081913..b36bdc02ca 100644
--- a/src/test/serfloat_tests.cpp
+++ b/src/test/serfloat_tests.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <hash.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <util/serfloat.h>
#include <serialize.h>
@@ -111,7 +112,7 @@ Python code to generate the below hashes:
*/
BOOST_AUTO_TEST_CASE(doubles)
{
- CDataStream ss(SER_DISK, 0);
+ DataStream ss{};
// encode
for (int i = 0; i < 1000; i++) {
ss << EncodeDouble(i);
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 8c7c650cb1..09f77d2b61 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -90,8 +90,8 @@ BOOST_AUTO_TEST_CASE(varints)
{
// encode
- CDataStream ss(SER_DISK, 0);
- CDataStream::size_type size = 0;
+ DataStream ss{};
+ DataStream::size_type size = 0;
for (int i = 0; i < 100000; i++) {
ss << VARINT_MODE(i, VarIntMode::NONNEGATIVE_SIGNED);
size += ::GetSerializeSize(VARINT_MODE(i, VarIntMode::NONNEGATIVE_SIGNED), 0);
@@ -120,20 +120,20 @@ BOOST_AUTO_TEST_CASE(varints)
BOOST_AUTO_TEST_CASE(varints_bitpatterns)
{
- CDataStream ss(SER_DISK, 0);
+ DataStream ss{};
ss << VARINT_MODE(0, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "00"); ss.clear();
ss << VARINT_MODE(0x7f, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
- ss << VARINT_MODE((int8_t)0x7f, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
+ ss << VARINT_MODE(int8_t{0x7f}, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
ss << VARINT_MODE(0x80, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
- ss << VARINT((uint8_t)0x80); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
+ ss << VARINT(uint8_t{0x80}); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
ss << VARINT_MODE(0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
- ss << VARINT_MODE((int16_t)0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
+ ss << VARINT_MODE(int16_t{0x1234}, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
ss << VARINT_MODE(0xffff, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
- ss << VARINT((uint16_t)0xffff); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
+ ss << VARINT(uint16_t{0xffff}); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
ss << VARINT_MODE(0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
- ss << VARINT_MODE((int32_t)0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
+ ss << VARINT_MODE(int32_t{0x123456}, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
ss << VARINT(0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
- ss << VARINT((uint32_t)0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
+ ss << VARINT(uint32_t{0x80123456U}); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
ss << VARINT(0xffffffff); BOOST_CHECK_EQUAL(HexStr(ss), "8efefefe7f"); ss.clear();
ss << VARINT_MODE(0x7fffffffffffffffLL, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "fefefefefefefefe7f"); ss.clear();
ss << VARINT(0xffffffffffffffffULL); BOOST_CHECK_EQUAL(HexStr(ss), "80fefefefefefefefe7f"); ss.clear();
@@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(varints_bitpatterns)
BOOST_AUTO_TEST_CASE(compactsize)
{
- CDataStream ss(SER_DISK, 0);
+ DataStream ss{};
std::vector<char>::size_type i, j;
for (i = 1; i <= MAX_SIZE; i *= 2)
@@ -182,7 +182,7 @@ BOOST_AUTO_TEST_CASE(noncanonical)
{
// Write some non-canonical CompactSize encodings, and
// make sure an exception is thrown when read back.
- CDataStream ss(SER_DISK, 0);
+ DataStream ss{};
std::vector<char>::size_type n;
// zero encoded with three bytes:
@@ -237,7 +237,8 @@ BOOST_AUTO_TEST_CASE(class_methods)
BOOST_CHECK(methodtest2 == methodtest3);
BOOST_CHECK(methodtest3 == methodtest4);
- CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, charstrval, txval);
+ CDataStream ss2{SER_DISK, PROTOCOL_VERSION};
+ ss2 << intval << boolval << stringval << charstrval << txval;
ss2 >> methodtest3;
BOOST_CHECK(methodtest3 == methodtest4);
}
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index 0feb68b9b1..ad12c46561 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(ReadWrite)
BOOST_CHECK(values.empty());
BOOST_CHECK(errors.empty());
- // Check duplicate keys not allowed
+ // Check duplicate keys not allowed and that values returns empty if a duplicate is found.
WriteText(path, R"({
"dupe": "string",
"dupe": "dupe"
@@ -88,6 +88,7 @@ BOOST_AUTO_TEST_CASE(ReadWrite)
BOOST_CHECK(!util::ReadSettings(path, values, errors));
std::vector<std::string> dup_keys = {strprintf("Found duplicate key dupe in settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), dup_keys.begin(), dup_keys.end());
+ BOOST_CHECK(values.empty());
// Check non-kv json files not allowed
WriteText(path, R"("non-kv")");
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 514798d8fa..e2d11afa6a 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2021 The Bitcoin Core developers
+// Copyright (c) 2013-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,6 +10,8 @@
#include <serialize.h>
#include <streams.h>
#include <test/data/sighash.json.h>
+#include <test/util/json.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <util/strencodings.h>
#include <util/system.h>
@@ -21,8 +23,6 @@
#include <univalue.h>
-UniValue read_json(const std::string& jsondata);
-
// Old script.cpp SignatureHash function
uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
{
@@ -110,7 +110,7 @@ void static RandomTransaction(CMutableTransaction& tx, bool fSingle)
for (int out = 0; out < outs; out++) {
tx.vout.push_back(CTxOut());
CTxOut &txout = tx.vout.back();
- txout.nValue = InsecureRandRange(100000000);
+ txout.nValue = InsecureRandMoneyAmount();
RandomScript(txout.scriptPubKey);
}
}
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index 55486db6b2..a17be54419 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -1,7 +1,8 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <coins.h>
#include <consensus/consensus.h>
#include <consensus/tx_verify.h>
#include <key.h>
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index 9f5e3ab7ae..050033e43a 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -1,8 +1,9 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2022 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 <chain.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <vector>
diff --git a/src/test/sock_tests.cpp b/src/test/sock_tests.cpp
index 8376ec1a68..9e6f73745e 100644
--- a/src/test/sock_tests.cpp
+++ b/src/test/sock_tests.cpp
@@ -1,12 +1,12 @@
-// Copyright (c) 2021-2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 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 <compat/compat.h>
#include <test/util/setup_common.h>
-#include <threadinterrupt.h>
#include <util/sock.h>
#include <util/system.h>
+#include <util/threadinterrupt.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 0925e2e9ee..a9b5251ad3 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 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 <fs.h>
#include <streams.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
@@ -128,9 +129,9 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader_rvalue)
BOOST_AUTO_TEST_CASE(bitstream_reader_writer)
{
- CDataStream data(SER_NETWORK, INIT_PROTO_VERSION);
+ DataStream data{};
- BitStreamWriter<CDataStream> bit_writer(data);
+ BitStreamWriter bit_writer{data};
bit_writer.Write(0, 1);
bit_writer.Write(2, 2);
bit_writer.Write(6, 3);
@@ -141,15 +142,15 @@ BOOST_AUTO_TEST_CASE(bitstream_reader_writer)
bit_writer.Write(30497, 16);
bit_writer.Flush();
- CDataStream data_copy(data);
+ DataStream data_copy{data};
uint32_t serialized_int1;
data >> serialized_int1;
- BOOST_CHECK_EQUAL(serialized_int1, (uint32_t)0x7700C35A); // NOTE: Serialized as LE
+ BOOST_CHECK_EQUAL(serialized_int1, uint32_t{0x7700C35A}); // NOTE: Serialized as LE
uint16_t serialized_int2;
data >> serialized_int2;
- BOOST_CHECK_EQUAL(serialized_int2, (uint16_t)0x1072); // NOTE: Serialized as LE
+ BOOST_CHECK_EQUAL(serialized_int2, uint16_t{0x1072}); // NOTE: Serialized as LE
- BitStreamReader<CDataStream> bit_reader(data_copy);
+ BitStreamReader bit_reader{data_copy};
BOOST_CHECK_EQUAL(bit_reader.Read(1), 0U);
BOOST_CHECK_EQUAL(bit_reader.Read(2), 2U);
BOOST_CHECK_EQUAL(bit_reader.Read(3), 6U);
@@ -167,7 +168,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
// Degenerate case
{
- CDataStream ds{in, 0, 0};
+ DataStream ds{in};
ds.Xor({0x00, 0x00});
BOOST_CHECK_EQUAL(""s, ds.str());
}
@@ -177,7 +178,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
// Single character key
{
- CDataStream ds{in, 0, 0};
+ DataStream ds{in};
ds.Xor({0xff});
BOOST_CHECK_EQUAL("\xf0\x0f"s, ds.str());
}
@@ -189,7 +190,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
in.push_back(std::byte{0x0f});
{
- CDataStream ds{in, 0, 0};
+ DataStream ds{in};
ds.Xor({0xff, 0x0f});
BOOST_CHECK_EQUAL("\x0f\x00"s, ds.str());
}
@@ -253,7 +254,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file)
BOOST_CHECK(false);
} catch (const std::exception& e) {
BOOST_CHECK(strstr(e.what(),
- "Read attempted past buffer limit") != nullptr);
+ "Attempt to position past buffer limit") != nullptr);
}
// The default argument removes the limit completely.
BOOST_CHECK(bf.SetLimit());
@@ -322,7 +323,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file)
BOOST_CHECK(!bf.SetPos(0));
// But we should now be positioned at least as far back as allowed
// by the rewind window (relative to our farthest read position, 40).
- BOOST_CHECK(bf.GetPos() <= 30);
+ BOOST_CHECK(bf.GetPos() <= 30U);
// We can explicitly close the file, or the destructor will do it.
bf.fclose();
@@ -330,6 +331,55 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file)
fs::remove(streams_test_filename);
}
+BOOST_AUTO_TEST_CASE(streams_buffered_file_skip)
+{
+ fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp";
+ FILE* file = fsbridge::fopen(streams_test_filename, "w+b");
+ // The value at each offset is the byte offset (e.g. byte 1 in the file has the value 0x01).
+ for (uint8_t j = 0; j < 40; ++j) {
+ fwrite(&j, 1, 1, file);
+ }
+ rewind(file);
+
+ // The buffer is 25 bytes, allow rewinding 10 bytes.
+ CBufferedFile bf(file, 25, 10, 222, 333);
+
+ uint8_t i;
+ // This is like bf >> (7-byte-variable), in that it will cause data
+ // to be read from the file into memory, but it's not copied to us.
+ bf.SkipTo(7);
+ BOOST_CHECK_EQUAL(bf.GetPos(), 7U);
+ bf >> i;
+ BOOST_CHECK_EQUAL(i, 7);
+
+ // The bytes in the buffer up to offset 7 are valid and can be read.
+ BOOST_CHECK(bf.SetPos(0));
+ bf >> i;
+ BOOST_CHECK_EQUAL(i, 0);
+ bf >> i;
+ BOOST_CHECK_EQUAL(i, 1);
+
+ bf.SkipTo(11);
+ bf >> i;
+ BOOST_CHECK_EQUAL(i, 11);
+
+ // SkipTo() honors the transfer limit; we can't position beyond the limit.
+ bf.SetLimit(13);
+ try {
+ bf.SkipTo(14);
+ BOOST_CHECK(false);
+ } catch (const std::exception& e) {
+ BOOST_CHECK(strstr(e.what(), "Attempt to position past buffer limit") != nullptr);
+ }
+
+ // We can position exactly to the transfer limit.
+ bf.SkipTo(13);
+ BOOST_CHECK_EQUAL(bf.GetPos(), 13U);
+
+ bf.fclose();
+ fs::remove(streams_test_filename);
+}
+
BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
{
// Make this test deterministic.
@@ -361,7 +411,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
// sizes; the boundaries of the objects can interact arbitrarily
// with the CBufferFile's internal buffer. These first three
// cases simulate objects of various sizes (1, 2, 5 bytes).
- switch (InsecureRandRange(5)) {
+ switch (InsecureRandRange(6)) {
case 0: {
uint8_t a[1];
if (currentPos + 1 > fileSize)
@@ -399,6 +449,16 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
break;
}
case 3: {
+ // SkipTo is similar to the "read" cases above, except
+ // we don't receive the data.
+ size_t skip_length{static_cast<size_t>(InsecureRandRange(5))};
+ if (currentPos + skip_length > fileSize) continue;
+ bf.SetLimit(currentPos + skip_length);
+ bf.SkipTo(currentPos + skip_length);
+ currentPos += skip_length;
+ break;
+ }
+ case 4: {
// Find a byte value (that is at or ahead of the current position).
size_t find = currentPos + InsecureRandRange(8);
if (find >= fileSize)
@@ -415,7 +475,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
currentPos++;
break;
}
- case 4: {
+ case 5: {
size_t requestPos = InsecureRandRange(maxPos + 4);
bool okay = bf.SetPos(requestPos);
// The new position may differ from the requested position
@@ -441,4 +501,18 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
fs::remove(streams_test_filename);
}
+BOOST_AUTO_TEST_CASE(streams_hashed)
+{
+ CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION);
+ HashedSourceWriter hash_writer{stream};
+ const std::string data{"bitcoin"};
+ hash_writer << data;
+
+ CHashVerifier hash_verifier{&stream};
+ std::string result;
+ hash_verifier >> result;
+ BOOST_CHECK_EQUAL(data, result);
+ BOOST_CHECK_EQUAL(hash_writer.GetHash(), hash_verifier.GetHash());
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp
index 55c2c5108d..0576bf1633 100644
--- a/src/test/sync_tests.cpp
+++ b/src/test/sync_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -107,12 +107,12 @@ BOOST_AUTO_TEST_CASE(potential_deadlock_detected)
#ifdef DEBUG_LOCKORDER
BOOST_AUTO_TEST_CASE(double_lock_mutex)
{
- TestDoubleLock<Mutex>(true /* should throw */);
+ TestDoubleLock<Mutex>(/*should_throw=*/true);
}
BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex)
{
- TestDoubleLock<RecursiveMutex>(false /* should not throw */);
+ TestDoubleLock<RecursiveMutex>(/*should_throw=*/false);
}
#endif /* DEBUG_LOCKORDER */
diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp
index f160bb08a5..c0a2566959 100644
--- a/src/test/system_tests.cpp
+++ b/src/test/system_tests.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 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/util/setup_common.h>
-#include <util/system.h>
+#include <common/run_command.h>
#include <univalue.h>
#ifdef ENABLE_EXTERNAL_SIGNER
@@ -34,6 +34,13 @@ BOOST_AUTO_TEST_CASE(dummy)
BOOST_AUTO_TEST_CASE(run_command)
{
+#ifdef WIN32
+ // https://www.winehq.org/pipermail/wine-devel/2008-September/069387.html
+ auto hntdll = GetModuleHandleA("ntdll.dll");
+ assert(hntdll);
+ const bool wine_runtime = GetProcAddress(hntdll, "wine_get_version");
+#endif
+
{
const UniValue result = RunCommandParseJSON("");
BOOST_CHECK(result.isNull());
@@ -47,31 +54,31 @@ BOOST_AUTO_TEST_CASE(run_command)
BOOST_CHECK(result.isObject());
const UniValue& success = find_value(result, "success");
BOOST_CHECK(!success.isNull());
- BOOST_CHECK_EQUAL(success.getBool(), true);
+ BOOST_CHECK_EQUAL(success.get_bool(), true);
}
{
// An invalid command is handled by Boost
#ifdef WIN32
- const std::string expected{"The system cannot find the file specified."};
+ const int expected_error{wine_runtime ? 6 : 2};
#else
- const std::string expected{"No such file or directory"};
+ const int expected_error{2};
#endif
BOOST_CHECK_EXCEPTION(RunCommandParseJSON("invalid_command"), boost::process::process_error, [&](const boost::process::process_error& e) {
- const std::string what(e.what());
- BOOST_CHECK(what.find("RunCommandParseJSON error:") == std::string::npos);
- BOOST_CHECK(what.find(expected) != std::string::npos);
+ BOOST_CHECK(std::string(e.what()).find("RunCommandParseJSON error:") == std::string::npos);
+ BOOST_CHECK_EQUAL(e.code().value(), expected_error);
return true;
});
}
{
// Return non-zero exit code, no output to stderr
#ifdef WIN32
- const std::string command{"cmd.exe /c call"};
+ const std::string command{"cmd.exe /c exit 1"};
#else
const std::string command{"false"};
#endif
BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) {
- BOOST_CHECK(std::string(e.what()).find(strprintf("RunCommandParseJSON error: process(%s) returned 1: \n", command)) != std::string::npos);
+ const std::string what{e.what()};
+ BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned 1: \n", command)) != std::string::npos);
return true;
});
}
@@ -79,7 +86,7 @@ BOOST_AUTO_TEST_CASE(run_command)
// Return non-zero exit code, with error message for stderr
#ifdef WIN32
const std::string command{"cmd.exe /c dir nosuchfile"};
- const std::string expected{"File Not Found"};
+ const std::string expected{wine_runtime ? "File not found." : "File Not Found"};
#else
const std::string command{"ls nosuchfile"};
const std::string expected{"No such file or directory"};
@@ -101,7 +108,7 @@ BOOST_AUTO_TEST_CASE(run_command)
BOOST_CHECK(result.isObject());
const UniValue& success = find_value(result, "success");
BOOST_CHECK(!success.isNull());
- BOOST_CHECK_EQUAL(success.getBool(), true);
+ BOOST_CHECK_EQUAL(success.get_bool(), true);
}
#endif
}
diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp
index 478d61d5e2..2814dbf4c0 100644
--- a/src/test/timedata_tests.cpp
+++ b/src/test/timedata_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Copyright (c) 2011-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 952598f745..11efb6a5c3 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -21,6 +21,8 @@
#include <script/signingprovider.h>
#include <script/standard.h>
#include <streams.h>
+#include <test/util/json.h>
+#include <test/util/random.h>
#include <test/util/script.h>
#include <test/util/transaction_utils.h>
#include <util/strencodings.h>
@@ -37,9 +39,6 @@
typedef std::vector<unsigned char> valtype;
-// In script_tests.cpp
-UniValue read_json(const std::string& jsondata);
-
static CFeeRate g_dust{DUST_RELAY_TX_FEE};
static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
@@ -435,7 +434,8 @@ static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const
inputm.vout.resize(1);
inputm.vout[0].nValue = 1;
inputm.vout[0].scriptPubKey = CScript();
- bool ret = SignSignature(keystore, *output, inputm, 0, SIGHASH_ALL);
+ SignatureData empty;
+ bool ret = SignSignature(keystore, *output, inputm, 0, SIGHASH_ALL, empty);
assert(ret == success);
CDataStream ssin(SER_NETWORK, PROTOCOL_VERSION);
ssin << inputm;
@@ -519,7 +519,8 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
// sign all inputs
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
- bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()));
+ SignatureData empty;
+ bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()), empty);
assert(hashSigned);
}
@@ -937,23 +938,58 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
CheckIsNotStandard(t, "bare-multisig");
g_bare_multi = DEFAULT_PERMIT_BAREMULTISIG;
+ // Check compressed P2PK outputs dust threshold (must have leading 02 or 03)
+ t.vout[0].scriptPubKey = CScript() << std::vector<unsigned char>(33, 0x02) << OP_CHECKSIG;
+ t.vout[0].nValue = 576;
+ CheckIsStandard(t);
+ t.vout[0].nValue = 575;
+ CheckIsNotStandard(t, "dust");
+
+ // Check uncompressed P2PK outputs dust threshold (must have leading 04/06/07)
+ t.vout[0].scriptPubKey = CScript() << std::vector<unsigned char>(65, 0x04) << OP_CHECKSIG;
+ t.vout[0].nValue = 672;
+ CheckIsStandard(t);
+ t.vout[0].nValue = 671;
+ CheckIsNotStandard(t, "dust");
+
+ // Check P2PKH outputs dust threshold
+ t.vout[0].scriptPubKey = CScript() << OP_DUP << OP_HASH160 << std::vector<unsigned char>(20, 0) << OP_EQUALVERIFY << OP_CHECKSIG;
+ t.vout[0].nValue = 546;
+ CheckIsStandard(t);
+ t.vout[0].nValue = 545;
+ CheckIsNotStandard(t, "dust");
+
+ // Check P2SH outputs dust threshold
+ t.vout[0].scriptPubKey = CScript() << OP_HASH160 << std::vector<unsigned char>(20, 0) << OP_EQUAL;
+ t.vout[0].nValue = 540;
+ CheckIsStandard(t);
+ t.vout[0].nValue = 539;
+ CheckIsNotStandard(t, "dust");
+
// Check P2WPKH outputs dust threshold
- t.vout[0].scriptPubKey = CScript() << OP_0 << ParseHex("ffffffffffffffffffffffffffffffffffffffff");
+ t.vout[0].scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(20, 0);
t.vout[0].nValue = 294;
CheckIsStandard(t);
t.vout[0].nValue = 293;
CheckIsNotStandard(t, "dust");
// Check P2WSH outputs dust threshold
- t.vout[0].scriptPubKey = CScript() << OP_0 << ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ t.vout[0].scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(32, 0);
+ t.vout[0].nValue = 330;
+ CheckIsStandard(t);
+ t.vout[0].nValue = 329;
+ CheckIsNotStandard(t, "dust");
+
+ // Check P2TR outputs dust threshold (Invalid xonly key ok!)
+ t.vout[0].scriptPubKey = CScript() << OP_1 << std::vector<unsigned char>(32, 0);
t.vout[0].nValue = 330;
CheckIsStandard(t);
t.vout[0].nValue = 329;
CheckIsNotStandard(t, "dust");
- // Check future Witness Program versions dust threshold
- for (int op = OP_2; op <= OP_16; op += 1) {
- t.vout[0].scriptPubKey = CScript() << (opcodetype)op << ParseHex("ffff");
+ // Check future Witness Program versions dust threshold (non-32-byte pushes are undefined for version 1)
+ for (int op = OP_1; op <= OP_16; op += 1) {
+ t.vout[0].scriptPubKey = CScript() << (opcodetype)op << std::vector<unsigned char>(2, 0);
t.vout[0].nValue = 240;
CheckIsStandard(t);
diff --git a/src/test/translation_tests.cpp b/src/test/translation_tests.cpp
new file mode 100644
index 0000000000..bda5dfd099
--- /dev/null
+++ b/src/test/translation_tests.cpp
@@ -0,0 +1,21 @@
+// Copyright (c) 2023 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 <tinyformat.h>
+#include <util/translation.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(translation_tests)
+
+BOOST_AUTO_TEST_CASE(translation_namedparams)
+{
+ bilingual_str arg{"original", "translated"};
+ bilingual_str format{"original [%s]", "translated [%s]"};
+ bilingual_str result{strprintf(format, arg)};
+ BOOST_CHECK_EQUAL(result.original, "original [original]");
+ BOOST_CHECK_EQUAL(result.translated, "translated [translated]");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index 62c7ddb673..b9bfa65c0a 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -69,11 +69,16 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
}
}
+ // It is not safe to stop and destroy the index until it finishes handling
+ // the last BlockConnected notification. The BlockUntilSyncedToCurrentChain()
+ // call above is sufficient to ensure this, but the
+ // SyncWithValidationInterfaceQueue() call below is also needed to ensure
+ // TSAN always sees the test thread waiting for the notification thread, and
+ // avoid potential false positive reports.
+ SyncWithValidationInterfaceQueue();
+
// shutdown sequence (c.f. Shutdown() in init.cpp)
txindex.Stop();
-
- // Let scheduler events finish running to avoid accessing any memory related to txindex after it is destructed
- SyncWithValidationInterfaceQueue();
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp
index 079b753304..024526497c 100644
--- a/src/test/txpackage_tests.cpp
+++ b/src/test/txpackage_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,6 +9,7 @@
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/standard.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <validation.h>
@@ -90,17 +91,21 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {tx_parent, tx_child}, /*test_accept=*/true);
BOOST_CHECK_MESSAGE(result_parent_child.m_state.IsValid(),
"Package validation unexpectedly failed: " << result_parent_child.m_state.GetRejectReason());
+ BOOST_CHECK(result_parent_child.m_tx_results.size() == 2);
auto it_parent = result_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
auto it_child = result_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
BOOST_CHECK(it_parent != result_parent_child.m_tx_results.end());
BOOST_CHECK_MESSAGE(it_parent->second.m_state.IsValid(),
"Package validation unexpectedly failed: " << it_parent->second.m_state.GetRejectReason());
+ BOOST_CHECK(it_parent->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_parent)) == COIN);
+ BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
+ BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
BOOST_CHECK(it_child != result_parent_child.m_tx_results.end());
BOOST_CHECK_MESSAGE(it_child->second.m_state.IsValid(),
"Package validation unexpectedly failed: " << it_child->second.m_state.GetRejectReason());
- BOOST_CHECK(result_parent_child.m_package_feerate.has_value());
- BOOST_CHECK(result_parent_child.m_package_feerate.value() ==
- CFeeRate(2 * COIN, GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child)));
+ BOOST_CHECK(it_child->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_child)) == COIN);
+ BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
+ BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
// A single, giant transaction submitted through ProcessNewPackage fails on single tx policy.
CTransactionRef giant_ptx = create_placeholder_tx(999, 999);
@@ -109,10 +114,10 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
BOOST_CHECK(result_single_large.m_state.IsInvalid());
BOOST_CHECK_EQUAL(result_single_large.m_state.GetResult(), PackageValidationResult::PCKG_TX);
BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(), "transaction failed");
+ BOOST_CHECK(result_single_large.m_tx_results.size() == 1);
auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash());
BOOST_CHECK(it_giant_tx != result_single_large.m_tx_results.end());
BOOST_CHECK_EQUAL(it_giant_tx->second.m_state.GetRejectReason(), "tx-size");
- BOOST_CHECK(result_single_large.m_package_feerate == std::nullopt);
// Check that mempool size hasn't changed.
BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
@@ -233,7 +238,6 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
- BOOST_CHECK(result_unrelated_submit.m_package_feerate == std::nullopt);
// Parent and Child (and Grandchild) Package
Package package_parent_child;
@@ -275,7 +279,30 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
- BOOST_CHECK(result_3gen_submit.m_package_feerate == std::nullopt);
+ }
+
+ // Parent and child package where transactions are invalid for reasons other than fee and
+ // missing inputs, so the package validation isn't expected to happen.
+ {
+ CScriptWitness bad_witness;
+ bad_witness.stack.push_back(std::vector<unsigned char>(1));
+ CMutableTransaction mtx_parent_invalid{mtx_parent};
+ mtx_parent_invalid.vin[0].scriptWitness = bad_witness;
+ CTransactionRef tx_parent_invalid = MakeTransactionRef(mtx_parent_invalid);
+ auto result_quit_early = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
+ {tx_parent_invalid, tx_child}, /*test_accept=*/ false);
+ BOOST_CHECK(result_quit_early.m_state.IsInvalid());
+ BOOST_CHECK_EQUAL(result_quit_early.m_state.GetResult(), PackageValidationResult::PCKG_TX);
+ BOOST_CHECK(!result_quit_early.m_tx_results.empty());
+ BOOST_CHECK_EQUAL(result_quit_early.m_tx_results.size(), 2);
+ auto it_parent = result_quit_early.m_tx_results.find(tx_parent_invalid->GetWitnessHash());
+ auto it_child = result_quit_early.m_tx_results.find(tx_child->GetWitnessHash());
+ BOOST_CHECK(it_parent != result_quit_early.m_tx_results.end());
+ BOOST_CHECK(it_child != result_quit_early.m_tx_results.end());
+ BOOST_CHECK_EQUAL(it_parent->second.m_state.GetResult(), TxValidationResult::TX_WITNESS_MUTATED);
+ BOOST_CHECK_EQUAL(it_parent->second.m_state.GetRejectReason(), "bad-witness-nonstandard");
+ BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MISSING_INPUTS);
+ BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(), "bad-txns-inputs-missingorspent");
}
// Child with missing parent.
@@ -290,8 +317,6 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetRejectReason(), "package-not-child-with-unconfirmed-parents");
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
-
- BOOST_CHECK(result_missing_parent.m_package_feerate == std::nullopt);
}
// Submit package with parent + child.
@@ -301,20 +326,23 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
expected_pool_size += 2;
BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(),
"Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason());
+ BOOST_CHECK_EQUAL(submit_parent_child.m_tx_results.size(), package_parent_child.size());
auto it_parent = submit_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end());
BOOST_CHECK(it_parent->second.m_state.IsValid());
+ BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_parent)));
+ BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
+ BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
BOOST_CHECK(it_child != submit_parent_child.m_tx_results.end());
BOOST_CHECK(it_child->second.m_state.IsValid());
+ BOOST_CHECK(it_child->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_child)));
+ BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
+ BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent->GetHash())));
BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_child->GetHash())));
-
- // Since both transactions have high feerates, they each passed validation individually.
- // Package validation was unnecessary, so there is no package feerate.
- BOOST_CHECK(submit_parent_child.m_package_feerate == std::nullopt);
}
// Already-in-mempool transactions should be detected and de-duplicated.
@@ -323,6 +351,7 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
package_parent_child, /*test_accept=*/false);
BOOST_CHECK_MESSAGE(submit_deduped.m_state.IsValid(),
"Package validation unexpectedly failed: " << submit_deduped.m_state.GetRejectReason());
+ BOOST_CHECK_EQUAL(submit_deduped.m_tx_results.size(), package_parent_child.size());
auto it_parent_deduped = submit_deduped.m_tx_results.find(tx_parent->GetWitnessHash());
auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash());
BOOST_CHECK(it_parent_deduped != submit_deduped.m_tx_results.end());
@@ -335,8 +364,6 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent->GetHash())));
BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_child->GetHash())));
-
- BOOST_CHECK(submit_deduped.m_package_feerate == std::nullopt);
}
}
@@ -399,6 +426,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
{ptx_parent, ptx_child1}, /*test_accept=*/false);
BOOST_CHECK_MESSAGE(submit_witness1.m_state.IsValid(),
"Package validation unexpectedly failed: " << submit_witness1.m_state.GetRejectReason());
+ BOOST_CHECK_EQUAL(submit_witness1.m_tx_results.size(), 2);
auto it_parent1 = submit_witness1.m_tx_results.find(ptx_parent->GetWitnessHash());
auto it_child1 = submit_witness1.m_tx_results.find(ptx_child1->GetWitnessHash());
BOOST_CHECK(it_parent1 != submit_witness1.m_tx_results.end());
@@ -412,13 +440,11 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child1->GetHash())));
// Child2 would have been validated individually.
- BOOST_CHECK(submit_witness1.m_package_feerate == std::nullopt);
-
const auto submit_witness2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
{ptx_parent, ptx_child2}, /*test_accept=*/false);
- BOOST_CHECK(submit_witness2.m_package_feerate == std::nullopt);
BOOST_CHECK_MESSAGE(submit_witness2.m_state.IsValid(),
"Package validation unexpectedly failed: " << submit_witness2.m_state.GetRejectReason());
+ BOOST_CHECK_EQUAL(submit_witness2.m_tx_results.size(), 2);
auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash());
auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash());
BOOST_CHECK(it_parent2_deduped != submit_witness2.m_tx_results.end());
@@ -436,11 +462,11 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
{ptx_parent, ptx_child1}, /*test_accept=*/false);
BOOST_CHECK_MESSAGE(submit_segwit_dedup.m_state.IsValid(),
"Package validation unexpectedly failed: " << submit_segwit_dedup.m_state.GetRejectReason());
+ BOOST_CHECK_EQUAL(submit_segwit_dedup.m_tx_results.size(), 2);
auto it_parent_dup = submit_segwit_dedup.m_tx_results.find(ptx_parent->GetWitnessHash());
auto it_child_dup = submit_segwit_dedup.m_tx_results.find(ptx_child1->GetWitnessHash());
BOOST_CHECK(it_parent_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
BOOST_CHECK(it_child_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
- BOOST_CHECK(submit_witness2.m_package_feerate == std::nullopt);
}
// Try submitting Package1{child2, grandchild} where child2 is same-txid-different-witness as
@@ -465,6 +491,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
{ptx_child2, ptx_grandchild}, /*test_accept=*/false);
BOOST_CHECK_MESSAGE(submit_spend_ignored.m_state.IsValid(),
"Package validation unexpectedly failed: " << submit_spend_ignored.m_state.GetRejectReason());
+ BOOST_CHECK_EQUAL(submit_spend_ignored.m_tx_results.size(), 2);
auto it_child2_ignored = submit_spend_ignored.m_tx_results.find(ptx_child2->GetWitnessHash());
auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash());
BOOST_CHECK(it_child2_ignored != submit_spend_ignored.m_tx_results.end());
@@ -475,9 +502,6 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child2->GetHash())));
BOOST_CHECK(!m_node.mempool->exists(GenTxid::Wtxid(ptx_child2->GetWitnessHash())));
BOOST_CHECK(m_node.mempool->exists(GenTxid::Wtxid(ptx_grandchild->GetWitnessHash())));
-
- // Since child2 is ignored, grandchild would be validated individually.
- BOOST_CHECK(submit_spend_ignored.m_package_feerate == std::nullopt);
}
// A package Package{parent1, parent2, parent3, child} where the parents are a mixture of
@@ -568,6 +592,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
{
const auto mixed_result = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_mixed, false);
BOOST_CHECK_MESSAGE(mixed_result.m_state.IsValid(), mixed_result.m_state.GetRejectReason());
+ BOOST_CHECK_EQUAL(mixed_result.m_tx_results.size(), package_mixed.size());
auto it_parent1 = mixed_result.m_tx_results.find(ptx_parent1->GetWitnessHash());
auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash());
auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash());
@@ -590,11 +615,12 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_mixed_child->GetHash())));
// package feerate should include parent3 and child. It should not include parent1 or parent2_v1.
- BOOST_CHECK(mixed_result.m_package_feerate.has_value());
const CFeeRate expected_feerate(1 * COIN, GetVirtualTransactionSize(*ptx_parent3) + GetVirtualTransactionSize(*ptx_mixed_child));
- BOOST_CHECK_MESSAGE(mixed_result.m_package_feerate.value() == expected_feerate,
- strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(),
- mixed_result.m_package_feerate.value().ToString()));
+ BOOST_CHECK(it_parent3->second.m_effective_feerate.value() == expected_feerate);
+ BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
+ std::vector<uint256> expected_wtxids({ptx_parent3->GetWitnessHash(), ptx_mixed_child->GetWitnessHash()});
+ BOOST_CHECK(it_parent3->second.m_wtxids_fee_calculations.value() == expected_wtxids);
+ BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
}
}
@@ -638,16 +664,12 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
const auto submit_cpfp_deprio = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
package_cpfp, /*test_accept=*/ false);
+ BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
BOOST_CHECK_MESSAGE(submit_cpfp_deprio.m_state.IsInvalid(),
"Package validation unexpectedly succeeded: " << submit_cpfp_deprio.m_state.GetRejectReason());
BOOST_CHECK(submit_cpfp_deprio.m_tx_results.empty());
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
const CFeeRate expected_feerate(0, GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child));
- BOOST_CHECK(submit_cpfp_deprio.m_package_feerate.has_value());
- BOOST_CHECK(submit_cpfp_deprio.m_package_feerate.value() == CFeeRate{0});
- BOOST_CHECK_MESSAGE(submit_cpfp_deprio.m_package_feerate.value() == expected_feerate,
- strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(),
- submit_cpfp_deprio.m_package_feerate.value().ToString()));
}
// Clear the prioritisation of the parent transaction.
@@ -662,6 +684,7 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
expected_pool_size += 2;
BOOST_CHECK_MESSAGE(submit_cpfp.m_state.IsValid(),
"Package validation unexpectedly failed: " << submit_cpfp.m_state.GetRejectReason());
+ BOOST_CHECK_EQUAL(submit_cpfp.m_tx_results.size(), package_cpfp.size());
auto it_parent = submit_cpfp.m_tx_results.find(tx_parent->GetWitnessHash());
auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
BOOST_CHECK(it_parent != submit_cpfp.m_tx_results.end());
@@ -677,11 +700,12 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
const CFeeRate expected_feerate(coinbase_value - child_value,
GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child));
+ BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
+ BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
+ std::vector<uint256> expected_wtxids({tx_parent->GetWitnessHash(), tx_child->GetWitnessHash()});
+ BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
+ BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
BOOST_CHECK(expected_feerate.GetFeePerK() > 1000);
- BOOST_CHECK(submit_cpfp.m_package_feerate.has_value());
- BOOST_CHECK_MESSAGE(submit_cpfp.m_package_feerate.value() == expected_feerate,
- strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(),
- submit_cpfp.m_package_feerate.value().ToString()));
}
// Just because we allow low-fee parents doesn't mean we allow low-feerate packages.
@@ -716,10 +740,6 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
const CFeeRate expected_feerate(200,
GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
BOOST_CHECK(expected_feerate.GetFeePerK() < 1000);
- BOOST_CHECK(submit_package_too_low.m_package_feerate.has_value());
- BOOST_CHECK_MESSAGE(submit_package_too_low.m_package_feerate.value() == expected_feerate,
- strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(),
- submit_package_too_low.m_package_feerate.value().ToString()));
}
// Package feerate includes the modified fees of the transactions.
@@ -734,10 +754,20 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
"Package validation unexpectedly failed" << submit_prioritised_package.m_state.GetRejectReason());
const CFeeRate expected_feerate(1 * COIN + 200,
GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
- BOOST_CHECK(submit_prioritised_package.m_package_feerate.has_value());
- BOOST_CHECK_MESSAGE(submit_prioritised_package.m_package_feerate.value() == expected_feerate,
- strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(),
- submit_prioritised_package.m_package_feerate.value().ToString()));
+ BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size());
+ auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash());
+ auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash());
+ BOOST_CHECK(it_parent != submit_prioritised_package.m_tx_results.end());
+ BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
+ BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
+ BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
+ BOOST_CHECK(it_child != submit_prioritised_package.m_tx_results.end());
+ BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
+ BOOST_CHECK(it_child->second.m_base_fees.value() == 200);
+ BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
+ std::vector<uint256> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()});
+ BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
+ BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
}
// Package feerate is calculated without topology in mind; it's just aggregating fees and sizes.
@@ -770,10 +800,6 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
BOOST_CHECK_MESSAGE(submit_rich_parent.m_state.IsInvalid(), "Package validation unexpectedly succeeded");
// The child would have been validated on its own and failed, then submitted as a "package" of 1.
- // The package feerate is just the child's feerate, which is 0sat/vb.
- BOOST_CHECK(submit_rich_parent.m_package_feerate.has_value());
- BOOST_CHECK_MESSAGE(submit_rich_parent.m_package_feerate.value() == CFeeRate(),
- "expected 0, got " << submit_rich_parent.m_package_feerate.value().ToString());
BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(), "package-fee-too-low");
@@ -783,6 +809,7 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
BOOST_CHECK(it_parent->second.m_state.GetRejectReason() == "");
BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee,
strprintf("rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value()));
+ BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(high_parent_fee, GetVirtualTransactionSize(*tx_parent_rich)));
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent_rich->GetHash())));
diff --git a/src/test/txreconciliation_tests.cpp b/src/test/txreconciliation_tests.cpp
new file mode 100644
index 0000000000..e258e3353d
--- /dev/null
+++ b/src/test/txreconciliation_tests.cpp
@@ -0,0 +1,84 @@
+// Copyright (c) 2021-2022 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 <node/txreconciliation.h>
+
+#include <test/util/setup_common.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(txreconciliation_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(RegisterPeerTest)
+{
+ TxReconciliationTracker tracker(TXRECONCILIATION_VERSION);
+ const uint64_t salt = 0;
+
+ // Prepare a peer for reconciliation.
+ tracker.PreRegisterPeer(0);
+
+ // Invalid version.
+ BOOST_CHECK_EQUAL(tracker.RegisterPeer(/*peer_id=*/0, /*is_peer_inbound=*/true,
+ /*peer_recon_version=*/0, salt),
+ ReconciliationRegisterResult::PROTOCOL_VIOLATION);
+
+ // Valid registration (inbound and outbound peers).
+ BOOST_REQUIRE(!tracker.IsPeerRegistered(0));
+ BOOST_REQUIRE_EQUAL(tracker.RegisterPeer(0, true, 1, salt), ReconciliationRegisterResult::SUCCESS);
+ BOOST_CHECK(tracker.IsPeerRegistered(0));
+ BOOST_REQUIRE(!tracker.IsPeerRegistered(1));
+ tracker.PreRegisterPeer(1);
+ BOOST_REQUIRE(tracker.RegisterPeer(1, false, 1, salt) == ReconciliationRegisterResult::SUCCESS);
+ BOOST_CHECK(tracker.IsPeerRegistered(1));
+
+ // Reconciliation version is higher than ours, should be able to register.
+ BOOST_REQUIRE(!tracker.IsPeerRegistered(2));
+ tracker.PreRegisterPeer(2);
+ BOOST_REQUIRE(tracker.RegisterPeer(2, true, 2, salt) == ReconciliationRegisterResult::SUCCESS);
+ BOOST_CHECK(tracker.IsPeerRegistered(2));
+
+ // Try registering for the second time.
+ BOOST_REQUIRE(tracker.RegisterPeer(1, false, 1, salt) == ReconciliationRegisterResult::ALREADY_REGISTERED);
+
+ // Do not register if there were no pre-registration for the peer.
+ BOOST_REQUIRE_EQUAL(tracker.RegisterPeer(100, true, 1, salt), ReconciliationRegisterResult::NOT_FOUND);
+ BOOST_CHECK(!tracker.IsPeerRegistered(100));
+}
+
+BOOST_AUTO_TEST_CASE(ForgetPeerTest)
+{
+ TxReconciliationTracker tracker(TXRECONCILIATION_VERSION);
+ NodeId peer_id0 = 0;
+
+ // Removing peer after pre-registring works and does not let to register the peer.
+ tracker.PreRegisterPeer(peer_id0);
+ tracker.ForgetPeer(peer_id0);
+ BOOST_CHECK_EQUAL(tracker.RegisterPeer(peer_id0, true, 1, 1), ReconciliationRegisterResult::NOT_FOUND);
+
+ // Removing peer after it is registered works.
+ tracker.PreRegisterPeer(peer_id0);
+ BOOST_REQUIRE(!tracker.IsPeerRegistered(peer_id0));
+ BOOST_REQUIRE_EQUAL(tracker.RegisterPeer(peer_id0, true, 1, 1), ReconciliationRegisterResult::SUCCESS);
+ BOOST_CHECK(tracker.IsPeerRegistered(peer_id0));
+ tracker.ForgetPeer(peer_id0);
+ BOOST_CHECK(!tracker.IsPeerRegistered(peer_id0));
+}
+
+BOOST_AUTO_TEST_CASE(IsPeerRegisteredTest)
+{
+ TxReconciliationTracker tracker(TXRECONCILIATION_VERSION);
+ NodeId peer_id0 = 0;
+
+ BOOST_REQUIRE(!tracker.IsPeerRegistered(peer_id0));
+ tracker.PreRegisterPeer(peer_id0);
+ BOOST_REQUIRE(!tracker.IsPeerRegistered(peer_id0));
+
+ BOOST_REQUIRE_EQUAL(tracker.RegisterPeer(peer_id0, true, 1, 1), ReconciliationRegisterResult::SUCCESS);
+ BOOST_CHECK(tracker.IsPeerRegistered(peer_id0));
+
+ tracker.ForgetPeer(peer_id0);
+ BOOST_CHECK(!tracker.IsPeerRegistered(peer_id0));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txrequest_tests.cpp b/src/test/txrequest_tests.cpp
index a4ed1e8b3a..17a55d5ab5 100644
--- a/src/test/txrequest_tests.cpp
+++ b/src/test/txrequest_tests.cpp
@@ -6,6 +6,7 @@
#include <txrequest.h>
#include <uint256.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <algorithm>
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 633f75ff4f..8cdea3890e 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -77,7 +77,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
LOCK(cs_main);
BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash());
}
- m_node.mempool->clear();
+ BOOST_CHECK_EQUAL(m_node.mempool->size(), 1U);
+ WITH_LOCK(m_node.mempool->cs, m_node.mempool->removeRecursive(CTransaction{spends[0]}, MemPoolRemovalReason::CONFLICT));
+ BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U);
// Test 3: ... and should be rejected if spend2 is in the memory pool
BOOST_CHECK(ToMemPool(spends[1]));
@@ -86,7 +88,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
LOCK(cs_main);
BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash());
}
- m_node.mempool->clear();
+ BOOST_CHECK_EQUAL(m_node.mempool->size(), 1U);
+ WITH_LOCK(m_node.mempool->cs, m_node.mempool->removeRecursive(CTransaction{spends[1]}, MemPoolRemovalReason::CONFLICT));
+ BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U);
// Final sanity test: first spend in *m_node.mempool, second in block, that's OK:
std::vector<CMutableTransaction> oneSpend;
@@ -113,7 +117,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
// should fail.
// Capture this interaction with the upgraded_nop argument: set it when evaluating
// any script flag that is implemented as an upgraded NOP code.
-static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
PrecomputedTransactionData txdata;
diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp
index bc206fc945..9caefe43e2 100644
--- a/src/test/uint256_tests.cpp
+++ b/src/test/uint256_tests.cpp
@@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G
BOOST_CHECK(GetSerializeSize(R1L, PROTOCOL_VERSION) == 32);
BOOST_CHECK(GetSerializeSize(ZeroL, PROTOCOL_VERSION) == 32);
- CDataStream ss(0, PROTOCOL_VERSION);
+ DataStream ss{};
ss << R1L;
BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+32));
ss >> TmpL;
diff --git a/src/test/util/blockfilter.cpp b/src/test/util/blockfilter.cpp
index 3ae22921b9..ec703c6a7b 100644
--- a/src/test/util/blockfilter.cpp
+++ b/src/test/util/blockfilter.cpp
@@ -28,4 +28,3 @@ bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex* block_index,
filter = BlockFilter(filter_type, block, block_undo);
return true;
}
-
diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h
index 2f0021b114..e664435e03 100644
--- a/src/test/util/chainstate.h
+++ b/src/test/util/chainstate.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
@@ -11,6 +11,7 @@
#include <node/context.h>
#include <node/utxo_snapshot.h>
#include <rpc/blockchain.h>
+#include <test/util/setup_common.h>
#include <validation.h>
#include <univalue.h>
@@ -20,11 +21,24 @@ const auto NoMalleation = [](AutoFile& file, node::SnapshotMetadata& meta){};
/**
* Create and activate a UTXO snapshot, optionally providing a function to
* malleate the snapshot.
+ *
+ * If `reset_chainstate` is true, reset the original chainstate back to the genesis
+ * block. This allows us to simulate more realistic conditions in which a snapshot is
+ * loaded into an otherwise mostly-uninitialized datadir. It also allows us to test
+ * conditions that would otherwise cause shutdowns based on the IBD chainstate going
+ * past the snapshot it generated.
*/
template<typename F = decltype(NoMalleation)>
static bool
-CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F malleation = NoMalleation)
+CreateAndActivateUTXOSnapshot(
+ TestingSetup* fixture,
+ F malleation = NoMalleation,
+ bool reset_chainstate = false,
+ bool in_memory_chainstate = false)
{
+ node::NodeContext& node = fixture->m_node;
+ fs::path root = fixture->m_path_root;
+
// Write out a snapshot to the test's tempdir.
//
int height;
@@ -47,7 +61,38 @@ CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F ma
malleation(auto_infile, metadata);
- return node.chainman->ActivateSnapshot(auto_infile, metadata, /*in_memory=*/true);
+ if (reset_chainstate) {
+ {
+ // What follows is code to selectively reset chainstate data without
+ // disturbing the existing BlockManager instance, which is needed to
+ // recognize the headers chain previously generated by the chainstate we're
+ // removing. Without those headers, we can't activate the snapshot below.
+ //
+ // This is a stripped-down version of node::LoadChainstate which
+ // preserves the block index.
+ LOCK(::cs_main);
+ uint256 gen_hash = node.chainman->ActiveChainstate().m_chain[0]->GetBlockHash();
+ node.chainman->ResetChainstates();
+ node.chainman->InitializeChainstate(node.mempool.get());
+ Chainstate& chain = node.chainman->ActiveChainstate();
+ Assert(chain.LoadGenesisBlock());
+ // These cache values will be corrected shortly in `MaybeRebalanceCaches`.
+ chain.InitCoinsDB(1 << 20, true, false, "");
+ chain.InitCoinsCache(1 << 20);
+ chain.CoinsTip().SetBestBlock(gen_hash);
+ chain.setBlockIndexCandidates.insert(node.chainman->m_blockman.LookupBlockIndex(gen_hash));
+ chain.LoadChainTip();
+ node.chainman->MaybeRebalanceCaches();
+ }
+ BlockValidationState state;
+ if (!node.chainman->ActiveChainstate().ActivateBestChain(state)) {
+ throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
+ }
+ Assert(
+ 0 == WITH_LOCK(node.chainman->GetMutex(), return node.chainman->ActiveHeight()));
+ }
+
+ return node.chainman->ActivateSnapshot(auto_infile, metadata, in_memory_chainstate);
}
diff --git a/src/test/util/coins.cpp b/src/test/util/coins.cpp
new file mode 100644
index 0000000000..9b6c5535c5
--- /dev/null
+++ b/src/test/util/coins.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) 2023 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/util/coins.h>
+
+#include <coins.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <test/util/random.h>
+#include <uint256.h>
+
+#include <stdint.h>
+#include <utility>
+
+COutPoint AddTestCoin(CCoinsViewCache& coins_view)
+{
+ Coin new_coin;
+ const uint256 txid{InsecureRand256()};
+ COutPoint outpoint{txid, /*nIn=*/0};
+ new_coin.nHeight = 1;
+ new_coin.out.nValue = InsecureRandMoneyAmount();
+ new_coin.out.scriptPubKey.assign(uint32_t{56}, 1);
+ coins_view.AddCoin(outpoint, std::move(new_coin), /*possible_overwrite=*/false);
+
+ return outpoint;
+};
diff --git a/src/test/util/coins.h b/src/test/util/coins.h
new file mode 100644
index 0000000000..5e6f4293ae
--- /dev/null
+++ b/src/test/util/coins.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2023 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_UTIL_COINS_H
+#define BITCOIN_TEST_UTIL_COINS_H
+
+#include <primitives/transaction.h>
+
+class CCoinsViewCache;
+
+/**
+ * Create a Coin with DynamicMemoryUsage of 80 bytes and add it to the given view.
+ * @param[in,out] coins_view The coins view cache to add the new coin to.
+ * @returns the COutPoint of the created coin.
+ */
+COutPoint AddTestCoin(CCoinsViewCache& coins_view);
+
+#endif // BITCOIN_TEST_UTIL_COINS_H
diff --git a/src/test/util/json.cpp b/src/test/util/json.cpp
new file mode 100644
index 0000000000..ad3c346c84
--- /dev/null
+++ b/src/test/util/json.cpp
@@ -0,0 +1,17 @@
+// Copyright (c) 2023 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/util/json.h>
+
+#include <string>
+#include <util/check.h>
+
+#include <univalue.h>
+
+UniValue read_json(const std::string& jsondata)
+{
+ UniValue v;
+ Assert(v.read(jsondata) && v.isArray());
+ return v.get_array();
+}
diff --git a/src/test/util/json.h b/src/test/util/json.h
new file mode 100644
index 0000000000..5b1026762e
--- /dev/null
+++ b/src/test/util/json.h
@@ -0,0 +1,14 @@
+// Copyright (c) 2023 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_UTIL_JSON_H
+#define BITCOIN_TEST_UTIL_JSON_H
+
+#include <string>
+
+#include <univalue.h>
+
+UniValue read_json(const std::string& jsondata);
+
+#endif // BITCOIN_TEST_UTIL_JSON_H
diff --git a/src/test/util/logging.h b/src/test/util/logging.h
index f477088392..73ac23825f 100644
--- a/src/test/util/logging.h
+++ b/src/test/util/logging.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp
index faa0b2878c..0df1db84c4 100644
--- a/src/test/util/mining.cpp
+++ b/src/test/util/mining.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,7 +8,6 @@
#include <consensus/merkle.h>
#include <key_io.h>
#include <node/context.h>
-#include <node/miner.h>
#include <pow.h>
#include <script/standard.h>
#include <test/util/script.h>
@@ -74,10 +73,11 @@ CTxIn MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
return CTxIn{block->vtx[0]->GetHash(), 0};
}
-std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
+std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey,
+ const BlockAssembler::Options& assembler_options)
{
auto block = std::make_shared<CBlock>(
- BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get())}
+ BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get()), assembler_options}
.CreateNewBlock(coinbase_scriptPubKey)
->block);
@@ -87,3 +87,9 @@ std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coi
return block;
}
+std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
+{
+ BlockAssembler::Options assembler_options;
+ ApplyArgsManOptions(*node.args, assembler_options);
+ return PrepareBlock(node, coinbase_scriptPubKey, assembler_options);
+}
diff --git a/src/test/util/mining.h b/src/test/util/mining.h
index 09e712cd35..70b1f7b3fb 100644
--- a/src/test/util/mining.h
+++ b/src/test/util/mining.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_TEST_UTIL_MINING_H
#define BITCOIN_TEST_UTIL_MINING_H
+#include <node/miner.h>
+
#include <memory>
#include <string>
#include <vector>
@@ -25,6 +27,8 @@ CTxIn MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey);
/** Prepare a block to be mined */
std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey);
+std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext& node, const CScript& coinbase_scriptPubKey,
+ const node::BlockAssembler::Options& assembler_options);
/** RPC-like helper function, returns the generated coin */
CTxIn generatetoaddress(const node::NodeContext&, const std::string& address);
diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp
index 2e3e16e681..ac5dfe9e73 100644
--- a/src/test/util/net.cpp
+++ b/src/test/util/net.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -67,15 +67,14 @@ void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, Span<const uint8_t> msg_by
assert(node.ReceiveMsgBytes(msg_bytes, complete));
if (complete) {
size_t nSizeAdded = 0;
- auto it(node.vRecvMsg.begin());
- for (; it != node.vRecvMsg.end(); ++it) {
+ for (const auto& msg : node.vRecvMsg) {
// vRecvMsg contains only completed CNetMessage
// the single possible partially deserialized message are held by TransportDeserializer
- nSizeAdded += it->m_raw_message_size;
+ nSizeAdded += msg.m_raw_message_size;
}
{
LOCK(node.cs_vProcessMsg);
- node.vProcessMsg.splice(node.vProcessMsg.end(), node.vRecvMsg, node.vRecvMsg.begin(), it);
+ node.vProcessMsg.splice(node.vProcessMsg.end(), node.vRecvMsg);
node.nProcessQueueSize += nSizeAdded;
node.fPauseRecv = node.nProcessQueueSize > nReceiveFloodSize;
}
diff --git a/src/test/util/net.h b/src/test/util/net.h
index 73543de4ca..e6506b0d08 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -103,7 +103,7 @@ constexpr auto ALL_NETWORKS = std::array{
class StaticContentsSock : public Sock
{
public:
- explicit StaticContentsSock(const std::string& contents) : m_contents{contents}, m_consumed{0}
+ explicit StaticContentsSock(const std::string& contents) : m_contents{contents}
{
// Just a dummy number that is not INVALID_SOCKET.
m_socket = INVALID_SOCKET - 1;
@@ -166,6 +166,10 @@ public:
return 0;
}
+ bool SetNonBlocking() const override { return true; }
+
+ bool IsSelectable() const override { return true; }
+
bool Wait(std::chrono::milliseconds timeout,
Event requested,
Event* occurred = nullptr) const override
@@ -187,7 +191,7 @@ public:
private:
const std::string m_contents;
- mutable size_t m_consumed;
+ mutable size_t m_consumed{0};
};
std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(int n_candidates, FastRandomContext& random_context);
diff --git a/src/test/util/random.h b/src/test/util/random.h
new file mode 100644
index 0000000000..7997e8a346
--- /dev/null
+++ b/src/test/util/random.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2023 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_UTIL_RANDOM_H
+#define BITCOIN_TEST_UTIL_RANDOM_H
+
+#include <consensus/amount.h>
+#include <random.h>
+#include <test/util/setup_common.h>
+#include <uint256.h>
+
+#include <cstdint>
+
+static inline uint32_t InsecureRand32()
+{
+ return g_insecure_rand_ctx.rand32();
+}
+
+static inline uint256 InsecureRand256()
+{
+ return g_insecure_rand_ctx.rand256();
+}
+
+static inline uint64_t InsecureRandBits(int bits)
+{
+ return g_insecure_rand_ctx.randbits(bits);
+}
+
+static inline uint64_t InsecureRandRange(uint64_t range)
+{
+ return g_insecure_rand_ctx.randrange(range);
+}
+
+static inline bool InsecureRandBool()
+{
+ return g_insecure_rand_ctx.randbool();
+}
+
+static inline CAmount InsecureRandMoneyAmount()
+{
+ return static_cast<CAmount>(InsecureRandRange(MAX_MONEY + 1));
+}
+
+#endif // BITCOIN_TEST_UTIL_RANDOM_H
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 74b055ee45..58593c9d5b 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,6 +9,7 @@
#include <addrman.h>
#include <banman.h>
#include <chainparams.h>
+#include <common/url.h>
#include <consensus/consensus.h>
#include <consensus/params.h>
#include <consensus/validation.h>
@@ -16,6 +17,7 @@
#include <init.h>
#include <init/common.h>
#include <interfaces/chain.h>
+#include <kernel/mempool_entry.h>
#include <net.h>
#include <net_processing.h>
#include <node/blockstorage.h>
@@ -36,6 +38,7 @@
#include <shutdown.h>
#include <streams.h>
#include <test/util/net.h>
+#include <test/util/txmempool.h>
#include <timedata.h>
#include <txdb.h>
#include <txmempool.h>
@@ -45,7 +48,6 @@
#include <util/threadnames.h>
#include <util/time.h>
#include <util/translation.h>
-#include <util/url.h>
#include <util/vector.h>
#include <validation.h>
#include <validationinterface.h>
@@ -60,7 +62,6 @@ using node::ApplyArgsManOptions;
using node::BlockAssembler;
using node::CalculateCacheSizes;
using node::LoadChainstate;
-using node::NodeContext;
using node::RegenerateCommitments;
using node::VerifyLoadedChainstate;
@@ -146,7 +147,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes));
m_node.chain = interfaces::MakeChain(m_node);
- fCheckBlockIndex = true;
static bool noui_connected = false;
if (!noui_connected) {
noui_connect();
@@ -162,19 +162,6 @@ BasicTestingSetup::~BasicTestingSetup()
gArgs.ClearArgs();
}
-CTxMemPool::Options MemPoolOptionsForTest(const NodeContext& node)
-{
- CTxMemPool::Options mempool_opts{
- .estimator = node.fee_estimator.get(),
- // Default to always checking mempool regardless of
- // chainparams.DefaultConsistencyChecks for tests
- .check_ratio = 1,
- };
- const auto err{ApplyArgsManOptions(*node.args, ::Params(), mempool_opts)};
- Assert(!err);
- return mempool_opts;
-}
-
ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args)
: BasicTestingSetup(chainName, extra_args)
{
@@ -193,15 +180,18 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve
const ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
+ .datadir = m_args.GetDataDirNet(),
.adjusted_time_callback = GetAdjustedTime,
+ .check_block_index = true,
};
- m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts);
- m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(m_cache_sizes.block_tree_db, true);
+ m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, node::BlockManager::Options{});
+ m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(DBParams{
+ .path = m_args.GetDataDirNet() / "blocks" / "index",
+ .cache_bytes = static_cast<size_t>(m_cache_sizes.block_tree_db),
+ .memory_only = true});
- // Start script-checking threads. Set g_parallel_script_checks to true so they are used.
constexpr int script_check_threads = 2;
StartScriptCheckWorkerThreads(script_check_threads);
- g_parallel_script_checks = true;
}
ChainTestingSetup::~ChainTestingSetup()
@@ -220,32 +210,45 @@ ChainTestingSetup::~ChainTestingSetup()
m_node.chainman.reset();
}
-TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args)
- : ChainTestingSetup(chainName, extra_args)
+void TestingSetup::LoadVerifyActivateChainstate()
{
- // Ideally we'd move all the RPC tests to the functional testing framework
- // instead of unit tests, but for now we need these here.
- RegisterAllCoreRPCCommands(tableRPC);
-
+ auto& chainman{*Assert(m_node.chainman)};
node::ChainstateLoadOptions options;
options.mempool = Assert(m_node.mempool.get());
- options.block_tree_db_in_memory = true;
- options.coins_db_in_memory = true;
+ options.block_tree_db_in_memory = m_block_tree_db_in_memory;
+ options.coins_db_in_memory = m_coins_db_in_memory;
options.reindex = node::fReindex;
options.reindex_chainstate = m_args.GetBoolArg("-reindex-chainstate", false);
- options.prune = node::fPruneMode;
+ options.prune = chainman.m_blockman.IsPruneMode();
options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
options.check_level = m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
- auto [status, error] = LoadChainstate(*Assert(m_node.chainman), m_cache_sizes, options);
+ options.require_full_verification = m_args.IsArgSet("-checkblocks") || m_args.IsArgSet("-checklevel");
+ auto [status, error] = LoadChainstate(chainman, m_cache_sizes, options);
assert(status == node::ChainstateLoadStatus::SUCCESS);
- std::tie(status, error) = VerifyLoadedChainstate(*Assert(m_node.chainman), options);
+ std::tie(status, error) = VerifyLoadedChainstate(chainman, options);
assert(status == node::ChainstateLoadStatus::SUCCESS);
BlockValidationState state;
- if (!m_node.chainman->ActiveChainstate().ActivateBestChain(state)) {
+ if (!chainman.ActiveChainstate().ActivateBestChain(state)) {
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
}
+}
+
+TestingSetup::TestingSetup(
+ const std::string& chainName,
+ const std::vector<const char*>& extra_args,
+ const bool coins_db_in_memory,
+ const bool block_tree_db_in_memory)
+ : ChainTestingSetup(chainName, extra_args),
+ m_coins_db_in_memory(coins_db_in_memory),
+ m_block_tree_db_in_memory(block_tree_db_in_memory)
+{
+ // Ideally we'd move all the RPC tests to the functional testing framework
+ // instead of unit tests, but for now we need these here.
+ RegisterAllCoreRPCCommands(tableRPC);
+
+ LoadVerifyActivateChainstate();
m_node.netgroupman = std::make_unique<NetGroupManager>(/*asmap=*/std::vector<bool>());
m_node.addrman = std::make_unique<AddrMan>(*m_node.netgroupman,
@@ -263,8 +266,12 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
}
}
-TestChain100Setup::TestChain100Setup(const std::string& chain_name, const std::vector<const char*>& extra_args)
- : TestingSetup{chain_name, extra_args}
+TestChain100Setup::TestChain100Setup(
+ const std::string& chain_name,
+ const std::vector<const char*>& extra_args,
+ const bool coins_db_in_memory,
+ const bool block_tree_db_in_memory)
+ : TestingSetup{CBaseChainParams::REGTEST, extra_args, coins_db_in_memory, block_tree_db_in_memory}
{
SetMockTime(1598887952);
constexpr std::array<unsigned char, 32> vchKey = {
@@ -320,7 +327,7 @@ CBlock TestChain100Setup::CreateAndProcessBlock(
chainstate = &Assert(m_node.chainman)->ActiveChainstate();
}
- const CBlock block = this->CreateBlock(txns, scriptPubKey, *chainstate);
+ CBlock block = this->CreateBlock(txns, scriptPubKey, *chainstate);
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, true, nullptr);
@@ -396,15 +403,15 @@ std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContex
unspent_prevouts.pop_front();
}
const size_t num_outputs = det_rand.randrange(24) + 1;
- // Approximately 1000sat "fee," equal output amounts.
- const CAmount amount_per_output = (total_in - 1000) / num_outputs;
+ const CAmount fee = 100 * det_rand.randrange(30);
+ const CAmount amount_per_output = (total_in - fee) / num_outputs;
for (size_t n{0}; n < num_outputs; ++n) {
CScript spk = CScript() << CScriptNum(num_transactions + n);
mtx.vout.push_back(CTxOut(amount_per_output, spk));
}
CTransactionRef ptx = MakeTransactionRef(mtx);
mempool_transactions.push_back(ptx);
- if (amount_per_output > 2000) {
+ if (amount_per_output > 3000) {
// If the value is high enough to fund another transaction + fees, keep track of it so
// it can be used to build a more complex transaction graph. Insert randomly into
// unspent_prevouts for extra randomness in the resulting structures.
@@ -414,26 +421,17 @@ std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContex
}
}
if (submit) {
- LOCK2(m_node.mempool->cs, cs_main);
+ LOCK2(cs_main, m_node.mempool->cs);
LockPoints lp;
- m_node.mempool->addUnchecked(CTxMemPoolEntry(ptx, 1000, 0, 1, false, 4, lp));
+ m_node.mempool->addUnchecked(CTxMemPoolEntry(ptx, /*fee=*/(total_in - num_outputs * amount_per_output),
+ /*time=*/0, /*entry_height=*/1,
+ /*spends_coinbase=*/false, /*sigops_cost=*/4, lp));
}
--num_transactions;
}
return mempool_transactions;
}
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const
-{
- return FromTx(MakeTransactionRef(tx));
-}
-
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx) const
-{
- return CTxMemPoolEntry(tx, nFee, nTime, nHeight,
- spendsCoinbase, sigOpCost, lp);
-}
-
/**
* @returns a real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
* with 9 txs.
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index 136ee1fd62..8874db7e75 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,21 +8,23 @@
#include <chainparamsbase.h>
#include <fs.h>
#include <key.h>
-#include <util/system.h>
#include <node/caches.h>
#include <node/context.h>
+#include <primitives/transaction.h>
#include <pubkey.h>
#include <random.h>
#include <stdexcept>
-#include <txmempool.h>
#include <util/check.h>
#include <util/string.h>
+#include <util/system.h>
#include <util/vector.h>
#include <functional>
#include <type_traits>
#include <vector>
+class Chainstate;
+
/** This is connected to the logger. Can be used to redirect logs to any other log */
extern const std::function<void(const std::string&)> G_TEST_LOG_FUN;
@@ -69,12 +71,6 @@ static inline void SeedInsecureRand(SeedRand seed = SeedRand::SEED)
}
}
-static inline uint32_t InsecureRand32() { return g_insecure_rand_ctx.rand32(); }
-static inline uint256 InsecureRand256() { return g_insecure_rand_ctx.rand256(); }
-static inline uint64_t InsecureRandBits(int bits) { return g_insecure_rand_ctx.randbits(bits); }
-static inline uint64_t InsecureRandRange(uint64_t range) { return g_insecure_rand_ctx.randrange(range); }
-static inline bool InsecureRandBool() { return g_insecure_rand_ctx.randbool(); }
-
static constexpr CAmount CENT{1000000};
/** Basic testing setup.
@@ -90,9 +86,6 @@ struct BasicTestingSetup {
ArgsManager m_args;
};
-
-CTxMemPool::Options MemPoolOptionsForTest(const node::NodeContext& node);
-
/** Testing setup that performs all steps up until right before
* ChainstateManager gets initialized. Meant for testing ChainstateManager
* initialization behaviour.
@@ -107,7 +100,16 @@ struct ChainTestingSetup : public BasicTestingSetup {
/** Testing setup that configures a complete environment.
*/
struct TestingSetup : public ChainTestingSetup {
- explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {});
+ bool m_coins_db_in_memory{true};
+ bool m_block_tree_db_in_memory{true};
+
+ void LoadVerifyActivateChainstate();
+
+ explicit TestingSetup(
+ const std::string& chainName = CBaseChainParams::MAIN,
+ const std::vector<const char*>& extra_args = {},
+ const bool coins_db_in_memory = true,
+ const bool block_tree_db_in_memory = true);
};
/** Identical to TestingSetup, but chain set to regtest */
@@ -124,8 +126,11 @@ class CScript;
* Testing fixture that pre-creates a 100-block REGTEST-mode block chain
*/
struct TestChain100Setup : public TestingSetup {
- TestChain100Setup(const std::string& chain_name = CBaseChainParams::REGTEST,
- const std::vector<const char*>& extra_args = {});
+ TestChain100Setup(
+ const std::string& chain_name = CBaseChainParams::REGTEST,
+ const std::vector<const char*>& extra_args = {},
+ const bool coins_db_in_memory = true,
+ const bool block_tree_db_in_memory = true);
/**
* Create a new block with just given transactions, coinbase paying to
@@ -201,33 +206,6 @@ std::unique_ptr<T> MakeNoLogFileContext(const std::string& chain_name = CBaseCha
return std::make_unique<T>(chain_name, arguments);
}
-class CTxMemPoolEntry;
-
-struct TestMemPoolEntryHelper
-{
- // Default values
- CAmount nFee;
- int64_t nTime;
- unsigned int nHeight;
- bool spendsCoinbase;
- unsigned int sigOpCost;
- LockPoints lp;
-
- TestMemPoolEntryHelper() :
- nFee(0), nTime(0), nHeight(1),
- spendsCoinbase(false), sigOpCost(4) { }
-
- CTxMemPoolEntry FromTx(const CMutableTransaction& tx) const;
- CTxMemPoolEntry FromTx(const CTransactionRef& tx) const;
-
- // Change the default value
- TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; }
- TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; }
- TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
- TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
- TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; }
-};
-
CBlock getBlock13b8a();
// define an implicit conversion here so that uint256 may be used directly in BOOST_CHECK_*
diff --git a/src/test/util/txmempool.cpp b/src/test/util/txmempool.cpp
new file mode 100644
index 0000000000..1873cf5ec8
--- /dev/null
+++ b/src/test/util/txmempool.cpp
@@ -0,0 +1,38 @@
+// Copyright (c) 2022 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/util/txmempool.h>
+
+#include <chainparams.h>
+#include <node/context.h>
+#include <node/mempool_args.h>
+#include <txmempool.h>
+#include <util/check.h>
+#include <util/time.h>
+#include <util/translation.h>
+
+using node::NodeContext;
+
+CTxMemPool::Options MemPoolOptionsForTest(const NodeContext& node)
+{
+ CTxMemPool::Options mempool_opts{
+ .estimator = node.fee_estimator.get(),
+ // Default to always checking mempool regardless of
+ // chainparams.DefaultConsistencyChecks for tests
+ .check_ratio = 1,
+ };
+ const auto err{ApplyArgsManOptions(*node.args, ::Params(), mempool_opts)};
+ Assert(!err);
+ return mempool_opts;
+}
+
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const
+{
+ return FromTx(MakeTransactionRef(tx));
+}
+
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx) const
+{
+ return CTxMemPoolEntry{tx, nFee, TicksSinceEpoch<std::chrono::seconds>(time), nHeight, spendsCoinbase, sigOpCost, lp};
+}
diff --git a/src/test/util/txmempool.h b/src/test/util/txmempool.h
new file mode 100644
index 0000000000..2fe7d69693
--- /dev/null
+++ b/src/test/util/txmempool.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2022 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_UTIL_TXMEMPOOL_H
+#define BITCOIN_TEST_UTIL_TXMEMPOOL_H
+
+#include <txmempool.h>
+#include <util/time.h>
+
+namespace node {
+struct NodeContext;
+}
+
+CTxMemPool::Options MemPoolOptionsForTest(const node::NodeContext& node);
+
+struct TestMemPoolEntryHelper {
+ // Default values
+ CAmount nFee{0};
+ NodeSeconds time{};
+ unsigned int nHeight{1};
+ bool spendsCoinbase{false};
+ unsigned int sigOpCost{4};
+ LockPoints lp;
+
+ CTxMemPoolEntry FromTx(const CMutableTransaction& tx) const;
+ CTxMemPoolEntry FromTx(const CTransactionRef& tx) const;
+
+ // Change the default value
+ TestMemPoolEntryHelper& Fee(CAmount _fee) { nFee = _fee; return *this; }
+ TestMemPoolEntryHelper& Time(NodeSeconds tp) { time = tp; return *this; }
+ TestMemPoolEntryHelper& Height(unsigned int _height) { nHeight = _height; return *this; }
+ TestMemPoolEntryHelper& SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
+ TestMemPoolEntryHelper& SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; }
+};
+
+#endif // BITCOIN_TEST_UTIL_TXMEMPOOL_H
diff --git a/src/test/util/validation.cpp b/src/test/util/validation.cpp
index 49535855f9..c0d7a532dc 100644
--- a/src/test/util/validation.cpp
+++ b/src/test/util/validation.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/util/validation.h b/src/test/util/validation.h
index cbe7745b81..7a511a2b79 100644
--- a/src/test/util/validation.h
+++ b/src/test/util/validation.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/util/wallet.cpp b/src/test/util/wallet.cpp
deleted file mode 100644
index b54774cbb9..0000000000
--- a/src/test/util/wallet.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2019-2021 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/util/wallet.h>
-
-#include <key_io.h>
-#include <outputtype.h>
-#include <script/standard.h>
-#ifdef ENABLE_WALLET
-#include <util/check.h>
-#include <util/translation.h>
-#include <wallet/wallet.h>
-#endif
-
-using wallet::CWallet;
-
-const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj";
-
-#ifdef ENABLE_WALLET
-std::string getnewaddress(CWallet& w)
-{
- constexpr auto output_type = OutputType::BECH32;
- return EncodeDestination(*Assert(w.GetNewDestination(output_type, "")));
-}
-
-#endif // ENABLE_WALLET
diff --git a/src/test/util/wallet.h b/src/test/util/wallet.h
deleted file mode 100644
index 31281bf70e..0000000000
--- a/src/test/util/wallet.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2019 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_TEST_UTIL_WALLET_H
-#define BITCOIN_TEST_UTIL_WALLET_H
-
-#include <string>
-
-namespace wallet {
-class CWallet;
-} // namespace wallet
-
-// Constants //
-
-extern const std::string ADDRESS_BCRT1_UNSPENDABLE;
-
-// RPC-like //
-
-/** Import the address to the wallet */
-void importaddress(wallet::CWallet& wallet, const std::string& address);
-/** Returns a new address from the wallet */
-std::string getnewaddress(wallet::CWallet& w);
-
-
-#endif // BITCOIN_TEST_UTIL_WALLET_H
diff --git a/src/test/util/xoroshiro128plusplus.h b/src/test/util/xoroshiro128plusplus.h
new file mode 100644
index 0000000000..ac9f59b3f5
--- /dev/null
+++ b/src/test/util/xoroshiro128plusplus.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2022 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_UTIL_XOROSHIRO128PLUSPLUS_H
+#define BITCOIN_TEST_UTIL_XOROSHIRO128PLUSPLUS_H
+
+#include <cstdint>
+#include <limits>
+
+/** xoroshiro128++ PRNG. Extremely fast, not appropriate for cryptographic purposes.
+ *
+ * Memory footprint is 128bit, period is 2^128 - 1.
+ * This class is not thread-safe.
+ *
+ * Reference implementation available at https://prng.di.unimi.it/xoroshiro128plusplus.c
+ * See https://prng.di.unimi.it/
+ */
+class XoRoShiRo128PlusPlus
+{
+ uint64_t m_s0;
+ uint64_t m_s1;
+
+ [[nodiscard]] constexpr static uint64_t rotl(uint64_t x, int n)
+ {
+ return (x << n) | (x >> (64 - n));
+ }
+
+ [[nodiscard]] constexpr static uint64_t SplitMix64(uint64_t& seedval) noexcept
+ {
+ uint64_t z = (seedval += UINT64_C(0x9e3779b97f4a7c15));
+ z = (z ^ (z >> 30U)) * UINT64_C(0xbf58476d1ce4e5b9);
+ z = (z ^ (z >> 27U)) * UINT64_C(0x94d049bb133111eb);
+ return z ^ (z >> 31U);
+ }
+
+public:
+ using result_type = uint64_t;
+
+ constexpr explicit XoRoShiRo128PlusPlus(uint64_t seedval) noexcept
+ : m_s0(SplitMix64(seedval)), m_s1(SplitMix64(seedval))
+ {
+ }
+
+ // no copy - that is dangerous, we don't want accidentally copy the RNG and then have two streams
+ // with exactly the same results. If you need a copy, call copy().
+ XoRoShiRo128PlusPlus(const XoRoShiRo128PlusPlus&) = delete;
+ XoRoShiRo128PlusPlus& operator=(const XoRoShiRo128PlusPlus&) = delete;
+
+ // allow moves
+ XoRoShiRo128PlusPlus(XoRoShiRo128PlusPlus&&) = default;
+ XoRoShiRo128PlusPlus& operator=(XoRoShiRo128PlusPlus&&) = default;
+
+ ~XoRoShiRo128PlusPlus() = default;
+
+ constexpr result_type operator()() noexcept
+ {
+ uint64_t s0 = m_s0, s1 = m_s1;
+ const uint64_t result = rotl(s0 + s1, 17) + s0;
+ s1 ^= s0;
+ m_s0 = rotl(s0, 49) ^ s1 ^ (s1 << 21);
+ m_s1 = rotl(s1, 28);
+ return result;
+ }
+
+ static constexpr result_type min() noexcept { return std::numeric_limits<result_type>::min(); }
+ static constexpr result_type max() noexcept { return std::numeric_limits<result_type>::max(); }
+ static constexpr double entropy() noexcept { return 0.0; }
+};
+
+#endif // BITCOIN_TEST_UTIL_XOROSHIRO128PLUSPLUS_H
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 6e59d2e8e6..a13552653e 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,9 +9,8 @@
#include <hash.h> // For Hash()
#include <key.h> // For CKey
#include <sync.h>
-#include <test/util/logging.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
-#include <test/util/str.h>
#include <uint256.h>
#include <util/getuniquepath.h>
#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
@@ -26,6 +25,7 @@
#include <util/bitdeque.h>
#include <array>
+#include <cmath>
#include <fstream>
#include <limits>
#include <map>
@@ -54,31 +54,6 @@ namespace BCLog {
BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup)
-BOOST_AUTO_TEST_CASE(util_datadir)
-{
- // Use local args variable instead of m_args to avoid making assumptions about test setup
- ArgsManager args;
- args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
-
- const fs::path dd_norm = args.GetDataDirBase();
-
- args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/");
- args.ClearPathCache();
- BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
-
- args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/.");
- args.ClearPathCache();
- BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
-
- args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/./");
- args.ClearPathCache();
- BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
-
- args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/.//");
- args.ClearPathCache();
- BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
-}
-
namespace {
class NoCopyOrMove
{
@@ -123,6 +98,11 @@ BOOST_AUTO_TEST_CASE(util_check)
// Check nested Asserts
BOOST_CHECK_EQUAL(Assert((Assert(x).test() ? 3 : 0)), 3);
+
+ // Check -Wdangling-gsl does not trigger when copying the int. (It would
+ // trigger on "const int&")
+ const int nine{*Assert(std::optional<int>{9})};
+ BOOST_CHECK_EQUAL(9, nine);
}
BOOST_AUTO_TEST_CASE(util_criticalsection)
@@ -161,26 +141,52 @@ BOOST_AUTO_TEST_CASE(parse_hex)
// Basic test vector
result = ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
+ result = TryParseHex<uint8_t>("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").value();
+ BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
// Spaces between bytes must be supported
result = ParseHex("12 34 56 78");
BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
+ result = TryParseHex<uint8_t>("12 34 56 78").value();
+ BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
// Leading space must be supported (used in BerkeleyEnvironment::Salvage)
result = ParseHex(" 89 34 56 78");
BOOST_CHECK(result.size() == 4 && result[0] == 0x89 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
+ result = TryParseHex<uint8_t>(" 89 34 56 78").value();
+ BOOST_CHECK(result.size() == 4 && result[0] == 0x89 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
+
+ // Mixed case and spaces are supported
+ result = ParseHex(" Ff aA ");
+ BOOST_CHECK(result.size() == 2 && result[0] == 0xff && result[1] == 0xaa);
+ result = TryParseHex<uint8_t>(" Ff aA ").value();
+ BOOST_CHECK(result.size() == 2 && result[0] == 0xff && result[1] == 0xaa);
+
+ // Empty string is supported
+ result = ParseHex("");
+ BOOST_CHECK(result.size() == 0);
+ result = TryParseHex<uint8_t>("").value();
+ BOOST_CHECK(result.size() == 0);
+
+ // Spaces between nibbles is treated as invalid
+ BOOST_CHECK_EQUAL(ParseHex("AAF F").size(), 0);
+ BOOST_CHECK(!TryParseHex("AAF F").has_value());
- // Embedded null is treated as end
+ // Embedded null is treated as invalid
const std::string with_embedded_null{" 11 "s
" \0 "
" 22 "s};
BOOST_CHECK_EQUAL(with_embedded_null.size(), 11);
- result = ParseHex(with_embedded_null);
- BOOST_CHECK(result.size() == 1 && result[0] == 0x11);
+ BOOST_CHECK_EQUAL(ParseHex(with_embedded_null).size(), 0);
+ BOOST_CHECK(!TryParseHex(with_embedded_null).has_value());
- // Stop parsing at invalid value
- result = ParseHex("1234 invalid 1234");
- BOOST_CHECK(result.size() == 2 && result[0] == 0x12 && result[1] == 0x34);
+ // Non-hex is treated as invalid
+ BOOST_CHECK_EQUAL(ParseHex("1234 invalid 1234").size(), 0);
+ BOOST_CHECK(!TryParseHex("1234 invalid 1234").has_value());
+
+ // Truncated input is treated as invalid
+ BOOST_CHECK_EQUAL(ParseHex("12 3").size(), 0);
+ BOOST_CHECK(!TryParseHex("12 3").has_value());
}
BOOST_AUTO_TEST_CASE(util_HexStr)
@@ -293,1000 +299,6 @@ BOOST_AUTO_TEST_CASE(util_FormatISO8601Date)
BOOST_CHECK_EQUAL(FormatISO8601Date(1317425777), "2011-09-30");
}
-struct TestArgsManager : public ArgsManager
-{
- TestArgsManager() { m_network_only_args.clear(); }
- void ReadConfigString(const std::string str_config)
- {
- std::istringstream streamConfig(str_config);
- {
- LOCK(cs_args);
- m_settings.ro_config.clear();
- m_config_sections.clear();
- }
- std::string error;
- BOOST_REQUIRE(ReadConfigStream(streamConfig, "", error));
- }
- void SetNetworkOnlyArg(const std::string arg)
- {
- LOCK(cs_args);
- m_network_only_args.insert(arg);
- }
- void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args)
- {
- for (const auto& arg : args) {
- AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS);
- }
- }
- using ArgsManager::GetSetting;
- using ArgsManager::GetSettingsList;
- using ArgsManager::ReadConfigStream;
- using ArgsManager::cs_args;
- using ArgsManager::m_network;
- using ArgsManager::m_settings;
-};
-
-//! Test GetSetting and GetArg type coercion, negation, and default value handling.
-class CheckValueTest : public TestChain100Setup
-{
-public:
- struct Expect {
- util::SettingsValue setting;
- bool default_string = false;
- bool default_int = false;
- bool default_bool = false;
- const char* string_value = nullptr;
- std::optional<int64_t> int_value;
- std::optional<bool> bool_value;
- std::optional<std::vector<std::string>> list_value;
- const char* error = nullptr;
-
- explicit Expect(util::SettingsValue s) : setting(std::move(s)) {}
- Expect& DefaultString() { default_string = true; return *this; }
- Expect& DefaultInt() { default_int = true; return *this; }
- Expect& DefaultBool() { default_bool = true; return *this; }
- Expect& String(const char* s) { string_value = s; return *this; }
- Expect& Int(int64_t i) { int_value = i; return *this; }
- Expect& Bool(bool b) { bool_value = b; return *this; }
- Expect& List(std::vector<std::string> m) { list_value = std::move(m); return *this; }
- Expect& Error(const char* e) { error = e; return *this; }
- };
-
- void CheckValue(unsigned int flags, const char* arg, const Expect& expect)
- {
- TestArgsManager test;
- test.SetupArgs({{"-value", flags}});
- const char* argv[] = {"ignored", arg};
- std::string error;
- bool success = test.ParseParameters(arg ? 2 : 1, (char**)argv, error);
-
- BOOST_CHECK_EQUAL(test.GetSetting("-value").write(), expect.setting.write());
- auto settings_list = test.GetSettingsList("-value");
- if (expect.setting.isNull() || expect.setting.isFalse()) {
- BOOST_CHECK_EQUAL(settings_list.size(), 0U);
- } else {
- BOOST_CHECK_EQUAL(settings_list.size(), 1U);
- BOOST_CHECK_EQUAL(settings_list[0].write(), expect.setting.write());
- }
-
- if (expect.error) {
- BOOST_CHECK(!success);
- BOOST_CHECK_NE(error.find(expect.error), std::string::npos);
- } else {
- BOOST_CHECK(success);
- BOOST_CHECK_EQUAL(error, "");
- }
-
- if (expect.default_string) {
- BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), "zzzzz");
- } else if (expect.string_value) {
- BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), expect.string_value);
- } else {
- BOOST_CHECK(!success);
- }
-
- if (expect.default_int) {
- BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), 99999);
- } else if (expect.int_value) {
- BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), *expect.int_value);
- } else {
- BOOST_CHECK(!success);
- }
-
- if (expect.default_bool) {
- BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), false);
- BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), true);
- } else if (expect.bool_value) {
- BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), *expect.bool_value);
- BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), *expect.bool_value);
- } else {
- BOOST_CHECK(!success);
- }
-
- if (expect.list_value) {
- auto l = test.GetArgs("-value");
- BOOST_CHECK_EQUAL_COLLECTIONS(l.begin(), l.end(), expect.list_value->begin(), expect.list_value->end());
- } else {
- BOOST_CHECK(!success);
- }
- }
-};
-
-BOOST_FIXTURE_TEST_CASE(util_CheckValue, CheckValueTest)
-{
- using M = ArgsManager;
-
- CheckValue(M::ALLOW_ANY, nullptr, Expect{{}}.DefaultString().DefaultInt().DefaultBool().List({}));
- CheckValue(M::ALLOW_ANY, "-novalue", Expect{false}.String("0").Int(0).Bool(false).List({}));
- CheckValue(M::ALLOW_ANY, "-novalue=", Expect{false}.String("0").Int(0).Bool(false).List({}));
- CheckValue(M::ALLOW_ANY, "-novalue=0", Expect{true}.String("1").Int(1).Bool(true).List({"1"}));
- CheckValue(M::ALLOW_ANY, "-novalue=1", Expect{false}.String("0").Int(0).Bool(false).List({}));
- CheckValue(M::ALLOW_ANY, "-novalue=2", Expect{false}.String("0").Int(0).Bool(false).List({}));
- CheckValue(M::ALLOW_ANY, "-novalue=abc", Expect{true}.String("1").Int(1).Bool(true).List({"1"}));
- CheckValue(M::ALLOW_ANY, "-value", Expect{""}.String("").Int(0).Bool(true).List({""}));
- CheckValue(M::ALLOW_ANY, "-value=", Expect{""}.String("").Int(0).Bool(true).List({""}));
- CheckValue(M::ALLOW_ANY, "-value=0", Expect{"0"}.String("0").Int(0).Bool(false).List({"0"}));
- CheckValue(M::ALLOW_ANY, "-value=1", Expect{"1"}.String("1").Int(1).Bool(true).List({"1"}));
- CheckValue(M::ALLOW_ANY, "-value=2", Expect{"2"}.String("2").Int(2).Bool(true).List({"2"}));
- CheckValue(M::ALLOW_ANY, "-value=abc", Expect{"abc"}.String("abc").Int(0).Bool(false).List({"abc"}));
-}
-
-struct NoIncludeConfTest {
- std::string Parse(const char* arg)
- {
- TestArgsManager test;
- test.SetupArgs({{"-includeconf", ArgsManager::ALLOW_ANY}});
- std::array argv{"ignored", arg};
- std::string error;
- (void)test.ParseParameters(argv.size(), argv.data(), error);
- return error;
- }
-};
-
-BOOST_FIXTURE_TEST_CASE(util_NoIncludeConf, NoIncludeConfTest)
-{
- BOOST_CHECK_EQUAL(Parse("-noincludeconf"), "");
- BOOST_CHECK_EQUAL(Parse("-includeconf"), "-includeconf cannot be used from commandline; -includeconf=\"\"");
- BOOST_CHECK_EQUAL(Parse("-includeconf=file"), "-includeconf cannot be used from commandline; -includeconf=\"file\"");
-}
-
-BOOST_AUTO_TEST_CASE(util_ParseParameters)
-{
- TestArgsManager testArgs;
- const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
- const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
- const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY);
- const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
-
- const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
-
- std::string error;
- LOCK(testArgs.cs_args);
- testArgs.SetupArgs({a, b, ccc, d});
- BOOST_CHECK(testArgs.ParseParameters(0, (char**)argv_test, error));
- BOOST_CHECK(testArgs.m_settings.command_line_options.empty() && testArgs.m_settings.ro_config.empty());
-
- BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error));
- BOOST_CHECK(testArgs.m_settings.command_line_options.empty() && testArgs.m_settings.ro_config.empty());
-
- BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error));
- // expectation: -ignored is ignored (program name argument),
- // -a, -b and -ccc end up in map, -d ignored because it is after
- // a non-option argument (non-GNU option parsing)
- BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 3 && testArgs.m_settings.ro_config.empty());
- BOOST_CHECK(testArgs.IsArgSet("-a") && testArgs.IsArgSet("-b") && testArgs.IsArgSet("-ccc")
- && !testArgs.IsArgSet("f") && !testArgs.IsArgSet("-d"));
- BOOST_CHECK(testArgs.m_settings.command_line_options.count("a") && testArgs.m_settings.command_line_options.count("b") && testArgs.m_settings.command_line_options.count("ccc")
- && !testArgs.m_settings.command_line_options.count("f") && !testArgs.m_settings.command_line_options.count("d"));
-
- BOOST_CHECK(testArgs.m_settings.command_line_options["a"].size() == 1);
- BOOST_CHECK(testArgs.m_settings.command_line_options["a"].front().get_str() == "");
- BOOST_CHECK(testArgs.m_settings.command_line_options["ccc"].size() == 2);
- BOOST_CHECK(testArgs.m_settings.command_line_options["ccc"].front().get_str() == "argument");
- BOOST_CHECK(testArgs.m_settings.command_line_options["ccc"].back().get_str() == "multiple");
- BOOST_CHECK(testArgs.GetArgs("-ccc").size() == 2);
-}
-
-BOOST_AUTO_TEST_CASE(util_ParseInvalidParameters)
-{
- TestArgsManager test;
- test.SetupArgs({{"-registered", ArgsManager::ALLOW_ANY}});
-
- const char* argv[] = {"ignored", "-registered"};
- std::string error;
- BOOST_CHECK(test.ParseParameters(2, (char**)argv, error));
- BOOST_CHECK_EQUAL(error, "");
-
- argv[1] = "-unregistered";
- BOOST_CHECK(!test.ParseParameters(2, (char**)argv, error));
- BOOST_CHECK_EQUAL(error, "Invalid parameter -unregistered");
-
- // Make sure registered parameters prefixed with a chain name trigger errors.
- // (Previously, they were accepted and ignored.)
- argv[1] = "-test.registered";
- BOOST_CHECK(!test.ParseParameters(2, (char**)argv, error));
- BOOST_CHECK_EQUAL(error, "Invalid parameter -test.registered");
-}
-
-static void TestParse(const std::string& str, bool expected_bool, int64_t expected_int)
-{
- TestArgsManager test;
- test.SetupArgs({{"-value", ArgsManager::ALLOW_ANY}});
- std::string arg = "-value=" + str;
- const char* argv[] = {"ignored", arg.c_str()};
- std::string error;
- BOOST_CHECK(test.ParseParameters(2, (char**)argv, error));
- BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), expected_bool);
- BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), expected_bool);
- BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99998), expected_int);
- BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), expected_int);
-}
-
-// Test bool and int parsing.
-BOOST_AUTO_TEST_CASE(util_ArgParsing)
-{
- // Some of these cases could be ambiguous or surprising to users, and might
- // be worth triggering errors or warnings in the future. But for now basic
- // test coverage is useful to avoid breaking backwards compatibility
- // unintentionally.
- TestParse("", true, 0);
- TestParse(" ", false, 0);
- TestParse("0", false, 0);
- TestParse("0 ", false, 0);
- TestParse(" 0", false, 0);
- TestParse("+0", false, 0);
- TestParse("-0", false, 0);
- TestParse("5", true, 5);
- TestParse("5 ", true, 5);
- TestParse(" 5", true, 5);
- TestParse("+5", true, 5);
- TestParse("-5", true, -5);
- TestParse("0 5", false, 0);
- TestParse("5 0", true, 5);
- TestParse("050", true, 50);
- TestParse("0.", false, 0);
- TestParse("5.", true, 5);
- TestParse("0.0", false, 0);
- TestParse("0.5", false, 0);
- TestParse("5.0", true, 5);
- TestParse("5.5", true, 5);
- TestParse("x", false, 0);
- TestParse("x0", false, 0);
- TestParse("x5", false, 0);
- TestParse("0x", false, 0);
- TestParse("5x", true, 5);
- TestParse("0x5", false, 0);
- TestParse("false", false, 0);
- TestParse("true", false, 0);
- TestParse("yes", false, 0);
- TestParse("no", false, 0);
-}
-
-BOOST_AUTO_TEST_CASE(util_GetBoolArg)
-{
- TestArgsManager testArgs;
- const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
- const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
- const auto c = std::make_pair("-c", ArgsManager::ALLOW_ANY);
- const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
- const auto e = std::make_pair("-e", ArgsManager::ALLOW_ANY);
- const auto f = std::make_pair("-f", ArgsManager::ALLOW_ANY);
-
- const char *argv_test[] = {
- "ignored", "-a", "-nob", "-c=0", "-d=1", "-e=false", "-f=true"};
- std::string error;
- LOCK(testArgs.cs_args);
- testArgs.SetupArgs({a, b, c, d, e, f});
- BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error));
-
- // Each letter should be set.
- for (const char opt : "abcdef")
- BOOST_CHECK(testArgs.IsArgSet({'-', opt}) || !opt);
-
- // Nothing else should be in the map
- BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 6 &&
- testArgs.m_settings.ro_config.empty());
-
- // The -no prefix should get stripped on the way in.
- BOOST_CHECK(!testArgs.IsArgSet("-nob"));
-
- // The -b option is flagged as negated, and nothing else is
- BOOST_CHECK(testArgs.IsArgNegated("-b"));
- BOOST_CHECK(!testArgs.IsArgNegated("-a"));
-
- // Check expected values.
- BOOST_CHECK(testArgs.GetBoolArg("-a", false) == true);
- BOOST_CHECK(testArgs.GetBoolArg("-b", true) == false);
- BOOST_CHECK(testArgs.GetBoolArg("-c", true) == false);
- BOOST_CHECK(testArgs.GetBoolArg("-d", false) == true);
- BOOST_CHECK(testArgs.GetBoolArg("-e", true) == false);
- BOOST_CHECK(testArgs.GetBoolArg("-f", true) == false);
-}
-
-BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
-{
- // Test some awful edge cases that hopefully no user will ever exercise.
- TestArgsManager testArgs;
-
- // Params test
- const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY);
- const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
- const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"};
- testArgs.SetupArgs({foo, bar});
- std::string error;
- BOOST_CHECK(testArgs.ParseParameters(4, (char**)argv_test, error));
-
- // This was passed twice, second one overrides the negative setting.
- BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
- BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "");
-
- // A double negative is a positive, and not marked as negated.
- BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
- BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
-
- // Config test
- const char *conf_test = "nofoo=1\nfoo=1\nnobar=0\n";
- BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error));
- testArgs.ReadConfigString(conf_test);
-
- // This was passed twice, second one overrides the negative setting,
- // and the value.
- BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
- BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "1");
-
- // A double negative is a positive, and does not count as negated.
- BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
- BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
-
- // Combined test
- const char *combo_test_args[] = {"ignored", "-nofoo", "-bar"};
- const char *combo_test_conf = "foo=1\nnobar=1\n";
- BOOST_CHECK(testArgs.ParseParameters(3, (char**)combo_test_args, error));
- testArgs.ReadConfigString(combo_test_conf);
-
- // Command line overrides, but doesn't erase old setting
- BOOST_CHECK(testArgs.IsArgNegated("-foo"));
- BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
- BOOST_CHECK(testArgs.GetArgs("-foo").size() == 0);
-
- // Command line overrides, but doesn't erase old setting
- BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
- BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "");
- BOOST_CHECK(testArgs.GetArgs("-bar").size() == 1
- && testArgs.GetArgs("-bar").front() == "");
-}
-
-BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
-{
- const char *str_config =
- "a=\n"
- "b=1\n"
- "ccc=argument\n"
- "ccc=multiple\n"
- "d=e\n"
- "nofff=1\n"
- "noggg=0\n"
- "h=1\n"
- "noh=1\n"
- "noi=1\n"
- "i=1\n"
- "sec1.ccc=extend1\n"
- "\n"
- "[sec1]\n"
- "ccc=extend2\n"
- "d=eee\n"
- "h=1\n"
- "[sec2]\n"
- "ccc=extend3\n"
- "iii=2\n";
-
- TestArgsManager test_args;
- LOCK(test_args.cs_args);
- const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
- const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
- const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY);
- const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
- const auto e = std::make_pair("-e", ArgsManager::ALLOW_ANY);
- const auto fff = std::make_pair("-fff", ArgsManager::ALLOW_ANY);
- const auto ggg = std::make_pair("-ggg", ArgsManager::ALLOW_ANY);
- const auto h = std::make_pair("-h", ArgsManager::ALLOW_ANY);
- const auto i = std::make_pair("-i", ArgsManager::ALLOW_ANY);
- const auto iii = std::make_pair("-iii", ArgsManager::ALLOW_ANY);
- test_args.SetupArgs({a, b, ccc, d, e, fff, ggg, h, i, iii});
-
- test_args.ReadConfigString(str_config);
- // expectation: a, b, ccc, d, fff, ggg, h, i end up in map
- // so do sec1.ccc, sec1.d, sec1.h, sec2.ccc, sec2.iii
-
- BOOST_CHECK(test_args.m_settings.command_line_options.empty());
- BOOST_CHECK(test_args.m_settings.ro_config.size() == 3);
- BOOST_CHECK(test_args.m_settings.ro_config[""].size() == 8);
- BOOST_CHECK(test_args.m_settings.ro_config["sec1"].size() == 3);
- BOOST_CHECK(test_args.m_settings.ro_config["sec2"].size() == 2);
-
- BOOST_CHECK(test_args.m_settings.ro_config[""].count("a"));
- BOOST_CHECK(test_args.m_settings.ro_config[""].count("b"));
- BOOST_CHECK(test_args.m_settings.ro_config[""].count("ccc"));
- BOOST_CHECK(test_args.m_settings.ro_config[""].count("d"));
- BOOST_CHECK(test_args.m_settings.ro_config[""].count("fff"));
- BOOST_CHECK(test_args.m_settings.ro_config[""].count("ggg"));
- BOOST_CHECK(test_args.m_settings.ro_config[""].count("h"));
- BOOST_CHECK(test_args.m_settings.ro_config[""].count("i"));
- BOOST_CHECK(test_args.m_settings.ro_config["sec1"].count("ccc"));
- BOOST_CHECK(test_args.m_settings.ro_config["sec1"].count("h"));
- BOOST_CHECK(test_args.m_settings.ro_config["sec2"].count("ccc"));
- BOOST_CHECK(test_args.m_settings.ro_config["sec2"].count("iii"));
-
- BOOST_CHECK(test_args.IsArgSet("-a"));
- BOOST_CHECK(test_args.IsArgSet("-b"));
- BOOST_CHECK(test_args.IsArgSet("-ccc"));
- BOOST_CHECK(test_args.IsArgSet("-d"));
- BOOST_CHECK(test_args.IsArgSet("-fff"));
- BOOST_CHECK(test_args.IsArgSet("-ggg"));
- BOOST_CHECK(test_args.IsArgSet("-h"));
- BOOST_CHECK(test_args.IsArgSet("-i"));
- BOOST_CHECK(!test_args.IsArgSet("-zzz"));
- BOOST_CHECK(!test_args.IsArgSet("-iii"));
-
- BOOST_CHECK_EQUAL(test_args.GetArg("-a", "xxx"), "");
- BOOST_CHECK_EQUAL(test_args.GetArg("-b", "xxx"), "1");
- BOOST_CHECK_EQUAL(test_args.GetArg("-ccc", "xxx"), "argument");
- BOOST_CHECK_EQUAL(test_args.GetArg("-d", "xxx"), "e");
- BOOST_CHECK_EQUAL(test_args.GetArg("-fff", "xxx"), "0");
- BOOST_CHECK_EQUAL(test_args.GetArg("-ggg", "xxx"), "1");
- BOOST_CHECK_EQUAL(test_args.GetArg("-h", "xxx"), "0");
- BOOST_CHECK_EQUAL(test_args.GetArg("-i", "xxx"), "1");
- BOOST_CHECK_EQUAL(test_args.GetArg("-zzz", "xxx"), "xxx");
- BOOST_CHECK_EQUAL(test_args.GetArg("-iii", "xxx"), "xxx");
-
- for (const bool def : {false, true}) {
- BOOST_CHECK(test_args.GetBoolArg("-a", def));
- BOOST_CHECK(test_args.GetBoolArg("-b", def));
- BOOST_CHECK(!test_args.GetBoolArg("-ccc", def));
- BOOST_CHECK(!test_args.GetBoolArg("-d", def));
- BOOST_CHECK(!test_args.GetBoolArg("-fff", def));
- BOOST_CHECK(test_args.GetBoolArg("-ggg", def));
- BOOST_CHECK(!test_args.GetBoolArg("-h", def));
- BOOST_CHECK(test_args.GetBoolArg("-i", def));
- BOOST_CHECK(test_args.GetBoolArg("-zzz", def) == def);
- BOOST_CHECK(test_args.GetBoolArg("-iii", def) == def);
- }
-
- BOOST_CHECK(test_args.GetArgs("-a").size() == 1
- && test_args.GetArgs("-a").front() == "");
- BOOST_CHECK(test_args.GetArgs("-b").size() == 1
- && test_args.GetArgs("-b").front() == "1");
- BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2
- && test_args.GetArgs("-ccc").front() == "argument"
- && test_args.GetArgs("-ccc").back() == "multiple");
- BOOST_CHECK(test_args.GetArgs("-fff").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-nofff").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-ggg").size() == 1
- && test_args.GetArgs("-ggg").front() == "1");
- BOOST_CHECK(test_args.GetArgs("-noggg").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-h").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-noh").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-i").size() == 1
- && test_args.GetArgs("-i").front() == "1");
- BOOST_CHECK(test_args.GetArgs("-noi").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-zzz").size() == 0);
-
- BOOST_CHECK(!test_args.IsArgNegated("-a"));
- BOOST_CHECK(!test_args.IsArgNegated("-b"));
- BOOST_CHECK(!test_args.IsArgNegated("-ccc"));
- BOOST_CHECK(!test_args.IsArgNegated("-d"));
- BOOST_CHECK(test_args.IsArgNegated("-fff"));
- BOOST_CHECK(!test_args.IsArgNegated("-ggg"));
- BOOST_CHECK(test_args.IsArgNegated("-h")); // last setting takes precedence
- BOOST_CHECK(!test_args.IsArgNegated("-i")); // last setting takes precedence
- BOOST_CHECK(!test_args.IsArgNegated("-zzz"));
-
- // Test sections work
- test_args.SelectConfigNetwork("sec1");
-
- // same as original
- BOOST_CHECK_EQUAL(test_args.GetArg("-a", "xxx"), "");
- BOOST_CHECK_EQUAL(test_args.GetArg("-b", "xxx"), "1");
- BOOST_CHECK_EQUAL(test_args.GetArg("-fff", "xxx"), "0");
- BOOST_CHECK_EQUAL(test_args.GetArg("-ggg", "xxx"), "1");
- BOOST_CHECK_EQUAL(test_args.GetArg("-zzz", "xxx"), "xxx");
- BOOST_CHECK_EQUAL(test_args.GetArg("-iii", "xxx"), "xxx");
- // d is overridden
- BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
- // section-specific setting
- BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
- // section takes priority for multiple values
- BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend1");
- // check multiple values works
- const std::vector<std::string> sec1_ccc_expected = {"extend1","extend2","argument","multiple"};
- const auto& sec1_ccc_res = test_args.GetArgs("-ccc");
- BOOST_CHECK_EQUAL_COLLECTIONS(sec1_ccc_res.begin(), sec1_ccc_res.end(), sec1_ccc_expected.begin(), sec1_ccc_expected.end());
-
- test_args.SelectConfigNetwork("sec2");
-
- // same as original
- BOOST_CHECK(test_args.GetArg("-a", "xxx") == "");
- BOOST_CHECK(test_args.GetArg("-b", "xxx") == "1");
- BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
- BOOST_CHECK(test_args.GetArg("-fff", "xxx") == "0");
- BOOST_CHECK(test_args.GetArg("-ggg", "xxx") == "1");
- BOOST_CHECK(test_args.GetArg("-zzz", "xxx") == "xxx");
- BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
- // section-specific setting
- BOOST_CHECK(test_args.GetArg("-iii", "xxx") == "2");
- // section takes priority for multiple values
- BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend3");
- // check multiple values works
- const std::vector<std::string> sec2_ccc_expected = {"extend3","argument","multiple"};
- const auto& sec2_ccc_res = test_args.GetArgs("-ccc");
- BOOST_CHECK_EQUAL_COLLECTIONS(sec2_ccc_res.begin(), sec2_ccc_res.end(), sec2_ccc_expected.begin(), sec2_ccc_expected.end());
-
- // Test section only options
-
- test_args.SetNetworkOnlyArg("-d");
- test_args.SetNetworkOnlyArg("-ccc");
- test_args.SetNetworkOnlyArg("-h");
-
- test_args.SelectConfigNetwork(CBaseChainParams::MAIN);
- BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
- BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
- BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
-
- test_args.SelectConfigNetwork("sec1");
- BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
- BOOST_CHECK(test_args.GetArgs("-d").size() == 1);
- BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
- BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
-
- test_args.SelectConfigNetwork("sec2");
- BOOST_CHECK(test_args.GetArg("-d", "xxx") == "xxx");
- BOOST_CHECK(test_args.GetArgs("-d").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-ccc").size() == 1);
- BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
-}
-
-BOOST_AUTO_TEST_CASE(util_GetArg)
-{
- TestArgsManager testArgs;
- LOCK(testArgs.cs_args);
- testArgs.m_settings.command_line_options.clear();
- testArgs.m_settings.command_line_options["strtest1"] = {"string..."};
- // strtest2 undefined on purpose
- testArgs.m_settings.command_line_options["inttest1"] = {"12345"};
- testArgs.m_settings.command_line_options["inttest2"] = {"81985529216486895"};
- // inttest3 undefined on purpose
- testArgs.m_settings.command_line_options["booltest1"] = {""};
- // booltest2 undefined on purpose
- testArgs.m_settings.command_line_options["booltest3"] = {"0"};
- testArgs.m_settings.command_line_options["booltest4"] = {"1"};
-
- // priorities
- testArgs.m_settings.command_line_options["pritest1"] = {"a", "b"};
- testArgs.m_settings.ro_config[""]["pritest2"] = {"a", "b"};
- testArgs.m_settings.command_line_options["pritest3"] = {"a"};
- testArgs.m_settings.ro_config[""]["pritest3"] = {"b"};
- testArgs.m_settings.command_line_options["pritest4"] = {"a","b"};
- testArgs.m_settings.ro_config[""]["pritest4"] = {"c","d"};
-
- BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string...");
- BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
- BOOST_CHECK_EQUAL(testArgs.GetIntArg("inttest1", -1), 12345);
- BOOST_CHECK_EQUAL(testArgs.GetIntArg("inttest2", -1), 81985529216486895LL);
- BOOST_CHECK_EQUAL(testArgs.GetIntArg("inttest3", -1), -1);
- BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), true);
- BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest2", false), false);
- BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest3", false), false);
- BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest4", false), true);
-
- BOOST_CHECK_EQUAL(testArgs.GetArg("pritest1", "default"), "b");
- BOOST_CHECK_EQUAL(testArgs.GetArg("pritest2", "default"), "a");
- BOOST_CHECK_EQUAL(testArgs.GetArg("pritest3", "default"), "a");
- BOOST_CHECK_EQUAL(testArgs.GetArg("pritest4", "default"), "b");
-}
-
-BOOST_AUTO_TEST_CASE(util_GetChainName)
-{
- TestArgsManager test_args;
- const auto testnet = std::make_pair("-testnet", ArgsManager::ALLOW_ANY);
- const auto regtest = std::make_pair("-regtest", ArgsManager::ALLOW_ANY);
- test_args.SetupArgs({testnet, regtest});
-
- const char* argv_testnet[] = {"cmd", "-testnet"};
- const char* argv_regtest[] = {"cmd", "-regtest"};
- const char* argv_test_no_reg[] = {"cmd", "-testnet", "-noregtest"};
- const char* argv_both[] = {"cmd", "-testnet", "-regtest"};
-
- // equivalent to "-testnet"
- // regtest in testnet section is ignored
- const char* testnetconf = "testnet=1\nregtest=0\n[test]\nregtest=1";
- std::string error;
-
- BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "main");
-
- BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
-
- BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest");
-
- BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
-
- BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
-
- BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
-
- BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
-
- BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
-
- BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
-
- BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
-
- // check setting the network to test (and thus making
- // [test] regtest=1 potentially relevant) doesn't break things
- test_args.SelectConfigNetwork("test");
-
- BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
-
- BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
-
- BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
-
- BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_test_no_reg, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
-
- BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
- test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
-}
-
-// Test different ways settings can be merged, and verify results. This test can
-// be used to confirm that updates to settings code don't change behavior
-// unintentionally.
-//
-// The test covers:
-//
-// - Combining different setting actions. Possible actions are: configuring a
-// setting, negating a setting (adding "-no" prefix), and configuring/negating
-// settings in a network section (adding "main." or "test." prefixes).
-//
-// - Combining settings from command line arguments and a config file.
-//
-// - Combining SoftSet and ForceSet calls.
-//
-// - Testing "main" and "test" network values to make sure settings from network
-// sections are applied and to check for mainnet-specific behaviors like
-// inheriting settings from the default section.
-//
-// - Testing network-specific settings like "-wallet", that may be ignored
-// outside a network section, and non-network specific settings like "-server"
-// that aren't sensitive to the network.
-//
-struct ArgsMergeTestingSetup : public BasicTestingSetup {
- //! Max number of actions to sequence together. Can decrease this when
- //! debugging to make test results easier to understand.
- static constexpr int MAX_ACTIONS = 3;
-
- enum Action { NONE, SET, NEGATE, SECTION_SET, SECTION_NEGATE };
- using ActionList = Action[MAX_ACTIONS];
-
- //! Enumerate all possible test configurations.
- template <typename Fn>
- void ForEachMergeSetup(Fn&& fn)
- {
- ActionList arg_actions = {};
- // command_line_options do not have sections. Only iterate over SET and NEGATE
- ForEachNoDup(arg_actions, SET, NEGATE, [&] {
- ActionList conf_actions = {};
- ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] {
- for (bool soft_set : {false, true}) {
- for (bool force_set : {false, true}) {
- for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
- for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
- for (bool net_specific : {false, true}) {
- fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
- }
- }
- }
- }
- }
- });
- });
- }
-
- //! Translate actions into a list of <key>=<value> setting strings.
- std::vector<std::string> GetValues(const ActionList& actions,
- const std::string& section,
- const std::string& name,
- const std::string& value_prefix)
- {
- std::vector<std::string> values;
- int suffix = 0;
- for (Action action : actions) {
- if (action == NONE) break;
- std::string prefix;
- if (action == SECTION_SET || action == SECTION_NEGATE) prefix = section + ".";
- if (action == SET || action == SECTION_SET) {
- for (int i = 0; i < 2; ++i) {
- values.push_back(prefix + name + "=" + value_prefix + ToString(++suffix));
- }
- }
- if (action == NEGATE || action == SECTION_NEGATE) {
- values.push_back(prefix + "no" + name + "=1");
- }
- }
- return values;
- }
-};
-
-// Regression test covering different ways config settings can be merged. The
-// test parses and merges settings, representing the results as strings that get
-// compared against an expected hash. To debug, the result strings can be dumped
-// to a file (see comments below).
-BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
-{
- CHash256 out_sha;
- FILE* out_file = nullptr;
- if (const char* out_path = getenv("ARGS_MERGE_TEST_OUT")) {
- out_file = fsbridge::fopen(out_path, "w");
- if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed");
- }
-
- ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions, bool soft_set, bool force_set,
- const std::string& section, const std::string& network, bool net_specific) {
- TestArgsManager parser;
- LOCK(parser.cs_args);
-
- std::string desc = "net=";
- desc += network;
- parser.m_network = network;
-
- const std::string& name = net_specific ? "wallet" : "server";
- const std::string key = "-" + name;
- parser.AddArg(key, name, ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- if (net_specific) parser.SetNetworkOnlyArg(key);
-
- auto args = GetValues(arg_actions, section, name, "a");
- std::vector<const char*> argv = {"ignored"};
- for (auto& arg : args) {
- arg.insert(0, "-");
- desc += " ";
- desc += arg;
- argv.push_back(arg.c_str());
- }
- std::string error;
- BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
- BOOST_CHECK_EQUAL(error, "");
-
- std::string conf;
- for (auto& conf_val : GetValues(conf_actions, section, name, "c")) {
- desc += " ";
- desc += conf_val;
- conf += conf_val;
- conf += "\n";
- }
- std::istringstream conf_stream(conf);
- BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
- BOOST_CHECK_EQUAL(error, "");
-
- if (soft_set) {
- desc += " soft";
- parser.SoftSetArg(key, "soft1");
- parser.SoftSetArg(key, "soft2");
- }
-
- if (force_set) {
- desc += " force";
- parser.ForceSetArg(key, "force1");
- parser.ForceSetArg(key, "force2");
- }
-
- desc += " || ";
-
- if (!parser.IsArgSet(key)) {
- desc += "unset";
- BOOST_CHECK(!parser.IsArgNegated(key));
- BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "default");
- BOOST_CHECK(parser.GetArgs(key).empty());
- } else if (parser.IsArgNegated(key)) {
- desc += "negated";
- BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "0");
- BOOST_CHECK(parser.GetArgs(key).empty());
- } else {
- desc += parser.GetArg(key, "default");
- desc += " |";
- for (const auto& arg : parser.GetArgs(key)) {
- desc += " ";
- desc += arg;
- }
- }
-
- std::set<std::string> ignored = parser.GetUnsuitableSectionOnlyArgs();
- if (!ignored.empty()) {
- desc += " | ignored";
- for (const auto& arg : ignored) {
- desc += " ";
- desc += arg;
- }
- }
-
- desc += "\n";
-
- out_sha.Write(MakeUCharSpan(desc));
- if (out_file) {
- BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
- }
- });
-
- if (out_file) {
- if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed");
- out_file = nullptr;
- }
-
- unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE];
- out_sha.Finalize(out_sha_bytes);
- std::string out_sha_hex = HexStr(out_sha_bytes);
-
- // If check below fails, should manually dump the results with:
- //
- // ARGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ArgsMerge
- //
- // And verify diff against previous results to make sure the changes are expected.
- //
- // Results file is formatted like:
- //
- // <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output>
- BOOST_CHECK_EQUAL(out_sha_hex, "d1e436c1cd510d0ec44d5205d4b4e3bee6387d316e0075c58206cb16603f3d82");
-}
-
-// Similar test as above, but for ArgsManager::GetChainName function.
-struct ChainMergeTestingSetup : public BasicTestingSetup {
- static constexpr int MAX_ACTIONS = 2;
-
- enum Action { NONE, ENABLE_TEST, DISABLE_TEST, NEGATE_TEST, ENABLE_REG, DISABLE_REG, NEGATE_REG };
- using ActionList = Action[MAX_ACTIONS];
-
- //! Enumerate all possible test configurations.
- template <typename Fn>
- void ForEachMergeSetup(Fn&& fn)
- {
- ActionList arg_actions = {};
- ForEachNoDup(arg_actions, ENABLE_TEST, NEGATE_REG, [&] {
- ActionList conf_actions = {};
- ForEachNoDup(conf_actions, ENABLE_TEST, NEGATE_REG, [&] { fn(arg_actions, conf_actions); });
- });
- }
-};
-
-BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
-{
- CHash256 out_sha;
- FILE* out_file = nullptr;
- if (const char* out_path = getenv("CHAIN_MERGE_TEST_OUT")) {
- out_file = fsbridge::fopen(out_path, "w");
- if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed");
- }
-
- ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions) {
- TestArgsManager parser;
- LOCK(parser.cs_args);
- parser.AddArg("-regtest", "regtest", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- parser.AddArg("-testnet", "testnet", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
-
- auto arg = [](Action action) { return action == ENABLE_TEST ? "-testnet=1" :
- action == DISABLE_TEST ? "-testnet=0" :
- action == NEGATE_TEST ? "-notestnet=1" :
- action == ENABLE_REG ? "-regtest=1" :
- action == DISABLE_REG ? "-regtest=0" :
- action == NEGATE_REG ? "-noregtest=1" : nullptr; };
-
- std::string desc;
- std::vector<const char*> argv = {"ignored"};
- for (Action action : arg_actions) {
- const char* argstr = arg(action);
- if (!argstr) break;
- argv.push_back(argstr);
- desc += " ";
- desc += argv.back();
- }
- std::string error;
- BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
- BOOST_CHECK_EQUAL(error, "");
-
- std::string conf;
- for (Action action : conf_actions) {
- const char* argstr = arg(action);
- if (!argstr) break;
- desc += " ";
- desc += argstr + 1;
- conf += argstr + 1;
- conf += "\n";
- }
- std::istringstream conf_stream(conf);
- BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
- BOOST_CHECK_EQUAL(error, "");
-
- desc += " || ";
- try {
- desc += parser.GetChainName();
- } catch (const std::runtime_error& e) {
- desc += "error: ";
- desc += e.what();
- }
- desc += "\n";
-
- out_sha.Write(MakeUCharSpan(desc));
- if (out_file) {
- BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
- }
- });
-
- if (out_file) {
- if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed");
- out_file = nullptr;
- }
-
- unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE];
- out_sha.Finalize(out_sha_bytes);
- std::string out_sha_hex = HexStr(out_sha_bytes);
-
- // If check below fails, should manually dump the results with:
- //
- // CHAIN_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ChainMerge
- //
- // And verify diff against previous results to make sure the changes are expected.
- //
- // Results file is formatted like:
- //
- // <input> || <output>
- BOOST_CHECK_EQUAL(out_sha_hex, "f263493e300023b6509963887444c41386f44b63bc30047eb8402e8c1144854c");
-}
-
-BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
-{
- // Test writing setting.
- TestArgsManager args1;
- args1.ForceSetArg("-datadir", fs::PathToString(m_path_root));
- args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; });
- args1.WriteSettingsFile();
-
- // Test reading setting.
- TestArgsManager args2;
- args2.ForceSetArg("-datadir", fs::PathToString(m_path_root));
- args2.ReadSettingsFile();
- args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
-
- // Test error logging, and remove previously written setting.
- {
- ASSERT_DEBUG_LOG("Failed renaming settings file");
- fs::remove(args1.GetDataDirBase() / "settings.json");
- fs::create_directory(args1.GetDataDirBase() / "settings.json");
- args2.WriteSettingsFile();
- fs::remove(args1.GetDataDirBase() / "settings.json");
- }
-}
-
BOOST_AUTO_TEST_CASE(util_FormatMoney)
{
BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");
@@ -1825,8 +837,8 @@ BOOST_AUTO_TEST_CASE(test_ParseInt64)
BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal
BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL);
BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL);
- BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == (int64_t)9223372036854775807);
- BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == (int64_t)-9223372036854775807-1);
+ BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == int64_t{9223372036854775807});
+ BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == int64_t{-9223372036854775807-1});
BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL);
// Invalid values
BOOST_CHECK(!ParseInt64("", &n));
@@ -1922,8 +934,8 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt32)
BOOST_CHECK(ParseUInt32("1234", &n) && n == 1234);
BOOST_CHECK(ParseUInt32("01234", &n) && n == 1234); // no octal
BOOST_CHECK(ParseUInt32("2147483647", &n) && n == 2147483647);
- BOOST_CHECK(ParseUInt32("2147483648", &n) && n == (uint32_t)2147483648);
- BOOST_CHECK(ParseUInt32("4294967295", &n) && n == (uint32_t)4294967295);
+ BOOST_CHECK(ParseUInt32("2147483648", &n) && n == uint32_t{2147483648});
+ BOOST_CHECK(ParseUInt32("4294967295", &n) && n == uint32_t{4294967295});
BOOST_CHECK(ParseUInt32("+1234", &n) && n == 1234);
BOOST_CHECK(ParseUInt32("00000000000000001234", &n) && n == 1234);
BOOST_CHECK(ParseUInt32("00000000000000000000", &n) && n == 0);
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index bb1ade153a..4c8687ce69 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@
#include <pow.h>
#include <random.h>
#include <script/standard.h>
+#include <test/util/random.h>
#include <test/util/script.h>
#include <test/util/setup_common.h>
#include <util/time.h>
diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp
index 347a967b33..2078fcd8f8 100644
--- a/src/test/validation_chainstate_tests.cpp
+++ b/src/test/validation_chainstate_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
@@ -8,6 +8,8 @@
#include <rpc/blockchain.h>
#include <sync.h>
#include <test/util/chainstate.h>
+#include <test/util/coins.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <uint256.h>
#include <validation.h>
@@ -24,20 +26,6 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches)
{
ChainstateManager& manager = *Assert(m_node.chainman);
CTxMemPool& mempool = *Assert(m_node.mempool);
-
- //! Create and add a Coin with DynamicMemoryUsage of 80 bytes to the given view.
- auto add_coin = [](CCoinsViewCache& coins_view) -> COutPoint {
- Coin newcoin;
- uint256 txid = InsecureRand256();
- COutPoint outp{txid, 0};
- newcoin.nHeight = 1;
- newcoin.out.nValue = InsecureRand32();
- newcoin.out.scriptPubKey.assign((uint32_t)56, 1);
- coins_view.AddCoin(outp, std::move(newcoin), false);
-
- return outp;
- };
-
Chainstate& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool));
c1.InitCoinsDB(
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
@@ -47,7 +35,7 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches)
// Add a coin to the in-memory cache, upsize once, then downsize.
{
LOCK(::cs_main);
- auto outpoint = add_coin(c1.CoinsTip());
+ const auto outpoint = AddTestCoin(c1.CoinsTip());
// Set a meaningless bestblock value in the coinsview cache - otherwise we won't
// flush during ResizecoinsCaches() and will subsequently hit an assertion.
@@ -89,7 +77,8 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
// After adding some blocks to the tip, best block should have changed.
BOOST_CHECK(::g_best_block != curr_tip);
- BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
+ BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(
+ this, NoMalleation, /*reset_chainstate=*/ true));
// Ensure our active chain is the snapshot chainstate.
BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.IsSnapshotActive()));
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 9fcb7d315a..688aafdd46 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
@@ -9,7 +9,9 @@
#include <rpc/blockchain.h>
#include <sync.h>
#include <test/util/chainstate.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
+#include <timedata.h>
#include <uint256.h>
#include <validation.h>
#include <validationinterface.h>
@@ -63,7 +65,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
// Create a snapshot-based chainstate.
//
const uint256 snapshot_blockhash = GetRandHash();
- Chainstate& c2 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(
+ Chainstate& c2 = WITH_LOCK(::cs_main, return manager.ActivateExistingSnapshot(
&mempool, snapshot_blockhash));
chainstates.push_back(&c2);
@@ -115,7 +117,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
// Create a legacy (IBD) chainstate.
//
- Chainstate& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool));
+ Chainstate& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(&mempool));
chainstates.push_back(&c1);
c1.InitCoinsDB(
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
@@ -133,7 +135,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
// Create a snapshot-based chainstate.
//
- Chainstate& c2 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool, GetRandHash()));
+ Chainstate& c2 = WITH_LOCK(cs_main, return manager.ActivateExistingSnapshot(&mempool, GetRandHash()));
chainstates.push_back(&c2);
c2.InitCoinsDB(
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
@@ -154,162 +156,241 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
BOOST_CHECK_CLOSE(c2.m_coinsdb_cache_size_bytes, max_cache * 0.95, 1);
}
-//! Test basic snapshot activation.
-BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
-{
- ChainstateManager& chainman = *Assert(m_node.chainman);
-
- size_t initial_size;
- size_t initial_total_coins{100};
-
- // Make some initial assertions about the contents of the chainstate.
+struct SnapshotTestSetup : TestChain100Setup {
+ // Run with coinsdb on the filesystem to support, e.g., moving invalidated
+ // chainstate dirs to "*_invalid".
+ //
+ // Note that this means the tests run considerably slower than in-memory DB
+ // tests, but we can't otherwise test this functionality since it relies on
+ // destructive filesystem operations.
+ SnapshotTestSetup() : TestChain100Setup{
+ {},
+ {},
+ /*coins_db_in_memory=*/false,
+ /*block_tree_db_in_memory=*/false,
+ }
{
- LOCK(::cs_main);
- CCoinsViewCache& ibd_coinscache = chainman.ActiveChainstate().CoinsTip();
- initial_size = ibd_coinscache.GetCacheSize();
- size_t total_coins{0};
-
- for (CTransactionRef& txn : m_coinbase_txns) {
- COutPoint op{txn->GetHash(), 0};
- BOOST_CHECK(ibd_coinscache.HaveCoin(op));
- total_coins++;
- }
-
- BOOST_CHECK_EQUAL(total_coins, initial_total_coins);
- BOOST_CHECK_EQUAL(initial_size, initial_total_coins);
}
- // Snapshot should refuse to load at this height.
- BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
- BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash);
- BOOST_CHECK(!chainman.SnapshotBlockhash());
-
- // Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can
- // be found.
- constexpr int snapshot_height = 110;
- mineBlocks(10);
- initial_size += 10;
- initial_total_coins += 10;
-
- // Should not load malleated snapshots
- BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
- // A UTXO is missing but count is correct
- metadata.m_coins_count -= 1;
-
- COutPoint outpoint;
- Coin coin;
-
- auto_infile >> outpoint;
- auto_infile >> coin;
- }));
- BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
- // Coins count is larger than coins in file
- metadata.m_coins_count += 1;
- }));
- BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
- // Coins count is smaller than coins in file
- metadata.m_coins_count -= 1;
- }));
- BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
- // Wrong hash
- metadata.m_base_blockhash = uint256::ZERO;
- }));
- BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
- // Wrong hash
- metadata.m_base_blockhash = uint256::ONE;
- }));
-
- BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
-
- // Ensure our active chain is the snapshot chainstate.
- BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
- BOOST_CHECK_EQUAL(
- *chainman.ActiveChainstate().m_from_snapshot_blockhash,
- *chainman.SnapshotBlockhash());
-
- // Ensure that the genesis block was not marked assumed-valid.
- BOOST_CHECK(WITH_LOCK(::cs_main, return !chainman.ActiveChain().Genesis()->IsAssumedValid()));
-
- const AssumeutxoData& au_data = *ExpectedAssumeutxo(snapshot_height, ::Params());
- const CBlockIndex* tip = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip());
-
- BOOST_CHECK_EQUAL(tip->nChainTx, au_data.nChainTx);
-
- // To be checked against later when we try loading a subsequent snapshot.
- uint256 loaded_snapshot_blockhash{*chainman.SnapshotBlockhash()};
-
- // Make some assertions about the both chainstates. These checks ensure the
- // legacy chainstate hasn't changed and that the newly created chainstate
- // reflects the expected content.
+ std::tuple<Chainstate*, Chainstate*> SetupSnapshot()
{
- LOCK(::cs_main);
- int chains_tested{0};
+ ChainstateManager& chainman = *Assert(m_node.chainman);
+
+ BOOST_CHECK(!chainman.IsSnapshotActive());
- for (Chainstate* chainstate : chainman.GetAll()) {
- BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
- CCoinsViewCache& coinscache = chainstate->CoinsTip();
+ {
+ LOCK(::cs_main);
+ BOOST_CHECK(!chainman.IsSnapshotValidated());
+ BOOST_CHECK(!node::FindSnapshotChainstateDir());
+ }
- // Both caches will be empty initially.
- BOOST_CHECK_EQUAL((unsigned int)0, coinscache.GetCacheSize());
+ size_t initial_size;
+ size_t initial_total_coins{100};
+ // Make some initial assertions about the contents of the chainstate.
+ {
+ LOCK(::cs_main);
+ CCoinsViewCache& ibd_coinscache = chainman.ActiveChainstate().CoinsTip();
+ initial_size = ibd_coinscache.GetCacheSize();
size_t total_coins{0};
for (CTransactionRef& txn : m_coinbase_txns) {
COutPoint op{txn->GetHash(), 0};
- BOOST_CHECK(coinscache.HaveCoin(op));
+ BOOST_CHECK(ibd_coinscache.HaveCoin(op));
total_coins++;
}
- BOOST_CHECK_EQUAL(initial_size , coinscache.GetCacheSize());
BOOST_CHECK_EQUAL(total_coins, initial_total_coins);
- chains_tested++;
+ BOOST_CHECK_EQUAL(initial_size, initial_total_coins);
}
- BOOST_CHECK_EQUAL(chains_tested, 2);
- }
+ Chainstate& validation_chainstate = chainman.ActiveChainstate();
+
+ // Snapshot should refuse to load at this height.
+ BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(this));
+ BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash);
+ BOOST_CHECK(!chainman.SnapshotBlockhash());
+
+ // Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can
+ // be found.
+ constexpr int snapshot_height = 110;
+ mineBlocks(10);
+ initial_size += 10;
+ initial_total_coins += 10;
+
+ // Should not load malleated snapshots
+ BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
+ this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
+ // A UTXO is missing but count is correct
+ metadata.m_coins_count -= 1;
+
+ COutPoint outpoint;
+ Coin coin;
+
+ auto_infile >> outpoint;
+ auto_infile >> coin;
+ }));
+
+ BOOST_CHECK(!node::FindSnapshotChainstateDir());
+
+ BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
+ this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
+ // Coins count is larger than coins in file
+ metadata.m_coins_count += 1;
+ }));
+ BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
+ this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
+ // Coins count is smaller than coins in file
+ metadata.m_coins_count -= 1;
+ }));
+ BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
+ this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
+ // Wrong hash
+ metadata.m_base_blockhash = uint256::ZERO;
+ }));
+ BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
+ this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
+ // Wrong hash
+ metadata.m_base_blockhash = uint256::ONE;
+ }));
+
+ BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(this));
+ BOOST_CHECK(fs::exists(*node::FindSnapshotChainstateDir()));
+
+ // Ensure our active chain is the snapshot chainstate.
+ BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
+ BOOST_CHECK_EQUAL(
+ *chainman.ActiveChainstate().m_from_snapshot_blockhash,
+ *chainman.SnapshotBlockhash());
+
+ Chainstate& snapshot_chainstate = chainman.ActiveChainstate();
+
+ {
+ LOCK(::cs_main);
- // Mine some new blocks on top of the activated snapshot chainstate.
- constexpr size_t new_coins{100};
- mineBlocks(new_coins); // Defined in TestChain100Setup.
+ fs::path found = *node::FindSnapshotChainstateDir();
- {
- LOCK(::cs_main);
- size_t coins_in_active{0};
- size_t coins_in_background{0};
- size_t coins_missing_from_background{0};
+ // Note: WriteSnapshotBaseBlockhash() is implicitly tested above.
+ BOOST_CHECK_EQUAL(
+ *node::ReadSnapshotBaseBlockhash(found),
+ *chainman.SnapshotBlockhash());
- for (Chainstate* chainstate : chainman.GetAll()) {
- BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
- CCoinsViewCache& coinscache = chainstate->CoinsTip();
- bool is_background = chainstate != &chainman.ActiveChainstate();
+ // Ensure that the genesis block was not marked assumed-valid.
+ BOOST_CHECK(!chainman.ActiveChain().Genesis()->IsAssumedValid());
+ }
- for (CTransactionRef& txn : m_coinbase_txns) {
- COutPoint op{txn->GetHash(), 0};
- if (coinscache.HaveCoin(op)) {
- (is_background ? coins_in_background : coins_in_active)++;
- } else if (is_background) {
- coins_missing_from_background++;
+ const AssumeutxoData& au_data = *ExpectedAssumeutxo(snapshot_height, ::Params());
+ const CBlockIndex* tip = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip());
+
+ BOOST_CHECK_EQUAL(tip->nChainTx, au_data.nChainTx);
+
+ // To be checked against later when we try loading a subsequent snapshot.
+ uint256 loaded_snapshot_blockhash{*chainman.SnapshotBlockhash()};
+
+ // Make some assertions about the both chainstates. These checks ensure the
+ // legacy chainstate hasn't changed and that the newly created chainstate
+ // reflects the expected content.
+ {
+ LOCK(::cs_main);
+ int chains_tested{0};
+
+ for (Chainstate* chainstate : chainman.GetAll()) {
+ BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
+ CCoinsViewCache& coinscache = chainstate->CoinsTip();
+
+ // Both caches will be empty initially.
+ BOOST_CHECK_EQUAL((unsigned int)0, coinscache.GetCacheSize());
+
+ size_t total_coins{0};
+
+ for (CTransactionRef& txn : m_coinbase_txns) {
+ COutPoint op{txn->GetHash(), 0};
+ BOOST_CHECK(coinscache.HaveCoin(op));
+ total_coins++;
+ }
+
+ BOOST_CHECK_EQUAL(initial_size , coinscache.GetCacheSize());
+ BOOST_CHECK_EQUAL(total_coins, initial_total_coins);
+ chains_tested++;
+ }
+
+ BOOST_CHECK_EQUAL(chains_tested, 2);
+ }
+
+ // Mine some new blocks on top of the activated snapshot chainstate.
+ constexpr size_t new_coins{100};
+ mineBlocks(new_coins); // Defined in TestChain100Setup.
+
+ {
+ LOCK(::cs_main);
+ size_t coins_in_active{0};
+ size_t coins_in_background{0};
+ size_t coins_missing_from_background{0};
+
+ for (Chainstate* chainstate : chainman.GetAll()) {
+ BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
+ CCoinsViewCache& coinscache = chainstate->CoinsTip();
+ bool is_background = chainstate != &chainman.ActiveChainstate();
+
+ for (CTransactionRef& txn : m_coinbase_txns) {
+ COutPoint op{txn->GetHash(), 0};
+ if (coinscache.HaveCoin(op)) {
+ (is_background ? coins_in_background : coins_in_active)++;
+ } else if (is_background) {
+ coins_missing_from_background++;
+ }
}
}
+
+ BOOST_CHECK_EQUAL(coins_in_active, initial_total_coins + new_coins);
+ BOOST_CHECK_EQUAL(coins_in_background, initial_total_coins);
+ BOOST_CHECK_EQUAL(coins_missing_from_background, new_coins);
}
- BOOST_CHECK_EQUAL(coins_in_active, initial_total_coins + new_coins);
- BOOST_CHECK_EQUAL(coins_in_background, initial_total_coins);
- BOOST_CHECK_EQUAL(coins_missing_from_background, new_coins);
+ // Snapshot should refuse to load after one has already loaded.
+ BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(this));
+
+ // Snapshot blockhash should be unchanged.
+ BOOST_CHECK_EQUAL(
+ *chainman.ActiveChainstate().m_from_snapshot_blockhash,
+ loaded_snapshot_blockhash);
+ return std::make_tuple(&validation_chainstate, &snapshot_chainstate);
}
- // Snapshot should refuse to load after one has already loaded.
- BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
+ // Simulate a restart of the node by flushing all state to disk, clearing the
+ // existing ChainstateManager, and unloading the block index.
+ //
+ // @returns a reference to the "restarted" ChainstateManager
+ ChainstateManager& SimulateNodeRestart()
+ {
+ ChainstateManager& chainman = *Assert(m_node.chainman);
- // Snapshot blockhash should be unchanged.
- BOOST_CHECK_EQUAL(
- *chainman.ActiveChainstate().m_from_snapshot_blockhash,
- loaded_snapshot_blockhash);
+ BOOST_TEST_MESSAGE("Simulating node restart");
+ {
+ LOCK(::cs_main);
+ for (Chainstate* cs : chainman.GetAll()) {
+ cs->ForceFlushStateToDisk();
+ }
+ chainman.ResetChainstates();
+ BOOST_CHECK_EQUAL(chainman.GetAll().size(), 0);
+ const ChainstateManager::Options chainman_opts{
+ .chainparams = ::Params(),
+ .datadir = m_args.GetDataDirNet(),
+ .adjusted_time_callback = GetAdjustedTime,
+ };
+ // For robustness, ensure the old manager is destroyed before creating a
+ // new one.
+ m_node.chainman.reset();
+ m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, node::BlockManager::Options{});
+ }
+ return *Assert(m_node.chainman);
+ }
+};
+
+//! Test basic snapshot activation.
+BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, SnapshotTestSetup)
+{
+ this->SetupSnapshot();
}
//! Test LoadBlockIndex behavior when multiple chainstates are in use.
@@ -374,7 +455,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
BOOST_CHECK_EQUAL(expected_assumed_valid, num_assumed_valid);
Chainstate& cs2 = WITH_LOCK(::cs_main,
- return chainman.InitializeChainstate(&mempool, GetRandHash()));
+ return chainman.ActivateExistingSnapshot(&mempool, GetRandHash()));
reload_all_block_indexes();
@@ -390,4 +471,224 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.size(), num_indexes);
}
+//! Ensure that snapshot chainstates initialize properly when found on disk.
+BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_init, SnapshotTestSetup)
+{
+ ChainstateManager& chainman = *Assert(m_node.chainman);
+ Chainstate& bg_chainstate = chainman.ActiveChainstate();
+
+ this->SetupSnapshot();
+
+ fs::path snapshot_chainstate_dir = *node::FindSnapshotChainstateDir();
+ BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
+ BOOST_CHECK_EQUAL(snapshot_chainstate_dir, gArgs.GetDataDirNet() / "chainstate_snapshot");
+
+ BOOST_CHECK(chainman.IsSnapshotActive());
+ const uint256 snapshot_tip_hash = WITH_LOCK(chainman.GetMutex(),
+ return chainman.ActiveTip()->GetBlockHash());
+
+ auto all_chainstates = chainman.GetAll();
+ BOOST_CHECK_EQUAL(all_chainstates.size(), 2);
+
+ // "Rewind" the background chainstate so that its tip is not at the
+ // base block of the snapshot - this is so after simulating a node restart,
+ // it will initialize instead of attempting to complete validation.
+ //
+ // Note that this is not a realistic use of DisconnectTip().
+ DisconnectedBlockTransactions unused_pool;
+ BlockValidationState unused_state;
+ {
+ LOCK2(::cs_main, bg_chainstate.MempoolMutex());
+ BOOST_CHECK(bg_chainstate.DisconnectTip(unused_state, &unused_pool));
+ unused_pool.clear(); // to avoid queuedTx assertion errors on teardown
+ }
+ BOOST_CHECK_EQUAL(bg_chainstate.m_chain.Height(), 109);
+
+ // Test that simulating a shutdown (resetting ChainstateManager) and then performing
+ // chainstate reinitializing successfully cleans up the background-validation
+ // chainstate data, and we end up with a single chainstate that is at tip.
+ ChainstateManager& chainman_restarted = this->SimulateNodeRestart();
+
+ BOOST_TEST_MESSAGE("Performing Load/Verify/Activate of chainstate");
+
+ // This call reinitializes the chainstates.
+ this->LoadVerifyActivateChainstate();
+
+ {
+ LOCK(chainman_restarted.GetMutex());
+ BOOST_CHECK_EQUAL(chainman_restarted.GetAll().size(), 2);
+ BOOST_CHECK(chainman_restarted.IsSnapshotActive());
+ BOOST_CHECK(!chainman_restarted.IsSnapshotValidated());
+
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveTip()->GetBlockHash(), snapshot_tip_hash);
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 210);
+ }
+
+ BOOST_TEST_MESSAGE(
+ "Ensure we can mine blocks on top of the initialized snapshot chainstate");
+ mineBlocks(10);
+ {
+ LOCK(chainman_restarted.GetMutex());
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 220);
+
+ // Background chainstate should be unaware of new blocks on the snapshot
+ // chainstate.
+ for (Chainstate* cs : chainman_restarted.GetAll()) {
+ if (cs != &chainman_restarted.ActiveChainstate()) {
+ BOOST_CHECK_EQUAL(cs->m_chain.Height(), 109);
+ }
+ }
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion, SnapshotTestSetup)
+{
+ this->SetupSnapshot();
+
+ ChainstateManager& chainman = *Assert(m_node.chainman);
+ Chainstate& active_cs = chainman.ActiveChainstate();
+ auto tip_cache_before_complete = active_cs.m_coinstip_cache_size_bytes;
+ auto db_cache_before_complete = active_cs.m_coinsdb_cache_size_bytes;
+
+ SnapshotCompletionResult res;
+ auto mock_shutdown = [](bilingual_str msg) {};
+
+ fs::path snapshot_chainstate_dir = *node::FindSnapshotChainstateDir();
+ BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
+ BOOST_CHECK_EQUAL(snapshot_chainstate_dir, gArgs.GetDataDirNet() / "chainstate_snapshot");
+
+ BOOST_CHECK(chainman.IsSnapshotActive());
+ const uint256 snapshot_tip_hash = WITH_LOCK(chainman.GetMutex(),
+ return chainman.ActiveTip()->GetBlockHash());
+
+ res = WITH_LOCK(::cs_main,
+ return chainman.MaybeCompleteSnapshotValidation(mock_shutdown));
+ BOOST_CHECK_EQUAL(res, SnapshotCompletionResult::SUCCESS);
+
+ WITH_LOCK(::cs_main, BOOST_CHECK(chainman.IsSnapshotValidated()));
+ BOOST_CHECK(chainman.IsSnapshotActive());
+
+ // Cache should have been rebalanced and reallocated to the "only" remaining
+ // chainstate.
+ BOOST_CHECK(active_cs.m_coinstip_cache_size_bytes > tip_cache_before_complete);
+ BOOST_CHECK(active_cs.m_coinsdb_cache_size_bytes > db_cache_before_complete);
+
+ auto all_chainstates = chainman.GetAll();
+ BOOST_CHECK_EQUAL(all_chainstates.size(), 1);
+ BOOST_CHECK_EQUAL(all_chainstates[0], &active_cs);
+
+ // Trying completion again should return false.
+ res = WITH_LOCK(::cs_main,
+ return chainman.MaybeCompleteSnapshotValidation(mock_shutdown));
+ BOOST_CHECK_EQUAL(res, SnapshotCompletionResult::SKIPPED);
+
+ // The invalid snapshot path should not have been used.
+ fs::path snapshot_invalid_dir = gArgs.GetDataDirNet() / "chainstate_snapshot_INVALID";
+ BOOST_CHECK(!fs::exists(snapshot_invalid_dir));
+ // chainstate_snapshot should still exist.
+ BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
+
+ // Test that simulating a shutdown (resetting ChainstateManager) and then performing
+ // chainstate reinitializing successfully cleans up the background-validation
+ // chainstate data, and we end up with a single chainstate that is at tip.
+ ChainstateManager& chainman_restarted = this->SimulateNodeRestart();
+
+ BOOST_TEST_MESSAGE("Performing Load/Verify/Activate of chainstate");
+
+ // This call reinitializes the chainstates, and should clean up the now unnecessary
+ // background-validation leveldb contents.
+ this->LoadVerifyActivateChainstate();
+
+ BOOST_CHECK(!fs::exists(snapshot_invalid_dir));
+ // chainstate_snapshot should now *not* exist.
+ BOOST_CHECK(!fs::exists(snapshot_chainstate_dir));
+
+ const Chainstate& active_cs2 = chainman_restarted.ActiveChainstate();
+
+ {
+ LOCK(chainman_restarted.GetMutex());
+ BOOST_CHECK_EQUAL(chainman_restarted.GetAll().size(), 1);
+ BOOST_CHECK(!chainman_restarted.IsSnapshotActive());
+ BOOST_CHECK(!chainman_restarted.IsSnapshotValidated());
+ BOOST_CHECK(active_cs2.m_coinstip_cache_size_bytes > tip_cache_before_complete);
+ BOOST_CHECK(active_cs2.m_coinsdb_cache_size_bytes > db_cache_before_complete);
+
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveTip()->GetBlockHash(), snapshot_tip_hash);
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 210);
+ }
+
+ BOOST_TEST_MESSAGE(
+ "Ensure we can mine blocks on top of the \"new\" IBD chainstate");
+ mineBlocks(10);
+ {
+ LOCK(chainman_restarted.GetMutex());
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 220);
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion_hash_mismatch, SnapshotTestSetup)
+{
+ auto chainstates = this->SetupSnapshot();
+ Chainstate& validation_chainstate = *std::get<0>(chainstates);
+ ChainstateManager& chainman = *Assert(m_node.chainman);
+ SnapshotCompletionResult res;
+ auto mock_shutdown = [](bilingual_str msg) {};
+
+ // Test tampering with the IBD UTXO set with an extra coin to ensure it causes
+ // snapshot completion to fail.
+ CCoinsViewCache& ibd_coins = WITH_LOCK(::cs_main,
+ return validation_chainstate.CoinsTip());
+ Coin badcoin;
+ badcoin.out.nValue = InsecureRand32();
+ badcoin.nHeight = 1;
+ badcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0);
+ uint256 txid = InsecureRand256();
+ ibd_coins.AddCoin(COutPoint(txid, 0), std::move(badcoin), false);
+
+ fs::path snapshot_chainstate_dir = gArgs.GetDataDirNet() / "chainstate_snapshot";
+ BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
+
+ res = WITH_LOCK(::cs_main,
+ return chainman.MaybeCompleteSnapshotValidation(mock_shutdown));
+ BOOST_CHECK_EQUAL(res, SnapshotCompletionResult::HASH_MISMATCH);
+
+ auto all_chainstates = chainman.GetAll();
+ BOOST_CHECK_EQUAL(all_chainstates.size(), 1);
+ BOOST_CHECK_EQUAL(all_chainstates[0], &validation_chainstate);
+ BOOST_CHECK_EQUAL(&chainman.ActiveChainstate(), &validation_chainstate);
+
+ fs::path snapshot_invalid_dir = gArgs.GetDataDirNet() / "chainstate_snapshot_INVALID";
+ BOOST_CHECK(fs::exists(snapshot_invalid_dir));
+
+ // Test that simulating a shutdown (resetting ChainstateManager) and then performing
+ // chainstate reinitializing successfully loads only the fully-validated
+ // chainstate data, and we end up with a single chainstate that is at tip.
+ ChainstateManager& chainman_restarted = this->SimulateNodeRestart();
+
+ BOOST_TEST_MESSAGE("Performing Load/Verify/Activate of chainstate");
+
+ // This call reinitializes the chainstates, and should clean up the now unnecessary
+ // background-validation leveldb contents.
+ this->LoadVerifyActivateChainstate();
+
+ BOOST_CHECK(fs::exists(snapshot_invalid_dir));
+ BOOST_CHECK(!fs::exists(snapshot_chainstate_dir));
+
+ {
+ LOCK(::cs_main);
+ BOOST_CHECK_EQUAL(chainman_restarted.GetAll().size(), 1);
+ BOOST_CHECK(!chainman_restarted.IsSnapshotActive());
+ BOOST_CHECK(!chainman_restarted.IsSnapshotValidated());
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 210);
+ }
+
+ BOOST_TEST_MESSAGE(
+ "Ensure we can mine blocks on top of the \"new\" IBD chainstate");
+ mineBlocks(10);
+ {
+ LOCK(::cs_main);
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 220);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp
index c06e6c8d3b..26c48eb0e0 100644
--- a/src/test/validation_flush_tests.cpp
+++ b/src/test/validation_flush_tests.cpp
@@ -1,8 +1,10 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 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 <sync.h>
+#include <test/util/coins.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <validation.h>
@@ -24,19 +26,6 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
LOCK(::cs_main);
auto& view = chainstate.CoinsTip();
- //! Create and add a Coin with DynamicMemoryUsage of 80 bytes to the given view.
- auto add_coin = [](CCoinsViewCache& coins_view) -> COutPoint {
- Coin newcoin;
- uint256 txid = InsecureRand256();
- COutPoint outp{txid, 0};
- newcoin.nHeight = 1;
- newcoin.out.nValue = InsecureRand32();
- newcoin.out.scriptPubKey.assign((uint32_t)56, 1);
- coins_view.AddCoin(outp, std::move(newcoin), false);
-
- return outp;
- };
-
// The number of bytes consumed by coin's heap data, i.e. CScript
// (prevector<28, unsigned char>) when assigned 56 bytes of data per above.
//
@@ -61,7 +50,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
// Add a bunch of coins to see that we at least flip over to CRITICAL.
for (int i{0}; i < 1000; ++i) {
- COutPoint res = add_coin(view);
+ const COutPoint res = AddTestCoin(view);
BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE);
}
@@ -83,7 +72,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
constexpr int COINS_UNTIL_CRITICAL{3};
for (int i{0}; i < COINS_UNTIL_CRITICAL; ++i) {
- COutPoint res = add_coin(view);
+ const COutPoint res = AddTestCoin(view);
print_view_mem_usage(view);
BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE);
BOOST_CHECK_EQUAL(
@@ -93,7 +82,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
// Adding some additional coins will push us over the edge to CRITICAL.
for (int i{0}; i < 4; ++i) {
- add_coin(view);
+ AddTestCoin(view);
print_view_mem_usage(view);
if (chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0) ==
CoinsCacheSizeState::CRITICAL) {
@@ -111,7 +100,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
CoinsCacheSizeState::OK);
for (int i{0}; i < 3; ++i) {
- add_coin(view);
+ AddTestCoin(view);
print_view_mem_usage(view);
BOOST_CHECK_EQUAL(
chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/1 << 10),
@@ -120,7 +109,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
// Adding another coin with the additional mempool room will put us >90%
// but not yet critical.
- add_coin(view);
+ AddTestCoin(view);
print_view_mem_usage(view);
// Only perform these checks on 64 bit hosts; I haven't done the math for 32.
@@ -136,7 +125,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
// Using the default max_* values permits way more coins to be added.
for (int i{0}; i < 1000; ++i) {
- add_coin(view);
+ AddTestCoin(view);
BOOST_CHECK_EQUAL(
chainstate.GetCoinsCacheSizeState(),
CoinsCacheSizeState::OK);
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index e6203af4b4..80c00036e7 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2014-2021 The Bitcoin Core developers
+// Copyright (c) 2014-2022 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 <chain.h>
#include <chainparams.h>
#include <consensus/params.h>
+#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <versionbits.h>
@@ -13,7 +14,7 @@
/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */
static int32_t TestTime(int nHeight) { return 1415926536 + 600 * nHeight; }
-static const std::string StateName(ThresholdState state)
+static std::string StateName(ThresholdState state)
{
switch (state) {
case ThresholdState::DEFINED: return "DEFINED";
diff --git a/src/test/xoroshiro128plusplus_tests.cpp b/src/test/xoroshiro128plusplus_tests.cpp
new file mode 100644
index 0000000000..ea1b3e355f
--- /dev/null
+++ b/src/test/xoroshiro128plusplus_tests.cpp
@@ -0,0 +1,29 @@
+// Copyright (c) 2022 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/util/setup_common.h>
+#include <test/util/xoroshiro128plusplus.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(xoroshiro128plusplus_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(reference_values)
+{
+ // numbers generated from reference implementation
+ XoRoShiRo128PlusPlus rng(0);
+ BOOST_TEST(0x6f68e1e7e2646ee1 == rng());
+ BOOST_TEST(0xbf971b7f454094ad == rng());
+ BOOST_TEST(0x48f2de556f30de38 == rng());
+ BOOST_TEST(0x6ea7c59f89bbfc75 == rng());
+
+ // seed with a random number
+ rng = XoRoShiRo128PlusPlus(0x1a26f3fa8546b47a);
+ BOOST_TEST(0xc8dc5e08d844ac7d == rng());
+ BOOST_TEST(0x5b5f1f6d499dad1b == rng());
+ BOOST_TEST(0xbeb0031f93313d6f == rng());
+ BOOST_TEST(0xbfbcf4f43a264497 == rng());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/timedata.cpp b/src/timedata.cpp
index fe9a5fbed7..a0646b4707 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2021 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/timedata.h b/src/timedata.h
index 669a571f47..c6c36d9a39 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/tinyformat.h b/src/tinyformat.h
index bedaa14007..3ec385bc95 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -508,9 +508,6 @@ class FormatArg
{
public:
FormatArg()
- : m_value(NULL),
- m_formatImpl(NULL),
- m_toIntImpl(NULL)
{ }
template<typename T>
@@ -549,10 +546,10 @@ class FormatArg
return convertToInt<T>::invoke(*static_cast<const T*>(value));
}
- const void* m_value;
+ const void* m_value{nullptr};
void (*m_formatImpl)(std::ostream& out, const char* fmtBegin,
- const char* fmtEnd, int ntrunc, const void* value);
- int (*m_toIntImpl)(const void* value);
+ const char* fmtEnd, int ntrunc, const void* value){nullptr};
+ int (*m_toIntImpl)(const void* value){nullptr};
};
@@ -1005,7 +1002,8 @@ class FormatListN : public FormatList
// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard
template<> class FormatListN<0> : public FormatList
{
- public: FormatListN() : FormatList(0, 0) {}
+public:
+ FormatListN() : FormatList(nullptr, 0) {}
};
} // namespace detail
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 3a21a79a34..d4daeacd3e 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -53,8 +53,8 @@ static const uint16_t DEFAULT_TOR_SOCKS_PORT = 9050;
/****** Low-level TorControlConnection ********/
-TorControlConnection::TorControlConnection(struct event_base *_base):
- base(_base), b_conn(nullptr)
+TorControlConnection::TorControlConnection(struct event_base* _base)
+ : base(_base)
{
}
@@ -380,7 +380,7 @@ void TorController::get_socks_cb(TorControlConnection& _conn, const TorControlRe
}
Assume(resolved.IsValid());
- LogPrint(BCLog::TOR, "Configuring onion proxy for %s\n", resolved.ToStringIPPort());
+ LogPrint(BCLog::TOR, "Configuring onion proxy for %s\n", resolved.ToStringAddrPort());
Proxy addrOnion = Proxy(resolved, true);
SetProxy(NET_ONION, addrOnion);
@@ -421,7 +421,7 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe
return;
}
service = LookupNumeric(std::string(service_id+".onion"), Params().GetDefaultPort());
- LogPrintfCategory(BCLog::TOR, "Got service ID %s, advertising service %s\n", service_id, service.ToString());
+ LogPrintfCategory(BCLog::TOR, "Got service ID %s, advertising service %s\n", service_id, service.ToStringAddrPort());
if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) {
LogPrint(BCLog::TOR, "Cached service private key to %s\n", fs::PathToString(GetPrivateKeyFile()));
} else {
@@ -453,7 +453,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
}
// Request onion service, redirect port.
// Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports.
- _conn.Command(strprintf("ADD_ONION %s Port=%i,%s", private_key, Params().GetDefaultPort(), m_target.ToStringIPPort()),
+ _conn.Command(strprintf("ADD_ONION %s Port=%i,%s", private_key, Params().GetDefaultPort(), m_target.ToStringAddrPort()),
std::bind(&TorController::add_onion_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
LogPrintf("tor: Authentication failed\n");
diff --git a/src/torcontrol.h b/src/torcontrol.h
index 81475aee74..6563a2ef42 100644
--- a/src/torcontrol.h
+++ b/src/torcontrol.h
@@ -93,7 +93,7 @@ private:
/** Libevent event base */
struct event_base *base;
/** Connection to control socket */
- struct bufferevent *b_conn;
+ struct bufferevent* b_conn{nullptr};
/** Message being received */
TorControlReply message;
/** Response handlers */
diff --git a/src/txdb.cpp b/src/txdb.cpp
index bad3bb80a9..15351a4355 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -1,16 +1,16 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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 <txdb.h>
#include <chain.h>
+#include <logging.h>
#include <pow.h>
#include <random.h>
#include <shutdown.h>
#include <uint256.h>
-#include <util/system.h>
#include <util/translation.h>
#include <util/vector.h>
@@ -70,21 +70,22 @@ struct CoinEntry {
} // namespace
-CCoinsViewDB::CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe) :
- m_db(std::make_unique<CDBWrapper>(ldb_path, nCacheSize, fMemory, fWipe, true)),
- m_ldb_path(ldb_path),
- m_is_memory(fMemory) { }
+CCoinsViewDB::CCoinsViewDB(DBParams db_params, CoinsViewOptions options) :
+ m_db_params{std::move(db_params)},
+ m_options{std::move(options)},
+ m_db{std::make_unique<CDBWrapper>(m_db_params)} { }
void CCoinsViewDB::ResizeCache(size_t new_cache_size)
{
// We can't do this operation with an in-memory DB since we'll lose all the coins upon
// reset.
- if (!m_is_memory) {
+ if (!m_db_params.memory_only) {
// Have to do a reset first to get the original `m_db` state to release its
// filesystem lock.
m_db.reset();
- m_db = std::make_unique<CDBWrapper>(
- m_ldb_path, new_cache_size, m_is_memory, /*fWipe=*/false, /*obfuscate=*/true);
+ m_db_params.cache_bytes = new_cache_size;
+ m_db_params.wipe_data = false;
+ m_db = std::make_unique<CDBWrapper>(m_db_params);
}
}
@@ -111,12 +112,10 @@ std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
return vhashHeadBlocks;
}
-bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
+bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase) {
CDBBatch batch(*m_db);
size_t count = 0;
size_t changed = 0;
- size_t batch_size = (size_t)gArgs.GetIntArg("-dbbatchsize", nDefaultDbBatchSize);
- int crash_simulate = gArgs.GetIntArg("-dbcrashratio", 0);
assert(!hashBlock.IsNull());
uint256 old_tip = GetBestBlock();
@@ -146,15 +145,14 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
changed++;
}
count++;
- CCoinsMap::iterator itOld = it++;
- mapCoins.erase(itOld);
- if (batch.SizeEstimate() > batch_size) {
+ it = erase ? mapCoins.erase(it) : std::next(it);
+ if (batch.SizeEstimate() > m_options.batch_write_bytes) {
LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
m_db->WriteBatch(batch);
batch.Clear();
- if (crash_simulate) {
+ if (m_options.simulate_crash_ratio) {
static FastRandomContext rng;
- if (rng.randrange(crash_simulate) == 0) {
+ if (rng.randrange(m_options.simulate_crash_ratio) == 0) {
LogPrintf("Simulating a crash. Goodbye.\n");
_Exit(0);
}
@@ -177,9 +175,6 @@ size_t CCoinsViewDB::EstimateSize() const
return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
}
-CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(gArgs.GetDataDirNet() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
-}
-
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
}
diff --git a/src/txdb.h b/src/txdb.h
index a04596f7bb..8a876349fb 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,7 +8,9 @@
#include <coins.h>
#include <dbwrapper.h>
+#include <kernel/cs_main.h>
#include <sync.h>
+#include <fs.h>
#include <memory>
#include <optional>
@@ -43,27 +45,30 @@ static const int64_t max_filter_index_cache = 1024;
//! Max memory allocated to coin DB specific cache (MiB)
static const int64_t nMaxCoinsDBCache = 8;
-// Actually declared in validation.cpp; can't include because of circular dependency.
-extern RecursiveMutex cs_main;
+//! User-controlled performance and debug options.
+struct CoinsViewOptions {
+ //! Maximum database write batch size in bytes.
+ size_t batch_write_bytes = nDefaultDbBatchSize;
+ //! If non-zero, randomly exit when the database is flushed with (1/ratio)
+ //! probability.
+ int simulate_crash_ratio = 0;
+};
/** CCoinsView backed by the coin database (chainstate/) */
class CCoinsViewDB final : public CCoinsView
{
protected:
+ DBParams m_db_params;
+ CoinsViewOptions m_options;
std::unique_ptr<CDBWrapper> m_db;
- fs::path m_ldb_path;
- bool m_is_memory;
public:
- /**
- * @param[in] ldb_path Location in the filesystem where leveldb data will be stored.
- */
- explicit CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe);
+ explicit CCoinsViewDB(DBParams db_params, CoinsViewOptions options);
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
bool HaveCoin(const COutPoint &outpoint) const override;
uint256 GetBestBlock() const override;
std::vector<uint256> GetHeadBlocks() const override;
- bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase = true) override;
std::unique_ptr<CCoinsViewCursor> Cursor() const override;
//! Whether an unsupported database format is used.
@@ -72,14 +77,16 @@ public:
//! Dynamically alter the underlying leveldb cache size.
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ //! @returns filesystem path to on-disk storage or std::nullopt if in memory.
+ std::optional<fs::path> StoragePath() { return m_db->StoragePath(); }
};
/** Access to the block database (blocks/index/) */
class CBlockTreeDB : public CDBWrapper
{
public:
- explicit CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
-
+ using CDBWrapper::CDBWrapper;
bool WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo);
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &info);
bool ReadLastBlockFile(int &nFile);
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index e1288b7346..378123ce0f 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,12 +17,16 @@
#include <util/check.h>
#include <util/moneystr.h>
#include <util/overflow.h>
+#include <util/result.h>
#include <util/system.h>
#include <util/time.h>
+#include <util/translation.h>
#include <validationinterface.h>
#include <cmath>
#include <optional>
+#include <string_view>
+#include <utility>
bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
{
@@ -41,42 +45,6 @@ bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
return true;
}
-CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& tx, CAmount fee,
- int64_t time, unsigned int entry_height,
- bool spends_coinbase, int64_t sigops_cost, LockPoints lp)
- : tx{tx},
- nFee{fee},
- nTxWeight(GetTransactionWeight(*tx)),
- nUsageSize{RecursiveDynamicUsage(tx)},
- nTime{time},
- entryHeight{entry_height},
- spendsCoinbase{spends_coinbase},
- sigOpCost{sigops_cost},
- m_modified_fee{nFee},
- lockPoints{lp},
- nSizeWithDescendants{GetTxSize()},
- nModFeesWithDescendants{nFee},
- nSizeWithAncestors{GetTxSize()},
- nModFeesWithAncestors{nFee},
- nSigOpCostWithAncestors{sigOpCost} {}
-
-void CTxMemPoolEntry::UpdateModifiedFee(CAmount fee_diff)
-{
- nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, fee_diff);
- nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, fee_diff);
- m_modified_fee = SaturatingAdd(m_modified_fee, fee_diff);
-}
-
-void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp)
-{
- lockPoints = lp;
-}
-
-size_t CTxMemPoolEntry::GetTxSize() const
-{
- return GetVirtualTransactionSize(nTxWeight, sigOpCost, ::nBytesPerSigOp);
-}
-
void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants,
const std::set<uint256>& setExclude, std::set<uint256>& descendants_to_remove)
{
@@ -145,7 +113,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashes
// Iterate in reverse, so that whenever we are looking at a transaction
// we are sure that all in-mempool descendants have already been processed.
// This maximizes the benefit of the descendant cache and guarantees that
- // CTxMemPool::m_children will be updated, an assumption made in
+ // CTxMemPoolEntry::m_children will be updated, an assumption made in
// UpdateForDescendants.
for (const uint256 &hash : reverse_iterate(vHashesToUpdate)) {
// calculate children from mapNextTx
@@ -154,7 +122,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashes
continue;
}
auto iter = mapNextTx.lower_bound(COutPoint(hash, 0));
- // First calculate the children, and update CTxMemPool::m_children to
+ // First calculate the children, and update CTxMemPoolEntry::m_children to
// include them, and update their CTxMemPoolEntry::m_parents to include this tx.
// we cache the in-mempool children to avoid duplicate updates
{
@@ -183,35 +151,29 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashes
}
}
-bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size,
- size_t entry_count,
- setEntries& setAncestors,
- CTxMemPoolEntry::Parents& staged_ancestors,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
- std::string &errString) const
+util::Result<CTxMemPool::setEntries> CTxMemPool::CalculateAncestorsAndCheckLimits(
+ size_t entry_size,
+ size_t entry_count,
+ CTxMemPoolEntry::Parents& staged_ancestors,
+ const Limits& limits) const
{
size_t totalSizeWithAncestors = entry_size;
+ setEntries ancestors;
while (!staged_ancestors.empty()) {
const CTxMemPoolEntry& stage = staged_ancestors.begin()->get();
txiter stageit = mapTx.iterator_to(stage);
- setAncestors.insert(stageit);
+ ancestors.insert(stageit);
staged_ancestors.erase(stage);
totalSizeWithAncestors += stageit->GetTxSize();
- if (stageit->GetSizeWithDescendants() + entry_size > limitDescendantSize) {
- errString = strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantSize);
- return false;
- } else if (stageit->GetCountWithDescendants() + entry_count > limitDescendantCount) {
- errString = strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantCount);
- return false;
- } else if (totalSizeWithAncestors > limitAncestorSize) {
- errString = strprintf("exceeds ancestor size limit [limit: %u]", limitAncestorSize);
- return false;
+ if (stageit->GetSizeWithDescendants() + entry_size > static_cast<uint64_t>(limits.descendant_size_vbytes)) {
+ return util::Error{Untranslated(strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_size_vbytes))};
+ } else if (stageit->GetCountWithDescendants() + entry_count > static_cast<uint64_t>(limits.descendant_count)) {
+ return util::Error{Untranslated(strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_count))};
+ } else if (totalSizeWithAncestors > static_cast<uint64_t>(limits.ancestor_size_vbytes)) {
+ return util::Error{Untranslated(strprintf("exceeds ancestor size limit [limit: %u]", limits.ancestor_size_vbytes))};
}
const CTxMemPoolEntry::Parents& parents = stageit->GetMemPoolParentsConst();
@@ -219,24 +181,20 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size,
txiter parent_it = mapTx.iterator_to(parent);
// If this is a new ancestor, add it.
- if (setAncestors.count(parent_it) == 0) {
+ if (ancestors.count(parent_it) == 0) {
staged_ancestors.insert(parent);
}
- if (staged_ancestors.size() + setAncestors.size() + entry_count > limitAncestorCount) {
- errString = strprintf("too many unconfirmed ancestors [limit: %u]", limitAncestorCount);
- return false;
+ if (staged_ancestors.size() + ancestors.size() + entry_count > static_cast<uint64_t>(limits.ancestor_count)) {
+ return util::Error{Untranslated(strprintf("too many unconfirmed ancestors [limit: %u]", limits.ancestor_count))};
}
}
}
- return true;
+ return ancestors;
}
bool CTxMemPool::CheckPackageLimits(const Package& package,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
+ const Limits& limits,
std::string &errString) const
{
CTxMemPoolEntry::Parents staged_ancestors;
@@ -247,8 +205,8 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
std::optional<txiter> piter = GetIter(input.prevout.hash);
if (piter) {
staged_ancestors.insert(**piter);
- if (staged_ancestors.size() + package.size() > limitAncestorCount) {
- errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount);
+ if (staged_ancestors.size() + package.size() > static_cast<uint64_t>(limits.ancestor_count)) {
+ errString = strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count);
return false;
}
}
@@ -257,24 +215,17 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
// When multiple transactions are passed in, the ancestors and descendants of all transactions
// considered together must be within limits even if they are not interdependent. This may be
// stricter than the limits for each individual transaction.
- setEntries setAncestors;
- const auto ret = CalculateAncestorsAndCheckLimits(total_size, package.size(),
- setAncestors, staged_ancestors,
- limitAncestorCount, limitAncestorSize,
- limitDescendantCount, limitDescendantSize, errString);
+ const auto ancestors{CalculateAncestorsAndCheckLimits(total_size, package.size(),
+ staged_ancestors, limits)};
// It's possible to overestimate the ancestor/descendant totals.
- if (!ret) errString.insert(0, "possibly ");
- return ret;
+ if (!ancestors.has_value()) errString = "possibly " + util::ErrorString(ancestors).original;
+ return ancestors.has_value();
}
-bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry,
- setEntries &setAncestors,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
- std::string &errString,
- bool fSearchForParents /* = true */) const
+util::Result<CTxMemPool::setEntries> CTxMemPool::CalculateMemPoolAncestors(
+ const CTxMemPoolEntry &entry,
+ const Limits& limits,
+ bool fSearchForParents /* = true */) const
{
CTxMemPoolEntry::Parents staged_ancestors;
const CTransaction &tx = entry.GetTx();
@@ -287,9 +238,8 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry,
std::optional<txiter> piter = GetIter(tx.vin[i].prevout.hash);
if (piter) {
staged_ancestors.insert(**piter);
- if (staged_ancestors.size() + 1 > limitAncestorCount) {
- errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount);
- return false;
+ if (staged_ancestors.size() + 1 > static_cast<uint64_t>(limits.ancestor_count)) {
+ return util::Error{Untranslated(strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count))};
}
}
}
@@ -300,10 +250,22 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry,
staged_ancestors = it->GetMemPoolParentsConst();
}
- return CalculateAncestorsAndCheckLimits(entry.GetTxSize(), /*entry_count=*/1,
- setAncestors, staged_ancestors,
- limitAncestorCount, limitAncestorSize,
- limitDescendantCount, limitDescendantSize, errString);
+ return CalculateAncestorsAndCheckLimits(entry.GetTxSize(), /*entry_count=*/1, staged_ancestors,
+ limits);
+}
+
+CTxMemPool::setEntries CTxMemPool::AssumeCalculateMemPoolAncestors(
+ std::string_view calling_fn_name,
+ const CTxMemPoolEntry &entry,
+ const Limits& limits,
+ bool fSearchForParents /* = true */) const
+{
+ auto result{CalculateMemPoolAncestors(entry, limits, fSearchForParents)};
+ if (!Assume(result)) {
+ LogPrintLevel(BCLog::MEMPOOL, BCLog::Level::Error, "%s: CalculateMemPoolAncestors failed unexpectedly, continuing with empty ancestor set (%s)\n",
+ calling_fn_name, util::ErrorString(result).original);
+ }
+ return std::move(result).value_or(CTxMemPool::setEntries{});
}
void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors)
@@ -347,7 +309,6 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
{
// For each entry, walk back all ancestors and decrement size associated with this
// transaction
- const uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
if (updateDescendants) {
// updateDescendants should be true whenever we're not recursively
// removing a tx and all its descendants, eg when a transaction is
@@ -368,9 +329,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
}
}
for (txiter removeIt : entriesToRemove) {
- setEntries setAncestors;
const CTxMemPoolEntry &entry = *removeIt;
- std::string dummy;
// Since this is a tx that is already in the mempool, we can call CMPA
// with fSearchForParents = false. If the mempool is in a consistent
// state, then using true or false should both be correct, though false
@@ -390,10 +349,10 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
// mempool parents we'd calculate by searching, and it's important that
// we use the cached notion of ancestor transactions as the set of
// things to update for removal.
- CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
+ auto ancestors{AssumeCalculateMemPoolAncestors(__func__, entry, Limits::NoLimits(), /*fSearchForParents=*/false)};
// Note that UpdateAncestorsOf severs the child links that point to
// removeIt in the entries for the parents of removeIt.
- UpdateAncestorsOf(false, removeIt, setAncestors);
+ UpdateAncestorsOf(false, removeIt, ancestors);
}
// After updating all the ancestor sizes, we can now sever the link between each
// transaction being removed and any mempool children (ie, update CTxMemPoolEntry::m_parents
@@ -437,7 +396,6 @@ CTxMemPool::CTxMemPool(const Options& opts)
m_full_rbf{opts.full_rbf},
m_limits{opts.limits}
{
- _clear(); //lock free clear
}
bool CTxMemPool::isSpent(const COutPoint& outpoint) const
@@ -675,26 +633,6 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
blockSinceLastRollingFeeBump = true;
}
-void CTxMemPool::_clear()
-{
- vTxHashes.clear();
- mapTx.clear();
- mapNextTx.clear();
- totalTxSize = 0;
- m_total_fee = 0;
- cachedInnerUsage = 0;
- lastRollingFeeUpdate = GetTime();
- blockSinceLastRollingFeeBump = false;
- rollingMinimumFeeRate = 0;
- ++nTransactionsUpdated;
-}
-
-void CTxMemPool::clear()
-{
- LOCK(cs);
- _clear();
-}
-
void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendheight) const
{
if (m_check_ratio == 0) return;
@@ -743,16 +681,13 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
assert(setParentCheck.size() == it->GetMemPoolParentsConst().size());
assert(std::equal(setParentCheck.begin(), setParentCheck.end(), it->GetMemPoolParentsConst().begin(), comp));
// Verify ancestor state is correct.
- setEntries setAncestors;
- uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
- std::string dummy;
- CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
- uint64_t nCountCheck = setAncestors.size() + 1;
+ auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits())};
+ uint64_t nCountCheck = ancestors.size() + 1;
uint64_t nSizeCheck = it->GetTxSize();
CAmount nFeesCheck = it->GetModifiedFee();
int64_t nSigOpCheck = it->GetSigOpCost();
- for (txiter ancestorIt : setAncestors) {
+ for (txiter ancestorIt : ancestors) {
nSizeCheck += ancestorIt->GetTxSize();
nFeesCheck += ancestorIt->GetModifiedFee();
nSigOpCheck += ancestorIt->GetSigOpCost();
@@ -907,11 +842,8 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD
if (it != mapTx.end()) {
mapTx.modify(it, [&nFeeDelta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(nFeeDelta); });
// Now update all ancestors' modified fees with descendants
- setEntries setAncestors;
- uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
- std::string dummy;
- CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
- for (txiter ancestorIt : setAncestors) {
+ auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits(), /*fSearchForParents=*/false)};
+ for (txiter ancestorIt : ancestors) {
mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e){ e.UpdateDescendantState(0, nFeeDelta, 0);});
}
// Now update all descendants' modified fees with ancestors
@@ -1048,11 +980,8 @@ int CTxMemPool::Expire(std::chrono::seconds time)
void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate)
{
- setEntries setAncestors;
- uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
- std::string dummy;
- CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
- return addUnchecked(entry, setAncestors, validFeeEstimate);
+ auto ancestors{AssumeCalculateMemPoolAncestors(__func__, entry, Limits::NoLimits())};
+ return addUnchecked(entry, ancestors, validFeeEstimate);
}
void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add)
@@ -1197,3 +1126,17 @@ void CTxMemPool::SetLoadTried(bool load_tried)
LOCK(cs);
m_load_tried = load_tried;
}
+
+
+std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept
+{
+ switch (r) {
+ case MemPoolRemovalReason::EXPIRY: return "expiry";
+ case MemPoolRemovalReason::SIZELIMIT: return "sizelimit";
+ case MemPoolRemovalReason::REORG: return "reorg";
+ case MemPoolRemovalReason::BLOCK: return "block";
+ case MemPoolRemovalReason::CONFLICT: return "conflict";
+ case MemPoolRemovalReason::REPLACED: return "replaced";
+ }
+ assert(false);
+}
diff --git a/src/txmempool.h b/src/txmempool.h
index cd15d069b1..2c3cb7e9db 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@
#include <optional>
#include <set>
#include <string>
+#include <string_view>
#include <utility>
#include <vector>
@@ -20,6 +21,8 @@
#include <coins.h>
#include <consensus/amount.h>
#include <indirectmap.h>
+#include <kernel/cs_main.h>
+#include <kernel/mempool_entry.h>
#include <policy/feerate.h>
#include <policy/packages.h>
#include <primitives/transaction.h>
@@ -27,6 +30,7 @@
#include <sync.h>
#include <util/epochguard.h>
#include <util/hasher.h>
+#include <util/result.h>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
@@ -36,137 +40,15 @@
class CBlockIndex;
class CChain;
class Chainstate;
-extern RecursiveMutex cs_main;
/** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */
static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF;
-struct LockPoints {
- // Will be set to the blockchain height and median time past
- // values that would be necessary to satisfy all relative locktime
- // constraints (BIP68) of this tx given our view of block chain history
- int height{0};
- int64_t time{0};
- // As long as the current chain descends from the highest height block
- // containing one of the inputs used in the calculation, then the cached
- // values are still valid even after a reorg.
- CBlockIndex* maxInputBlock{nullptr};
-};
-
/**
* Test whether the LockPoints height and time are still valid on the current chain
*/
bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-struct CompareIteratorByHash {
- // SFINAE for T where T is either a pointer type (e.g., a txiter) or a reference_wrapper<T>
- // (e.g. a wrapped CTxMemPoolEntry&)
- template <typename T>
- bool operator()(const std::reference_wrapper<T>& a, const std::reference_wrapper<T>& b) const
- {
- return a.get().GetTx().GetHash() < b.get().GetTx().GetHash();
- }
- template <typename T>
- bool operator()(const T& a, const T& b) const
- {
- return a->GetTx().GetHash() < b->GetTx().GetHash();
- }
-};
-
-/** \class CTxMemPoolEntry
- *
- * CTxMemPoolEntry stores data about the corresponding transaction, as well
- * as data about all in-mempool transactions that depend on the transaction
- * ("descendant" transactions).
- *
- * When a new entry is added to the mempool, we update the descendant state
- * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for
- * all ancestors of the newly added transaction.
- *
- */
-
-class CTxMemPoolEntry
-{
-public:
- typedef std::reference_wrapper<const CTxMemPoolEntry> CTxMemPoolEntryRef;
- // two aliases, should the types ever diverge
- typedef std::set<CTxMemPoolEntryRef, CompareIteratorByHash> Parents;
- typedef std::set<CTxMemPoolEntryRef, CompareIteratorByHash> Children;
-
-private:
- const CTransactionRef tx;
- mutable Parents m_parents;
- mutable Children m_children;
- const CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
- const size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
- const size_t nUsageSize; //!< ... and total memory usage
- const int64_t nTime; //!< Local time when entering the mempool
- const unsigned int entryHeight; //!< Chain height when entering the mempool
- const bool spendsCoinbase; //!< keep track of transactions that spend a coinbase
- const int64_t sigOpCost; //!< Total sigop cost
- CAmount m_modified_fee; //!< Used for determining the priority of the transaction for mining in a block
- LockPoints lockPoints; //!< Track the height and time at which tx was final
-
- // Information about descendants of this transaction that are in the
- // mempool; if we remove this transaction we must remove all of these
- // descendants as well.
- uint64_t nCountWithDescendants{1}; //!< number of descendant transactions
- uint64_t nSizeWithDescendants; //!< ... and size
- CAmount nModFeesWithDescendants; //!< ... and total fees (all including us)
-
- // Analogous statistics for ancestor transactions
- uint64_t nCountWithAncestors{1};
- uint64_t nSizeWithAncestors;
- CAmount nModFeesWithAncestors;
- int64_t nSigOpCostWithAncestors;
-
-public:
- CTxMemPoolEntry(const CTransactionRef& tx, CAmount fee,
- int64_t time, unsigned int entry_height,
- bool spends_coinbase,
- int64_t sigops_cost, LockPoints lp);
-
- const CTransaction& GetTx() const { return *this->tx; }
- CTransactionRef GetSharedTx() const { return this->tx; }
- const CAmount& GetFee() const { return nFee; }
- size_t GetTxSize() const;
- size_t GetTxWeight() const { return nTxWeight; }
- std::chrono::seconds GetTime() const { return std::chrono::seconds{nTime}; }
- unsigned int GetHeight() const { return entryHeight; }
- int64_t GetSigOpCost() const { return sigOpCost; }
- CAmount GetModifiedFee() const { return m_modified_fee; }
- size_t DynamicMemoryUsage() const { return nUsageSize; }
- const LockPoints& GetLockPoints() const { return lockPoints; }
-
- // Adjusts the descendant state.
- void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
- // Adjusts the ancestor state
- void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps);
- // Updates the modified fees with descendants/ancestors.
- void UpdateModifiedFee(CAmount fee_diff);
- // Update the LockPoints after a reorg
- void UpdateLockPoints(const LockPoints& lp);
-
- uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
- uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
- CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
-
- bool GetSpendsCoinbase() const { return spendsCoinbase; }
-
- uint64_t GetCountWithAncestors() const { return nCountWithAncestors; }
- uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
- CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
- int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; }
-
- const Parents& GetMemPoolParentsConst() const { return m_parents; }
- const Children& GetMemPoolChildrenConst() const { return m_children; }
- Parents& GetMemPoolParents() const { return m_parents; }
- Children& GetMemPoolChildren() const { return m_children; }
-
- mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes
- mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms
-};
-
// extracts a transaction hash from CTxMemPoolEntry or CTransactionRef
struct mempoolentry_txid
{
@@ -355,6 +237,8 @@ enum class MemPoolRemovalReason {
REPLACED, //!< Removed for replacement
};
+std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept;
+
/**
* CTxMemPool stores valid-according-to-the-current-best-chain transactions
* that may be included in the next block.
@@ -435,14 +319,14 @@ protected:
std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
CBlockPolicyEstimator* const minerPolicyEstimator;
- uint64_t totalTxSize GUARDED_BY(cs); //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
- CAmount m_total_fee GUARDED_BY(cs); //!< sum of all mempool tx's fees (NOT modified fee)
- uint64_t cachedInnerUsage GUARDED_BY(cs); //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves)
+ uint64_t totalTxSize GUARDED_BY(cs){0}; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
+ CAmount m_total_fee GUARDED_BY(cs){0}; //!< sum of all mempool tx's fees (NOT modified fee)
+ uint64_t cachedInnerUsage GUARDED_BY(cs){0}; //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves)
- mutable int64_t lastRollingFeeUpdate GUARDED_BY(cs);
- mutable bool blockSinceLastRollingFeeBump GUARDED_BY(cs);
- mutable double rollingMinimumFeeRate GUARDED_BY(cs); //!< minimum fee to get into the pool, decreases exponentially
- mutable Epoch m_epoch GUARDED_BY(cs);
+ mutable int64_t lastRollingFeeUpdate GUARDED_BY(cs){GetTime()};
+ mutable bool blockSinceLastRollingFeeBump GUARDED_BY(cs){false};
+ mutable double rollingMinimumFeeRate GUARDED_BY(cs){0}; //!< minimum fee to get into the pool, decreases exponentially
+ mutable Epoch m_epoch GUARDED_BY(cs){};
// In-memory counter for external mempool tracking purposes.
// This number is incremented once every time a transaction
@@ -526,6 +410,8 @@ public:
typedef std::set<txiter, CompareIteratorByHash> setEntries;
+ using Limits = kernel::MemPoolLimits;
+
uint64_t CalculateDescendantMaximum(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
private:
typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap;
@@ -544,21 +430,20 @@ private:
/**
* Helper function to calculate all in-mempool ancestors of staged_ancestors and apply ancestor
- * and descendant limits (including staged_ancestors thsemselves, entry_size and entry_count).
- * param@[in] entry_size Virtual size to include in the limits.
- * param@[in] entry_count How many entries to include in the limits.
- * param@[in] staged_ancestors Should contain entries in the mempool.
- * param@[out] setAncestors Will be populated with all mempool ancestors.
+ * and descendant limits (including staged_ancestors themselves, entry_size and entry_count).
+ *
+ * @param[in] entry_size Virtual size to include in the limits.
+ * @param[in] entry_count How many entries to include in the limits.
+ * @param[in] staged_ancestors Should contain entries in the mempool.
+ * @param[in] limits Maximum number and size of ancestors and descendants
+ *
+ * @return all in-mempool ancestors, or an error if any ancestor or descendant limits were hit
*/
- bool CalculateAncestorsAndCheckLimits(size_t entry_size,
- size_t entry_count,
- setEntries& setAncestors,
- CTxMemPoolEntry::Parents &staged_ancestors,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
- std::string &errString) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ util::Result<setEntries> CalculateAncestorsAndCheckLimits(size_t entry_size,
+ size_t entry_count,
+ CTxMemPoolEntry::Parents &staged_ancestors,
+ const Limits& limits
+ ) const EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
indirectmap<COutPoint, const CTransaction*> mapNextTx GUARDED_BY(cs);
@@ -576,8 +461,6 @@ public:
const bool m_require_standard;
const bool m_full_rbf;
- using Limits = kernel::MemPoolLimits;
-
const Limits m_limits;
/** Create a new CTxMemPool.
@@ -617,8 +500,6 @@ public:
void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs);
- void clear();
- void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid=false);
void queryHashes(std::vector<uint256>& vtxid) const;
bool isSpent(const COutPoint& outpoint) const;
@@ -668,38 +549,56 @@ public:
*/
void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch);
- /** Try to calculate all in-mempool ancestors of entry.
- * (these are all calculated including the tx itself)
- * limitAncestorCount = max number of ancestors
- * limitAncestorSize = max size of ancestors
- * limitDescendantCount = max number of descendants any ancestor can have
- * limitDescendantSize = max size of descendants any ancestor can have
- * errString = populated with error reason if any limits are hit
- * fSearchForParents = whether to search a tx's vin for in-mempool parents, or
- * look up parents from mapLinks. Must be true for entries not in the mempool
+ /**
+ * Try to calculate all in-mempool ancestors of entry.
+ * (these are all calculated including the tx itself)
+ *
+ * @param[in] entry CTxMemPoolEntry of which all in-mempool ancestors are calculated
+ * @param[in] limits Maximum number and size of ancestors and descendants
+ * @param[in] fSearchForParents Whether to search a tx's vin for in-mempool parents, or look
+ * up parents from mapLinks. Must be true for entries not in
+ * the mempool
+ *
+ * @return all in-mempool ancestors, or an error if any ancestor or descendant limits were hit
+ */
+ util::Result<setEntries> CalculateMemPoolAncestors(const CTxMemPoolEntry& entry,
+ const Limits& limits,
+ bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+
+ /**
+ * Same as CalculateMemPoolAncestors, but always returns a (non-optional) setEntries.
+ * Should only be used when it is assumed CalculateMemPoolAncestors would not fail. If
+ * CalculateMemPoolAncestors does unexpectedly fail, an empty setEntries is returned and the
+ * error is logged to BCLog::MEMPOOL with level BCLog::Level::Error. In debug builds, failure
+ * of CalculateMemPoolAncestors will lead to shutdown due to assertion failure.
+ *
+ * @param[in] calling_fn_name Name of calling function so we can properly log the call site
+ *
+ * @return a setEntries corresponding to the result of CalculateMemPoolAncestors or an empty
+ * setEntries if it failed
+ *
+ * @see CTXMemPool::CalculateMemPoolAncestors()
*/
- bool CalculateMemPoolAncestors(const CTxMemPoolEntry& entry, setEntries& setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string& errString, bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ setEntries AssumeCalculateMemPoolAncestors(
+ std::string_view calling_fn_name,
+ const CTxMemPoolEntry &entry,
+ const Limits& limits,
+ bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Calculate all in-mempool ancestors of a set of transactions not already in the mempool and
* check ancestor and descendant limits. Heuristics are used to estimate the ancestor and
* descendant count of all entries if the package were to be added to the mempool. The limits
* are applied to the union of all package transactions. For example, if the package has 3
- * transactions and limitAncestorCount = 25, the union of all 3 sets of ancestors (including the
+ * transactions and limits.ancestor_count = 25, the union of all 3 sets of ancestors (including the
* transactions themselves) must be <= 22.
* @param[in] package Transaction package being evaluated for acceptance
* to mempool. The transactions need not be direct
* ancestors/descendants of each other.
- * @param[in] limitAncestorCount Max number of txns including ancestors.
- * @param[in] limitAncestorSize Max virtual size including ancestors.
- * @param[in] limitDescendantCount Max number of txns including descendants.
- * @param[in] limitDescendantSize Max virtual size including descendants.
+ * @param[in] limits Maximum number and size of ancestors and descendants
* @param[out] errString Populated with error reason if a limit is hit.
*/
bool CheckPackageLimits(const Package& package,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
+ const Limits& limits,
std::string &errString) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Populate setDescendants with all in-mempool descendants of hash.
@@ -825,7 +724,7 @@ private:
* mempool but may have child transactions in the mempool, eg during a
* chain reorg.
*
- * @pre CTxMemPool::m_children is correct for the given tx and all
+ * @pre CTxMemPoolEntry::m_children is correct for the given tx and all
* descendants.
* @pre cachedDescendants is an accurate cache where each entry has all
* descendants of the corresponding key, including those that should
diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp
index 69ae8ea582..19f9fae998 100644
--- a/src/txorphanage.cpp
+++ b/src/txorphanage.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,11 +15,10 @@ static constexpr int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60;
/** Minimum time between orphan transactions expire time checks in seconds */
static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60;
-RecursiveMutex g_cs_orphans;
bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
{
- AssertLockHeld(g_cs_orphans);
+ LOCK(m_mutex);
const uint256& hash = tx->GetHash();
if (m_orphans.count(hash))
@@ -55,7 +54,13 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
int TxOrphanage::EraseTx(const uint256& txid)
{
- AssertLockHeld(g_cs_orphans);
+ LOCK(m_mutex);
+ return _EraseTx(txid);
+}
+
+int TxOrphanage::_EraseTx(const uint256& txid)
+{
+ AssertLockHeld(m_mutex);
std::map<uint256, OrphanTx>::iterator it = m_orphans.find(txid);
if (it == m_orphans.end())
return 0;
@@ -87,7 +92,9 @@ int TxOrphanage::EraseTx(const uint256& txid)
void TxOrphanage::EraseForPeer(NodeId peer)
{
- AssertLockHeld(g_cs_orphans);
+ LOCK(m_mutex);
+
+ m_peer_work_set.erase(peer);
int nErased = 0;
std::map<uint256, OrphanTx>::iterator iter = m_orphans.begin();
@@ -96,7 +103,7 @@ void TxOrphanage::EraseForPeer(NodeId peer)
std::map<uint256, OrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
if (maybeErase->second.fromPeer == peer)
{
- nErased += EraseTx(maybeErase->second.tx->GetHash());
+ nErased += _EraseTx(maybeErase->second.tx->GetHash());
}
}
if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer);
@@ -104,7 +111,7 @@ void TxOrphanage::EraseForPeer(NodeId peer)
void TxOrphanage::LimitOrphans(unsigned int max_orphans)
{
- AssertLockHeld(g_cs_orphans);
+ LOCK(m_mutex);
unsigned int nEvicted = 0;
static int64_t nNextSweep;
@@ -118,7 +125,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans)
{
std::map<uint256, OrphanTx>::iterator maybeErase = iter++;
if (maybeErase->second.nTimeExpire <= nNow) {
- nErased += EraseTx(maybeErase->second.tx->GetHash());
+ nErased += _EraseTx(maybeErase->second.tx->GetHash());
} else {
nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime);
}
@@ -132,19 +139,25 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans)
{
// Evict a random orphan:
size_t randompos = rng.randrange(m_orphan_list.size());
- EraseTx(m_orphan_list[randompos]->first);
+ _EraseTx(m_orphan_list[randompos]->first);
++nEvicted;
}
if (nEvicted > 0) LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted);
}
-void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>& orphan_work_set) const
+void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx)
{
- AssertLockHeld(g_cs_orphans);
+ LOCK(m_mutex);
+
+
for (unsigned int i = 0; i < tx.vout.size(); i++) {
const auto it_by_prev = m_outpoint_to_orphan_it.find(COutPoint(tx.GetHash(), i));
if (it_by_prev != m_outpoint_to_orphan_it.end()) {
for (const auto& elem : it_by_prev->second) {
+ // Get this source peer's work set, emplacing an empty set if it didn't exist
+ // (note: if this peer wasn't still connected, we would have removed the orphan tx already)
+ std::set<uint256>& orphan_work_set = m_peer_work_set.try_emplace(elem->second.fromPeer).first->second;
+ // Add this tx to the work set
orphan_work_set.insert(elem->first);
}
}
@@ -153,7 +166,7 @@ void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>
bool TxOrphanage::HaveTx(const GenTxid& gtxid) const
{
- LOCK(g_cs_orphans);
+ LOCK(m_mutex);
if (gtxid.IsWtxid()) {
return m_wtxid_to_orphan_it.count(gtxid.GetHash());
} else {
@@ -161,18 +174,41 @@ bool TxOrphanage::HaveTx(const GenTxid& gtxid) const
}
}
-std::pair<CTransactionRef, NodeId> TxOrphanage::GetTx(const uint256& txid) const
+CTransactionRef TxOrphanage::GetTxToReconsider(NodeId peer)
{
- AssertLockHeld(g_cs_orphans);
+ LOCK(m_mutex);
+
+ auto work_set_it = m_peer_work_set.find(peer);
+ if (work_set_it != m_peer_work_set.end()) {
+ auto& work_set = work_set_it->second;
+ while (!work_set.empty()) {
+ uint256 txid = *work_set.begin();
+ work_set.erase(work_set.begin());
+
+ const auto orphan_it = m_orphans.find(txid);
+ if (orphan_it != m_orphans.end()) {
+ return orphan_it->second.tx;
+ }
+ }
+ }
+ return nullptr;
+}
- const auto it = m_orphans.find(txid);
- if (it == m_orphans.end()) return {nullptr, -1};
- return {it->second.tx, it->second.fromPeer};
+bool TxOrphanage::HaveTxToReconsider(NodeId peer)
+{
+ LOCK(m_mutex);
+
+ auto work_set_it = m_peer_work_set.find(peer);
+ if (work_set_it != m_peer_work_set.end()) {
+ auto& work_set = work_set_it->second;
+ return !work_set.empty();
+ }
+ return false;
}
void TxOrphanage::EraseForBlock(const CBlock& block)
{
- LOCK(g_cs_orphans);
+ LOCK(m_mutex);
std::vector<uint256> vOrphanErase;
@@ -195,7 +231,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block)
if (vOrphanErase.size()) {
int nErased = 0;
for (const uint256& orphanHash : vOrphanErase) {
- nErased += EraseTx(orphanHash);
+ nErased += _EraseTx(orphanHash);
}
LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased);
}
diff --git a/src/txorphanage.h b/src/txorphanage.h
index 9363e6f733..45276c6c98 100644
--- a/src/txorphanage.h
+++ b/src/txorphanage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,8 +10,8 @@
#include <primitives/transaction.h>
#include <sync.h>
-/** Guards orphan transactions and extra txs for compact blocks */
-extern RecursiveMutex g_cs_orphans;
+#include <map>
+#include <set>
/** A class to track orphan transactions (failed on TX_MISSING_INPUTS)
* Since we cannot distinguish orphans from bad transactions with
@@ -21,40 +21,47 @@ extern RecursiveMutex g_cs_orphans;
class TxOrphanage {
public:
/** Add a new orphan transaction */
- bool AddTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
+ bool AddTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
/** Check if we already have an orphan transaction (by txid or wtxid) */
- bool HaveTx(const GenTxid& gtxid) const LOCKS_EXCLUDED(::g_cs_orphans);
+ bool HaveTx(const GenTxid& gtxid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
- /** Get an orphan transaction and its originating peer
- * (Transaction ref will be nullptr if not found)
+ /** Extract a transaction from a peer's work set
+ * Returns nullptr if there are no transactions to work on.
+ * Otherwise returns the transaction reference, and removes
+ * it from the work set.
*/
- std::pair<CTransactionRef, NodeId> GetTx(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
+ CTransactionRef GetTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
/** Erase an orphan by txid */
- int EraseTx(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
+ int EraseTx(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
/** Erase all orphans announced by a peer (eg, after that peer disconnects) */
- void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
+ void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
/** Erase all orphans included in or invalidated by a new block */
- void EraseForBlock(const CBlock& block) LOCKS_EXCLUDED(::g_cs_orphans);
+ void EraseForBlock(const CBlock& block) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
/** Limit the orphanage to the given maximum */
- void LimitOrphans(unsigned int max_orphans) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
+ void LimitOrphans(unsigned int max_orphans) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
- /** Add any orphans that list a particular tx as a parent into a peer's work set
- * (ie orphans that may have found their final missing parent, and so should be reconsidered for the mempool) */
- void AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>& orphan_work_set) const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
+ /** Add any orphans that list a particular tx as a parent into the from peer's work set */
+ void AddChildrenToWorkSet(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);;
+
+ /** Does this peer have any work to do? */
+ bool HaveTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);;
/** Return how many entries exist in the orphange */
- size_t Size() LOCKS_EXCLUDED(::g_cs_orphans)
+ size_t Size() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
- LOCK(::g_cs_orphans);
+ LOCK(m_mutex);
return m_orphans.size();
}
protected:
+ /** Guards orphan transactions */
+ mutable Mutex m_mutex;
+
struct OrphanTx {
CTransactionRef tx;
NodeId fromPeer;
@@ -64,7 +71,10 @@ protected:
/** Map from txid to orphan transaction record. Limited by
* -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */
- std::map<uint256, OrphanTx> m_orphans GUARDED_BY(g_cs_orphans);
+ std::map<uint256, OrphanTx> m_orphans GUARDED_BY(m_mutex);
+
+ /** Which peer provided the orphans that need to be reconsidered */
+ std::map<NodeId, std::set<uint256>> m_peer_work_set GUARDED_BY(m_mutex);
using OrphanMap = decltype(m_orphans);
@@ -79,14 +89,17 @@ protected:
/** Index from the parents' COutPoint into the m_orphans. Used
* to remove orphan transactions from the m_orphans */
- std::map<COutPoint, std::set<OrphanMap::iterator, IteratorComparator>> m_outpoint_to_orphan_it GUARDED_BY(g_cs_orphans);
+ std::map<COutPoint, std::set<OrphanMap::iterator, IteratorComparator>> m_outpoint_to_orphan_it GUARDED_BY(m_mutex);
/** Orphan transactions in vector for quick random eviction */
- std::vector<OrphanMap::iterator> m_orphan_list GUARDED_BY(g_cs_orphans);
+ std::vector<OrphanMap::iterator> m_orphan_list GUARDED_BY(m_mutex);
/** Index from wtxid into the m_orphans to lookup orphan
* transactions using their witness ids. */
- std::map<uint256, OrphanMap::iterator> m_wtxid_to_orphan_it GUARDED_BY(g_cs_orphans);
+ std::map<uint256, OrphanMap::iterator> m_wtxid_to_orphan_it GUARDED_BY(m_mutex);
+
+ /** Erase an orphan by txid */
+ int _EraseTx(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
};
#endif // BITCOIN_TXORPHANAGE_H
diff --git a/src/uint256.cpp b/src/uint256.cpp
index cd9cbb566a..7f81c3c448 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -7,15 +7,6 @@
#include <util/strencodings.h>
-#include <string.h>
-
-template <unsigned int BITS>
-base_blob<BITS>::base_blob(const std::vector<unsigned char>& vch)
-{
- assert(vch.size() == sizeof(m_data));
- memcpy(m_data, vch.data(), sizeof(m_data));
-}
-
template <unsigned int BITS>
std::string base_blob<BITS>::GetHex() const
{
@@ -29,7 +20,7 @@ std::string base_blob<BITS>::GetHex() const
template <unsigned int BITS>
void base_blob<BITS>::SetHex(const char* psz)
{
- memset(m_data, 0, sizeof(m_data));
+ std::fill(m_data.begin(), m_data.end(), 0);
// skip leading spaces
while (IsSpace(*psz))
@@ -43,7 +34,7 @@ void base_blob<BITS>::SetHex(const char* psz)
size_t digits = 0;
while (::HexDigit(psz[digits]) != -1)
digits++;
- unsigned char* p1 = (unsigned char*)m_data;
+ unsigned char* p1 = m_data.data();
unsigned char* pend = p1 + WIDTH;
while (digits > 0 && p1 < pend) {
*p1 = ::HexDigit(psz[--digits]);
@@ -67,14 +58,12 @@ std::string base_blob<BITS>::ToString() const
}
// Explicit instantiations for base_blob<160>
-template base_blob<160>::base_blob(const std::vector<unsigned char>&);
template std::string base_blob<160>::GetHex() const;
template std::string base_blob<160>::ToString() const;
template void base_blob<160>::SetHex(const char*);
template void base_blob<160>::SetHex(const std::string&);
// Explicit instantiations for base_blob<256>
-template base_blob<256>::base_blob(const std::vector<unsigned char>&);
template std::string base_blob<256>::GetHex() const;
template std::string base_blob<256>::ToString() const;
template void base_blob<256>::SetHex(const char*);
diff --git a/src/uint256.h b/src/uint256.h
index e74b9ff7b1..1cc3721487 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,11 +9,12 @@
#include <crypto/common.h>
#include <span.h>
-#include <assert.h>
+#include <algorithm>
+#include <array>
+#include <cassert>
#include <cstring>
#include <stdint.h>
#include <string>
-#include <vector>
/** Template base class for fixed-sized opaque blobs. */
template<unsigned int BITS>
@@ -21,7 +22,9 @@ class base_blob
{
protected:
static constexpr int WIDTH = BITS / 8;
- uint8_t m_data[WIDTH];
+ std::array<uint8_t, WIDTH> m_data;
+ static_assert(WIDTH == sizeof(m_data), "Sanity check");
+
public:
/* construct 0 value by default */
constexpr base_blob() : m_data() {}
@@ -29,64 +32,47 @@ public:
/* constructor for constants between 1 and 255 */
constexpr explicit base_blob(uint8_t v) : m_data{v} {}
- explicit base_blob(const std::vector<unsigned char>& vch);
+ constexpr explicit base_blob(Span<const unsigned char> vch)
+ {
+ assert(vch.size() == WIDTH);
+ std::copy(vch.begin(), vch.end(), m_data.begin());
+ }
- bool IsNull() const
+ constexpr bool IsNull() const
{
- for (int i = 0; i < WIDTH; i++)
- if (m_data[i] != 0)
- return false;
- return true;
+ return std::all_of(m_data.begin(), m_data.end(), [](uint8_t val) {
+ return val == 0;
+ });
}
- void SetNull()
+ constexpr void SetNull()
{
- memset(m_data, 0, sizeof(m_data));
+ std::fill(m_data.begin(), m_data.end(), 0);
}
- inline int Compare(const base_blob& other) const { return memcmp(m_data, other.m_data, sizeof(m_data)); }
+ constexpr int Compare(const base_blob& other) const { return std::memcmp(m_data.data(), other.m_data.data(), WIDTH); }
- friend inline bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; }
- friend inline bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; }
- friend inline bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; }
+ friend constexpr bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; }
+ friend constexpr bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; }
+ friend constexpr bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; }
std::string GetHex() const;
void SetHex(const char* psz);
void SetHex(const std::string& str);
std::string ToString() const;
- const unsigned char* data() const { return m_data; }
- unsigned char* data() { return m_data; }
+ constexpr const unsigned char* data() const { return m_data.data(); }
+ constexpr unsigned char* data() { return m_data.data(); }
- unsigned char* begin()
- {
- return &m_data[0];
- }
+ constexpr unsigned char* begin() { return m_data.data(); }
+ constexpr unsigned char* end() { return m_data.data() + WIDTH; }
- unsigned char* end()
- {
- return &m_data[WIDTH];
- }
+ constexpr const unsigned char* begin() const { return m_data.data(); }
+ constexpr const unsigned char* end() const { return m_data.data() + WIDTH; }
- const unsigned char* begin() const
- {
- return &m_data[0];
- }
+ static constexpr unsigned int size() { return WIDTH; }
- const unsigned char* end() const
- {
- return &m_data[WIDTH];
- }
-
- static constexpr unsigned int size()
- {
- return sizeof(m_data);
- }
-
- uint64_t GetUint64(int pos) const
- {
- return ReadLE64(m_data + pos * 8);
- }
+ constexpr uint64_t GetUint64(int pos) const { return ReadLE64(m_data.data() + pos * 8); }
template<typename Stream>
void Serialize(Stream& s) const
@@ -107,8 +93,8 @@ public:
*/
class uint160 : public base_blob<160> {
public:
- constexpr uint160() {}
- explicit uint160(const std::vector<unsigned char>& vch) : base_blob<160>(vch) {}
+ constexpr uint160() = default;
+ constexpr explicit uint160(Span<const unsigned char> vch) : base_blob<160>(vch) {}
};
/** 256-bit opaque blob.
@@ -118,9 +104,9 @@ public:
*/
class uint256 : public base_blob<256> {
public:
- constexpr uint256() {}
+ constexpr uint256() = default;
constexpr explicit uint256(uint8_t v) : base_blob<256>(v) {}
- explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {}
+ constexpr explicit uint256(Span<const unsigned char> vch) : base_blob<256>(vch) {}
static const uint256 ZERO;
static const uint256 ONE;
};
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index 850d0a1cbc..d501c3fb69 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -12,6 +12,7 @@
#include <map>
#include <stdexcept>
#include <string>
+#include <string_view>
#include <type_traits>
#include <vector>
@@ -25,10 +26,7 @@ public:
};
UniValue() { typ = VNULL; }
- UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
- typ = initialType;
- val = initialStr;
- }
+ UniValue(UniValue::VType type, std::string str = {}) : typ{type}, val{std::move(str)} {}
template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
std::enable_if_t<std::is_floating_point_v<T> || // setFloat
std::is_same_v<bool, T> || // setBool
@@ -54,12 +52,12 @@ public:
void setNull();
void setBool(bool val);
- void setNumStr(const std::string& val);
+ void setNumStr(std::string str);
void setInt(uint64_t val);
void setInt(int64_t val);
void setInt(int val_) { return setInt(int64_t{val_}); }
void setFloat(double val);
- void setStr(const std::string& val);
+ void setStr(std::string str);
void setArray();
void setObject();
@@ -69,7 +67,6 @@ public:
size_t size() const { return values.size(); }
- bool getBool() const { return isTrue(); }
void getObjMap(std::map<std::string,UniValue>& kv) const;
bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const;
const UniValue& operator[](const std::string& key) const;
@@ -99,9 +96,7 @@ public:
bool read(const char *raw, size_t len);
bool read(const char *raw) { return read(raw, strlen(raw)); }
- bool read(const std::string& rawStr) {
- return read(rawStr.data(), rawStr.size());
- }
+ bool read(std::string_view raw) { return read(raw.data(), raw.size()); }
private:
UniValue::VType typ;
diff --git a/src/univalue/include/univalue_utffilter.h b/src/univalue/include/univalue_utffilter.h
index f688eaaa30..41d8e6bb05 100644
--- a/src/univalue/include/univalue_utffilter.h
+++ b/src/univalue/include/univalue_utffilter.h
@@ -13,8 +13,8 @@
class JSONUTF8StringFilter
{
public:
- explicit JSONUTF8StringFilter(std::string &s):
- str(s), is_valid(true), codepoint(0), state(0), surpair(0)
+ explicit JSONUTF8StringFilter(std::string& s)
+ : str(s)
{
}
// Write single 8-bit char (may be part of UTF-8 sequence)
@@ -79,10 +79,10 @@ public:
}
private:
std::string &str;
- bool is_valid;
+ bool is_valid{true};
// Current UTF-8 decoding state
- unsigned int codepoint;
- int state; // Top bit to be filled in for next UTF-8 byte, or 0
+ unsigned int codepoint{0};
+ int state{0}; // Top bit to be filled in for next UTF-8 byte, or 0
// Keep track of the following state to handle the following section of
// RFC4627:
@@ -94,7 +94,7 @@ private:
// "\uD834\uDD1E".
//
// Two subsequent \u.... may have to be replaced with one actual codepoint.
- unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0
+ unsigned int surpair{0}; // First half of open UTF-16 surrogate pair, or 0
void append_codepoint(unsigned int codepoint_)
{
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index 4448981d3e..5aa39edb75 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -44,15 +44,15 @@ static bool validNumStr(const std::string& s)
return (tt == JTOK_NUMBER);
}
-void UniValue::setNumStr(const std::string& val_)
+void UniValue::setNumStr(std::string str)
{
- if (!validNumStr(val_)) {
- throw std::runtime_error{"The string '" + val_ + "' is not a valid JSON number"};
+ if (!validNumStr(str)) {
+ throw std::runtime_error{"The string '" + str + "' is not a valid JSON number"};
}
clear();
typ = VNUM;
- val = val_;
+ val = std::move(str);
}
void UniValue::setInt(uint64_t val_)
@@ -82,11 +82,11 @@ void UniValue::setFloat(double val_)
return setNumStr(oss.str());
}
-void UniValue::setStr(const std::string& val_)
+void UniValue::setStr(std::string str)
{
clear();
typ = VSTR;
- val = val_;
+ val = std::move(str);
}
void UniValue::setArray()
diff --git a/src/univalue/lib/univalue_get.cpp b/src/univalue/lib/univalue_get.cpp
index 5c58f388dd..037449ca08 100644
--- a/src/univalue/lib/univalue_get.cpp
+++ b/src/univalue/lib/univalue_get.cpp
@@ -60,7 +60,7 @@ const std::vector<UniValue>& UniValue::getValues() const
bool UniValue::get_bool() const
{
checkType(VBOOL);
- return getBool();
+ return isTrue();
}
const std::string& UniValue::get_str() const
diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp
index 94d7343ff3..5ddf300393 100644
--- a/src/univalue/test/object.cpp
+++ b/src/univalue/test/object.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2014 BitPay Inc.
-// Copyright (c) 2014-2016 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
@@ -11,6 +11,7 @@
#include <memory>
#include <stdexcept>
#include <string>
+#include <string_view>
#include <vector>
#define BOOST_CHECK(expr) assert(expr)
@@ -160,6 +161,14 @@ void univalue_set()
BOOST_CHECK(v.isStr());
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
+ {
+ std::string_view sv{"ab\0c", 4};
+ UniValue j{sv};
+ BOOST_CHECK(j.isStr());
+ BOOST_CHECK_EQUAL(j.getValStr(), sv);
+ BOOST_CHECK_EQUAL(j.write(), "\"ab\\u0000c\"");
+ }
+
v.setFloat(-1.01);
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
@@ -184,13 +193,13 @@ void univalue_set()
BOOST_CHECK_EQUAL(v.isBool(), true);
BOOST_CHECK_EQUAL(v.isTrue(), false);
BOOST_CHECK_EQUAL(v.isFalse(), true);
- BOOST_CHECK_EQUAL(v.getBool(), false);
+ BOOST_CHECK_EQUAL(v.get_bool(), false);
v.setBool(true);
BOOST_CHECK_EQUAL(v.isBool(), true);
BOOST_CHECK_EQUAL(v.isTrue(), true);
BOOST_CHECK_EQUAL(v.isFalse(), false);
- BOOST_CHECK_EQUAL(v.getBool(), true);
+ BOOST_CHECK_EQUAL(v.get_bool(), true);
BOOST_CHECK_THROW(v.setNumStr("zombocom"), std::runtime_error);
diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp
index 33258d9962..4b548c5a4d 100644
--- a/src/util/asmap.cpp
+++ b/src/util/asmap.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/bip32.cpp b/src/util/bip32.cpp
index 796af4a544..c4b7120394 100644
--- a/src/util/bip32.cpp
+++ b/src/util/bip32.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/bip32.h b/src/util/bip32.h
index 0872bc88de..b720cb5638 100644
--- a/src/util/bip32.h
+++ b/src/util/bip32.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/bytevectorhash.cpp b/src/util/bytevectorhash.cpp
index 6d777613e6..29be138eeb 100644
--- a/src/util/bytevectorhash.cpp
+++ b/src/util/bytevectorhash.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/bytevectorhash.h b/src/util/bytevectorhash.h
index c2322b8daf..079385678c 100644
--- a/src/util/bytevectorhash.h
+++ b/src/util/bytevectorhash.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/check.cpp b/src/util/check.cpp
index 2a9f885560..795dce7124 100644
--- a/src/util/check.cpp
+++ b/src/util/check.cpp
@@ -4,9 +4,32 @@
#include <util/check.h>
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <clientversion.h>
#include <tinyformat.h>
-void assertion_fail(const char* file, int line, const char* func, const char* assertion)
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include <string_view>
+
+std::string StrFormatInternalBug(std::string_view msg, std::string_view file, int line, std::string_view func)
+{
+ return strprintf("Internal bug detected: \"%s\"\n%s:%d (%s)\n"
+ "%s %s\n"
+ "Please report this issue here: %s\n",
+ msg, file, line, func, PACKAGE_NAME, FormatFullVersion(), PACKAGE_BUGREPORT);
+}
+
+NonFatalCheckError::NonFatalCheckError(std::string_view msg, std::string_view file, int line, std::string_view func)
+ : std::runtime_error{StrFormatInternalBug(msg, file, line, func)}
+{
+}
+
+void assertion_fail(std::string_view file, int line, std::string_view func, std::string_view assertion)
{
auto str = strprintf("%s:%s %s: Assertion `%s' failed.\n", file, line, func, assertion);
fwrite(str.data(), 1, str.size(), stderr);
diff --git a/src/util/check.h b/src/util/check.h
index aca957925a..7ddcebf506 100644
--- a/src/util/check.h
+++ b/src/util/check.h
@@ -1,34 +1,33 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UTIL_CHECK_H
#define BITCOIN_UTIL_CHECK_H
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
-#include <tinyformat.h>
+#include <attributes.h>
#include <stdexcept>
+#include <string>
+#include <string_view>
+#include <utility>
+
+std::string StrFormatInternalBug(std::string_view msg, std::string_view file, int line, std::string_view func);
class NonFatalCheckError : public std::runtime_error
{
- using std::runtime_error::runtime_error;
+public:
+ NonFatalCheckError(std::string_view msg, std::string_view file, int line, std::string_view func);
};
-#define format_internal_error(msg, file, line, func, report) \
- strprintf("Internal bug detected: \"%s\"\n%s:%d (%s)\nPlease report this issue here: %s\n", \
- msg, file, line, func, report)
+#define STR_INTERNAL_BUG(msg) StrFormatInternalBug((msg), __FILE__, __LINE__, __func__)
/** Helper for CHECK_NONFATAL() */
template <typename T>
-T&& inline_check_non_fatal(T&& val, const char* file, int line, const char* func, const char* assertion)
+T&& inline_check_non_fatal(LIFETIMEBOUND T&& val, const char* file, int line, const char* func, const char* assertion)
{
- if (!(val)) {
- throw NonFatalCheckError(
- format_internal_error(assertion, file, line, func, PACKAGE_BUGREPORT));
+ if (!val) {
+ throw NonFatalCheckError{assertion, file, line, func};
}
return std::forward<T>(val);
}
@@ -52,11 +51,11 @@ T&& inline_check_non_fatal(T&& val, const char* file, int line, const char* func
#endif
/** Helper for Assert() */
-void assertion_fail(const char* file, int line, const char* func, const char* assertion);
+void assertion_fail(std::string_view file, int line, std::string_view func, std::string_view assertion);
/** Helper for Assert()/Assume() */
template <bool IS_ASSERT, typename T>
-T&& inline_assertion_check(T&& val, [[maybe_unused]] const char* file, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* assertion)
+T&& inline_assertion_check(LIFETIMEBOUND T&& val, [[maybe_unused]] const char* file, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* assertion)
{
if constexpr (IS_ASSERT
#ifdef ABORT_ON_FAILED_ASSUME
@@ -87,11 +86,9 @@ T&& inline_assertion_check(T&& val, [[maybe_unused]] const char* file, [[maybe_u
/**
* NONFATAL_UNREACHABLE() is a macro that is used to mark unreachable code. It throws a NonFatalCheckError.
- * This is used to mark code that is not yet implemented or is not yet reachable.
*/
#define NONFATAL_UNREACHABLE() \
throw NonFatalCheckError( \
- format_internal_error("Unreachable code reached (non-fatal)", \
- __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT))
+ "Unreachable code reached (non-fatal)", __FILE__, __LINE__, __func__)
#endif // BITCOIN_UTIL_CHECK_H
diff --git a/src/util/epochguard.h b/src/util/epochguard.h
index 7f6477fb3b..145f4dc132 100644
--- a/src/util/epochguard.h
+++ b/src/util/epochguard.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/error.cpp b/src/util/error.cpp
index 33a35a6d59..309877d067 100644
--- a/src/util/error.cpp
+++ b/src/util/error.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2010-2021 The Bitcoin Core developers
+// Copyright (c) 2010-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -33,6 +33,8 @@ bilingual_str TransactionErrorString(const TransactionError err)
return Untranslated("Specified sighash value does not match value stored in PSBT");
case TransactionError::MAX_FEE_EXCEEDED:
return Untranslated("Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)");
+ case TransactionError::MAX_BURN_EXCEEDED:
+ return Untranslated("Unspendable output exceeds maximum configured by user (maxburnamount)");
case TransactionError::EXTERNAL_SIGNER_NOT_FOUND:
return Untranslated("External signer not found");
case TransactionError::EXTERNAL_SIGNER_FAILED:
@@ -49,6 +51,11 @@ bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBi
return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind);
}
+bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& invalid_value)
+{
+ return strprintf(_("Invalid port specified in %s: '%s'"), optname, invalid_value);
+}
+
bilingual_str AmountHighWarn(const std::string& optname)
{
return strprintf(_("%s is set very high!"), optname);
diff --git a/src/util/error.h b/src/util/error.h
index 0429de651a..a52a8f47de 100644
--- a/src/util/error.h
+++ b/src/util/error.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010-2020 The Bitcoin Core developers
+// Copyright (c) 2010-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -30,6 +30,7 @@ enum class TransactionError {
PSBT_MISMATCH,
SIGHASH_MISMATCH,
MAX_FEE_EXCEEDED,
+ MAX_BURN_EXCEEDED,
EXTERNAL_SIGNER_NOT_FOUND,
EXTERNAL_SIGNER_FAILED,
INVALID_PACKAGE,
@@ -39,6 +40,8 @@ bilingual_str TransactionErrorString(const TransactionError error);
bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBind);
+bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& strPort);
+
bilingual_str AmountHighWarn(const std::string& optname);
bilingual_str AmountErrMsg(const std::string& optname, const std::string& strValue);
diff --git a/src/util/exception.cpp b/src/util/exception.cpp
new file mode 100644
index 0000000000..d961f0540f
--- /dev/null
+++ b/src/util/exception.cpp
@@ -0,0 +1,41 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2023 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <util/exception.h>
+
+#include <logging.h>
+#include <tinyformat.h>
+
+#include <exception>
+#include <iostream>
+#include <string>
+#include <typeinfo>
+
+#ifdef WIN32
+#include <windows.h>
+#endif // WIN32
+
+static std::string FormatException(const std::exception* pex, std::string_view thread_name)
+{
+#ifdef WIN32
+ char pszModule[MAX_PATH] = "";
+ GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
+#else
+ const char* pszModule = "bitcoin";
+#endif
+ if (pex)
+ return strprintf(
+ "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, thread_name);
+ else
+ return strprintf(
+ "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, thread_name);
+}
+
+void PrintExceptionContinue(const std::exception* pex, std::string_view thread_name)
+{
+ std::string message = FormatException(pex, thread_name);
+ LogPrintf("\n\n************************\n%s\n", message);
+ tfm::format(std::cerr, "\n\n************************\n%s\n", message);
+}
diff --git a/src/util/exception.h b/src/util/exception.h
new file mode 100644
index 0000000000..946eb2644c
--- /dev/null
+++ b/src/util/exception.h
@@ -0,0 +1,14 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2023 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTIL_EXCEPTION_H
+#define BITCOIN_UTIL_EXCEPTION_H
+
+#include <exception>
+#include <string_view>
+
+void PrintExceptionContinue(const std::exception* pex, std::string_view thread_name);
+
+#endif // BITCOIN_UTIL_EXCEPTION_H
diff --git a/src/util/fastrange.h b/src/util/fastrange.h
index 77cb883ce0..87a2415976 100644
--- a/src/util/fastrange.h
+++ b/src/util/fastrange.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/fees.cpp b/src/util/fees.cpp
index cbefe18dbb..8ada02ce54 100644
--- a/src/util/fees.cpp
+++ b/src/util/fees.cpp
@@ -49,7 +49,7 @@ std::string FeeModes(const std::string& delimiter)
return Join(FeeModeMap(), delimiter, [&](const std::pair<std::string, FeeEstimateMode>& i) { return i.first; });
}
-const std::string InvalidEstimateModeErrorMessage()
+std::string InvalidEstimateModeErrorMessage()
{
return "Invalid estimate_mode parameter, must be one of: \"" + FeeModes("\", \"") + "\"";
}
diff --git a/src/util/fees.h b/src/util/fees.h
index 9ef2389d3e..10ba1e4f85 100644
--- a/src/util/fees.h
+++ b/src/util/fees.h
@@ -13,6 +13,6 @@ enum class FeeReason;
bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
std::string StringForFeeReason(FeeReason reason);
std::string FeeModes(const std::string& delimiter);
-const std::string InvalidEstimateModeErrorMessage();
+std::string InvalidEstimateModeErrorMessage();
#endif // BITCOIN_UTIL_FEES_H
diff --git a/src/util/getuniquepath.cpp b/src/util/getuniquepath.cpp
index 1d8e511c83..42c5dee0ed 100644
--- a/src/util/getuniquepath.cpp
+++ b/src/util/getuniquepath.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/golombrice.h b/src/util/golombrice.h
index 4ff4f6d7e5..63402c5e4d 100644
--- a/src/util/golombrice.h
+++ b/src/util/golombrice.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/hasher.cpp b/src/util/hasher.cpp
index a80f20c894..81e9b990e1 100644
--- a/src/util/hasher.cpp
+++ b/src/util/hasher.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,7 +9,10 @@
SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand<uint64_t>()), k1(GetRand<uint64_t>()) {}
-SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand<uint64_t>()), k1(GetRand<uint64_t>()) {}
+SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) :
+ k0(deterministic ? 0x8e819f2607a18de6 : GetRand<uint64_t>()),
+ k1(deterministic ? 0xf4020d2e3983b0eb : GetRand<uint64_t>())
+{}
SaltedSipHasher::SaltedSipHasher() : m_k0(GetRand<uint64_t>()), m_k1(GetRand<uint64_t>()) {}
diff --git a/src/util/hasher.h b/src/util/hasher.h
index 426b8990e6..506ae9415d 100644
--- a/src/util/hasher.h
+++ b/src/util/hasher.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -36,7 +36,7 @@ private:
const uint64_t k0, k1;
public:
- SaltedOutpointHasher();
+ SaltedOutpointHasher(bool deterministic = false);
/**
* Having the hash noexcept allows libstdc++'s unordered_map to recalculate
diff --git a/src/util/macros.h b/src/util/macros.h
index bf6ba665dc..11aa683152 100644
--- a/src/util/macros.h
+++ b/src/util/macros.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/message.cpp b/src/util/message.cpp
index 7d6f3403f4..f8ea8247d5 100644
--- a/src/util/message.cpp
+++ b/src/util/message.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/message.h b/src/util/message.h
index 1b7febe60a..d0e2422574 100644
--- a/src/util/message.h
+++ b/src/util/message.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp
index d9e6cef600..9181329afc 100644
--- a/src/util/moneystr.cpp
+++ b/src/util/moneystr.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -34,7 +34,7 @@ std::string FormatMoney(const CAmount n)
str.erase(str.size()-nTrim, nTrim);
if (n < 0)
- str.insert((unsigned int)0, 1, '-');
+ str.insert(uint32_t{0}, 1, '-');
return str;
}
diff --git a/src/util/moneystr.h b/src/util/moneystr.h
index 3d33bd7f99..dba0ce676a 100644
--- a/src/util/moneystr.h
+++ b/src/util/moneystr.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/overflow.h b/src/util/overflow.h
index 6b7dd1e8fd..7e0cce6c27 100644
--- a/src/util/overflow.h
+++ b/src/util/overflow.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/readwritefile.cpp b/src/util/readwritefile.cpp
index 3ec08119e7..cc555adf45 100644
--- a/src/util/readwritefile.cpp
+++ b/src/util/readwritefile.cpp
@@ -1,8 +1,10 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <util/readwritefile.h>
+
#include <fs.h>
#include <algorithm>
@@ -11,7 +13,7 @@
#include <string>
#include <utility>
-std::pair<bool,std::string> ReadBinaryFile(const fs::path &filename, size_t maxsize=std::numeric_limits<size_t>::max())
+std::pair<bool,std::string> ReadBinaryFile(const fs::path &filename, size_t maxsize)
{
FILE *f = fsbridge::fopen(filename, "rb");
if (f == nullptr)
diff --git a/src/util/serfloat.h b/src/util/serfloat.h
index 343ccb9d3a..0dbba6ee03 100644
--- a/src/util/serfloat.h
+++ b/src/util/serfloat.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/settings.cpp b/src/util/settings.cpp
index 924a9cfab2..a2e30098dc 100644
--- a/src/util/settings.cpp
+++ b/src/util/settings.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -99,6 +99,8 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va
auto inserted = values.emplace(in_keys[i], in_values[i]);
if (!inserted.second) {
errors.emplace_back(strprintf("Found duplicate key %s in settings file %s", in_keys[i], fs::PathToString(path)));
+ values.clear();
+ break;
}
}
return errors.empty();
diff --git a/src/util/settings.h b/src/util/settings.h
index e97158dc09..b0d8acb711 100644
--- a/src/util/settings.h
+++ b/src/util/settings.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index 125dbc7f18..53d20bdf19 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -1,14 +1,14 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 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 <compat/compat.h>
#include <logging.h>
-#include <threadinterrupt.h>
#include <tinyformat.h>
#include <util/sock.h>
#include <util/syserror.h>
#include <util/system.h>
+#include <util/threadinterrupt.h>
#include <util/time.h>
#include <memory>
@@ -117,6 +117,34 @@ int Sock::GetSockName(sockaddr* name, socklen_t* name_len) const
return getsockname(m_socket, name, name_len);
}
+bool Sock::SetNonBlocking() const
+{
+#ifdef WIN32
+ u_long on{1};
+ if (ioctlsocket(m_socket, FIONBIO, &on) == SOCKET_ERROR) {
+ return false;
+ }
+#else
+ const int flags{fcntl(m_socket, F_GETFL, 0)};
+ if (flags == SOCKET_ERROR) {
+ return false;
+ }
+ if (fcntl(m_socket, F_SETFL, flags | O_NONBLOCK) == SOCKET_ERROR) {
+ return false;
+ }
+#endif
+ return true;
+}
+
+bool Sock::IsSelectable() const
+{
+#if defined(USE_POLL) || defined(WIN32)
+ return true;
+#else
+ return m_socket < FD_SETSIZE;
+#endif
+}
+
bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
{
// We need a `shared_ptr` owning `this` for `WaitMany()`, but don't want
@@ -185,10 +213,10 @@ bool Sock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per
SOCKET socket_max{0};
for (const auto& [sock, events] : events_per_sock) {
- const auto& s = sock->m_socket;
- if (!IsSelectableSocket(s)) {
+ if (!sock->IsSelectable()) {
return false;
}
+ const auto& s = sock->m_socket;
if (events.requested & RECV) {
FD_SET(s, &recv);
}
diff --git a/src/util/sock.h b/src/util/sock.h
index 38a7dc80d6..6bac2dfd34 100644
--- a/src/util/sock.h
+++ b/src/util/sock.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,7 +6,7 @@
#define BITCOIN_UTIL_SOCK_H
#include <compat/compat.h>
-#include <threadinterrupt.h>
+#include <util/threadinterrupt.h>
#include <util/time.h>
#include <chrono>
@@ -133,6 +133,18 @@ public:
*/
[[nodiscard]] virtual int GetSockName(sockaddr* name, socklen_t* name_len) const;
+ /**
+ * Set the non-blocking option on the socket.
+ * @return true if set successfully
+ */
+ [[nodiscard]] virtual bool SetNonBlocking() const;
+
+ /**
+ * Check if the underlying socket can be used for `select(2)` (or the `Wait()` method).
+ * @return true if selectable
+ */
+ [[nodiscard]] virtual bool IsSelectable() const;
+
using Event = uint8_t;
/**
@@ -169,9 +181,9 @@ public:
* Auxiliary requested/occurred events to wait for in `WaitMany()`.
*/
struct Events {
- explicit Events(Event req) : requested{req}, occurred{0} {}
+ explicit Events(Event req) : requested{req} {}
Event requested;
- Event occurred;
+ Event occurred{0};
};
struct HashSharedPtrSock {
diff --git a/src/util/spanparsing.cpp b/src/util/spanparsing.cpp
index 565c867e18..c464fc2b87 100644
--- a/src/util/spanparsing.cpp
+++ b/src/util/spanparsing.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/spanparsing.h b/src/util/spanparsing.h
index 51795271de..765fe13aca 100644
--- a/src/util/spanparsing.h
+++ b/src/util/spanparsing.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index b5ac151374..a54f408496 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -78,27 +78,29 @@ bool IsHexNumber(std::string_view str)
}
template <typename Byte>
-std::vector<Byte> ParseHex(std::string_view str)
+std::optional<std::vector<Byte>> TryParseHex(std::string_view str)
{
std::vector<Byte> vch;
auto it = str.begin();
- while (it != str.end() && it + 1 != str.end()) {
+ while (it != str.end()) {
if (IsSpace(*it)) {
++it;
continue;
}
auto c1 = HexDigit(*(it++));
+ if (it == str.end()) return std::nullopt;
auto c2 = HexDigit(*(it++));
- if (c1 < 0 || c2 < 0) break;
+ if (c1 < 0 || c2 < 0) return std::nullopt;
vch.push_back(Byte(c1 << 4) | Byte(c2));
}
return vch;
}
-template std::vector<std::byte> ParseHex(std::string_view);
-template std::vector<uint8_t> ParseHex(std::string_view);
+template std::optional<std::vector<std::byte>> TryParseHex(std::string_view);
+template std::optional<std::vector<uint8_t>> TryParseHex(std::string_view);
-void SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut)
+bool SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut)
{
+ bool valid = false;
size_t colon = in.find_last_of(':');
// if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
bool fHaveColon = colon != in.npos;
@@ -109,13 +111,18 @@ void SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut)
if (ParseUInt16(in.substr(colon + 1), &n)) {
in = in.substr(0, colon);
portOut = n;
+ valid = (portOut != 0);
}
+ } else {
+ valid = true;
}
if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') {
hostOut = in.substr(1, in.size() - 2);
} else {
hostOut = in;
}
+
+ return valid;
}
std::string EncodeBase64(Span<const unsigned char> input)
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index 14867b21b2..05e7b957c4 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -57,9 +57,15 @@ enum class ByteUnit : uint64_t {
* @return A new string without unsafe chars
*/
std::string SanitizeString(std::string_view str, int rule = SAFE_CHARS_DEFAULT);
-/** Parse the hex string into bytes (uint8_t or std::byte). Ignores whitespace. */
+/** Parse the hex string into bytes (uint8_t or std::byte). Ignores whitespace. Returns nullopt on invalid input. */
+template <typename Byte = std::byte>
+std::optional<std::vector<Byte>> TryParseHex(std::string_view str);
+/** Like TryParseHex, but returns an empty vector on invalid input. */
template <typename Byte = uint8_t>
-std::vector<Byte> ParseHex(std::string_view str);
+std::vector<Byte> ParseHex(std::string_view hex_str)
+{
+ return TryParseHex<Byte>(hex_str).value_or(std::vector<Byte>{});
+}
signed char HexDigit(char c);
/* Returns true if each character in str is a hex character, and has an even
* number of hex digits.*/
@@ -88,7 +94,16 @@ std::string EncodeBase32(Span<const unsigned char> input, bool pad = true);
*/
std::string EncodeBase32(std::string_view str, bool pad = true);
-void SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut);
+/**
+ * Splits socket address string into host string and port value.
+ * Validates port value.
+ *
+ * @param[in] in The socket address string to split.
+ * @param[out] portOut Port-portion of the input, if found and parsable.
+ * @param[out] hostOut Host-portion of the input, if found.
+ * @return true if port-portion is absent or within its allowed range, otherwise false
+ */
+bool SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut);
// LocaleIndependentAtoi is provided for backwards compatibility reasons.
//
diff --git a/src/util/string.cpp b/src/util/string.cpp
index e994c85f1c..3d31849745 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/string.h b/src/util/string.h
index 9b4c9a7e28..fb93d2a80e 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp
index a69f815ce4..b1579bdb9c 100644
--- a/src/util/syscall_sandbox.cpp
+++ b/src/util/syscall_sandbox.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/syscall_sandbox.h b/src/util/syscall_sandbox.h
index dc02ce29e9..3e56ebe937 100644
--- a/src/util/syscall_sandbox.h
+++ b/src/util/syscall_sandbox.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/system.cpp b/src/util/system.cpp
index c3c6cbfef6..98e89f82e7 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -1,23 +1,10 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <util/system.h>
-#ifdef ENABLE_EXTERNAL_SIGNER
-#if defined(__GNUC__)
-// Boost 1.78 requires the following workaround.
-// See: https://github.com/boostorg/process/issues/235
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wnarrowing"
-#endif
-#include <boost/process.hpp>
-#if defined(__GNUC__)
-#pragma GCC diagnostic pop
-#endif
-#endif // ENABLE_EXTERNAL_SIGNER
-
#include <chainparamsbase.h>
#include <fs.h>
#include <sync.h>
@@ -255,7 +242,7 @@ static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, con
ArgsManager::ArgsManager() = default;
ArgsManager::~ArgsManager() = default;
-const std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const
+std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const
{
std::set<std::string> unsuitables;
@@ -275,7 +262,7 @@ const std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const
return unsuitables;
}
-const std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
+std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
{
// Section names to be recognized in the config file.
static const std::set<std::string> available_sections{
@@ -430,8 +417,7 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const
LOCK(cs_args);
fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path;
- // Cache the path to avoid calling fs::create_directories on every call of
- // this function
+ // Used cached path if available
if (!path.empty()) return path;
const fs::path datadir{GetPathArg("-datadir")};
@@ -445,15 +431,8 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const
path = GetDefaultDataDir();
}
- if (!fs::exists(path)) {
- fs::create_directories(path / "wallets");
- }
-
if (net_specific && !BaseParams().DataDir().empty()) {
path /= fs::PathFromString(BaseParams().DataDir());
- if (!fs::exists(path)) {
- fs::create_directories(path / "wallets");
- }
}
return path;
@@ -502,24 +481,6 @@ bool ArgsManager::IsArgSet(const std::string& strArg) const
return !GetSetting(strArg).isNull();
}
-bool ArgsManager::InitSettings(std::string& error)
-{
- if (!GetSettingsPath()) {
- return true; // Do nothing if settings file disabled.
- }
-
- std::vector<std::string> errors;
- if (!ReadSettingsFile(&errors)) {
- error = strprintf("Failed loading settings file:\n%s\n", MakeUnorderedList(errors));
- return false;
- }
- if (!WriteSettingsFile(&errors)) {
- error = strprintf("Failed saving settings file:\n%s\n", MakeUnorderedList(errors));
- return false;
- }
- return true;
-}
-
bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp, bool backup) const
{
fs::path settings = GetPathArg("-settings", BITCOIN_SETTINGS_FILENAME);
@@ -831,29 +792,6 @@ std::string HelpMessageOpt(const std::string &option, const std::string &message
std::string("\n\n");
}
-static std::string FormatException(const std::exception* pex, std::string_view thread_name)
-{
-#ifdef WIN32
- char pszModule[MAX_PATH] = "";
- GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
-#else
- const char* pszModule = "bitcoin";
-#endif
- if (pex)
- return strprintf(
- "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, thread_name);
- else
- return strprintf(
- "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, thread_name);
-}
-
-void PrintExceptionContinue(const std::exception* pex, std::string_view thread_name)
-{
- std::string message = FormatException(pex, thread_name);
- LogPrintf("\n\n************************\n%s\n", message);
- tfm::format(std::cerr, "\n\n************************\n%s\n", message);
-}
-
fs::path GetDefaultDataDir()
{
// Windows: C:\Users\Username\AppData\Roaming\Bitcoin
@@ -879,15 +817,15 @@ fs::path GetDefaultDataDir()
#endif
}
-bool CheckDataDirOption()
+bool CheckDataDirOption(const ArgsManager& args)
{
- const fs::path datadir{gArgs.GetPathArg("-datadir")};
+ const fs::path datadir{args.GetPathArg("-datadir")};
return datadir.empty() || fs::is_directory(fs::absolute(datadir));
}
-fs::path GetConfigFile(const fs::path& configuration_file_path)
+fs::path GetConfigFile(const ArgsManager& args, const fs::path& configuration_file_path)
{
- return AbsPathForConfigVal(configuration_file_path, /*net_specific=*/false);
+ return AbsPathForConfigVal(args, configuration_file_path, /*net_specific=*/false);
}
static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
@@ -935,6 +873,20 @@ static bool GetConfigOptions(std::istream& stream, const std::string& filepath,
return true;
}
+bool IsConfSupported(KeyInfo& key, std::string& error) {
+ if (key.name == "conf") {
+ error = "conf cannot be set in the configuration file; use includeconf= if you want to include additional config files";
+ return false;
+ }
+ if (key.name == "reindex") {
+ // reindex can be set in a config file but it is strongly discouraged as this will cause the node to reindex on
+ // every restart. Allow the config but throw a warning
+ LogPrintf("Warning: reindex=1 is set in the configuration file, which will significantly slow down startup. Consider removing or commenting out this option for better performance, unless there is currently a condition which makes rebuilding the indexes necessary\n");
+ return true;
+ }
+ return true;
+}
+
bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys)
{
LOCK(cs_args);
@@ -945,6 +897,7 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& file
for (const std::pair<std::string, std::string>& option : options) {
KeyInfo key = InterpretKey(option.first);
std::optional<unsigned int> flags = GetArgFlags('-' + key.name);
+ if (!IsConfSupported(key, error)) return false;
if (flags) {
std::optional<util::SettingsValue> value = InterpretValue(key, &option.second, *flags, error);
if (!value) {
@@ -963,6 +916,11 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& file
return true;
}
+fs::path ArgsManager::GetConfigFilePath() const
+{
+ return GetConfigFile(*this, GetPathArg("-conf", BITCOIN_CONF_FILENAME));
+}
+
bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
{
{
@@ -971,8 +929,8 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
m_config_sections.clear();
}
- const fs::path conf_path = GetPathArg("-conf", BITCOIN_CONF_FILENAME);
- std::ifstream stream{GetConfigFile(conf_path)};
+ const auto conf_path{GetConfigFilePath()};
+ std::ifstream stream{conf_path};
// not ok to have a config file specified that cannot be opened
if (IsArgSet("-conf") && !stream.good()) {
@@ -1019,7 +977,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
const size_t default_includes = add_includes({});
for (const std::string& conf_file_name : conf_file_names) {
- std::ifstream conf_file_stream{GetConfigFile(fs::PathFromString(conf_file_name))};
+ std::ifstream conf_file_stream{GetConfigFile(*this, fs::PathFromString(conf_file_name))};
if (conf_file_stream.good()) {
if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) {
return false;
@@ -1047,8 +1005,8 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
}
// If datadir is changed in .conf file:
- gArgs.ClearPathCache();
- if (!CheckDataDirOption()) {
+ ClearPathCache();
+ if (!CheckDataDirOption(*this)) {
error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", ""));
return false;
}
@@ -1332,44 +1290,6 @@ void runCommand(const std::string& strCommand)
}
#endif
-UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in)
-{
-#ifdef ENABLE_EXTERNAL_SIGNER
- namespace bp = boost::process;
-
- UniValue result_json;
- bp::opstream stdin_stream;
- bp::ipstream stdout_stream;
- bp::ipstream stderr_stream;
-
- if (str_command.empty()) return UniValue::VNULL;
-
- bp::child c(
- str_command,
- bp::std_out > stdout_stream,
- bp::std_err > stderr_stream,
- bp::std_in < stdin_stream
- );
- if (!str_std_in.empty()) {
- stdin_stream << str_std_in << std::endl;
- }
- stdin_stream.pipe().close();
-
- std::string result;
- std::string error;
- std::getline(stdout_stream, result);
- std::getline(stderr_stream, error);
-
- c.wait();
- const int n_error = c.exit_code();
- if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error));
- if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result);
-
- return result_json;
-#else
- throw std::runtime_error("Compiled without external signing support (required for external signing).");
-#endif // ENABLE_EXTERNAL_SIGNER
-}
void SetupEnvironment()
{
@@ -1396,6 +1316,11 @@ void SetupEnvironment()
SetConsoleCP(CP_UTF8);
SetConsoleOutputCP(CP_UTF8);
#endif
+
+#ifndef WIN32
+ constexpr mode_t private_umask = 0077;
+ umask(private_umask);
+#endif
}
bool SetupNetworking()
@@ -1421,12 +1346,12 @@ int64_t GetStartupTime()
return nStartupTime;
}
-fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific)
+fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific)
{
if (path.is_absolute()) {
return path;
}
- return fsbridge::AbsPathJoin(net_specific ? gArgs.GetDataDirNet() : gArgs.GetDataDirBase(), path);
+ return fsbridge::AbsPathJoin(net_specific ? args.GetDataDirNet() : args.GetDataDirBase(), path);
}
void ScheduleBatchPriority()
diff --git a/src/util/system.h b/src/util/system.h
index c8e1de6700..7292262bea 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -19,12 +19,10 @@
#include <fs.h>
#include <logging.h>
#include <sync.h>
-#include <tinyformat.h>
#include <util/settings.h>
#include <util/time.h>
#include <any>
-#include <exception>
#include <map>
#include <optional>
#include <set>
@@ -33,6 +31,7 @@
#include <utility>
#include <vector>
+class ArgsManager;
class UniValue;
// Application startup time (used for uptime calculation)
@@ -44,15 +43,6 @@ extern const char * const BITCOIN_SETTINGS_FILENAME;
void SetupEnvironment();
bool SetupNetworking();
-template<typename... Args>
-bool error(const char* fmt, const Args&... args)
-{
- LogPrintf("ERROR: %s\n", tfm::format(fmt, args...));
- return false;
-}
-
-void PrintExceptionContinue(const std::exception* pex, std::string_view thread_name);
-
/**
* Ensure file contents are fully committed to disk, using a platform-specific
* feature analogous to fsync().
@@ -96,8 +86,8 @@ void ReleaseDirectoryLocks();
bool TryCreateDirectories(const fs::path& p);
fs::path GetDefaultDataDir();
// Return true if -datadir option points to a valid directory or is not specified.
-bool CheckDataDirOption();
-fs::path GetConfigFile(const fs::path& configuration_file_path);
+bool CheckDataDirOption(const ArgsManager& args);
+fs::path GetConfigFile(const ArgsManager& args, const fs::path& configuration_file_path);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
@@ -107,24 +97,17 @@ std::string ShellEscape(const std::string& arg);
#if HAVE_SYSTEM
void runCommand(const std::string& strCommand);
#endif
-/**
- * Execute a command which returns JSON, and parse the result.
- *
- * @param str_command The command to execute, including any arguments
- * @param str_std_in string to pass to stdin
- * @return parsed JSON
- */
-UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in="");
/**
* Most paths passed as configuration arguments are treated as relative to
* the datadir if they are not absolute.
*
+ * @param args Parsed arguments and settings.
* @param path The path to be conditionally prefixed with datadir.
* @param net_specific Use network specific datadir variant
* @return The normalized path.
*/
-fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific = true);
+fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific = true);
inline bool IsSwitchChar(char c)
{
@@ -250,6 +233,11 @@ protected:
void SelectConfigNetwork(const std::string& network);
[[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error);
+
+ /**
+ * Return config file path (read-only)
+ */
+ fs::path GetConfigFilePath() const;
[[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
/**
@@ -258,12 +246,12 @@ protected:
* on the command line or in a network-specific section in the
* config file.
*/
- const std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
+ std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
/**
* Log warnings for unrecognized section names in the config file.
*/
- const std::list<SectionInfo> GetUnrecognizedSections() const;
+ std::list<SectionInfo> GetUnrecognizedSections() const;
struct Command {
/** The command (if one has been registered with AddCommand), or empty */
@@ -290,7 +278,6 @@ protected:
* Get data directory path
*
* @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
- * @post Returned directory path is created unless it is empty
*/
const fs::path& GetDataDirBase() const { return GetDataDir(false); }
@@ -298,7 +285,6 @@ protected:
* Get data directory path with appended network identifier
*
* @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
- * @post Returned directory path is created unless it is empty
*/
const fs::path& GetDataDirNet() const { return GetDataDir(true); }
@@ -438,13 +424,6 @@ protected:
std::optional<unsigned int> GetArgFlags(const std::string& name) const;
/**
- * Read and update settings file with saved settings. This needs to be
- * called after SelectParams() because the settings file location is
- * network-specific.
- */
- bool InitSettings(std::string& error);
-
- /**
* Get settings file path, or return false if read-write settings were
* disabled with -nosettings.
*/
@@ -489,7 +468,6 @@ private:
*
* @param net_specific Append network identifier to the returned path
* @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
- * @post Returned directory path is created unless it is empty
*/
const fs::path& GetDataDir(bool net_specific) const;
diff --git a/src/util/thread.cpp b/src/util/thread.cpp
index ae98abdb3d..f380d29f7a 100644
--- a/src/util/thread.cpp
+++ b/src/util/thread.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <util/thread.h>
#include <logging.h>
-#include <util/system.h>
+#include <util/exception.h>
#include <util/threadnames.h>
#include <exception>
diff --git a/src/util/thread.h b/src/util/thread.h
index b80bf046a0..8a2de84a7f 100644
--- a/src/util/thread.h
+++ b/src/util/thread.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/threadinterrupt.cpp b/src/util/threadinterrupt.cpp
index e28b447c1d..3ea406d4a8 100644
--- a/src/threadinterrupt.cpp
+++ b/src/util/threadinterrupt.cpp
@@ -1,9 +1,9 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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 <threadinterrupt.h>
+#include <util/threadinterrupt.h>
#include <sync.h>
diff --git a/src/threadinterrupt.h b/src/util/threadinterrupt.h
index 979bc2ee3e..ccc053f576 100644
--- a/src/threadinterrupt.h
+++ b/src/util/threadinterrupt.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 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_THREADINTERRUPT_H
-#define BITCOIN_THREADINTERRUPT_H
+#ifndef BITCOIN_UTIL_THREADINTERRUPT_H
+#define BITCOIN_UTIL_THREADINTERRUPT_H
#include <sync.h>
#include <threadsafety.h>
@@ -33,4 +33,4 @@ private:
std::atomic<bool> flag;
};
-#endif // BITCOIN_THREADINTERRUPT_H
+#endif // BITCOIN_UTIL_THREADINTERRUPT_H
diff --git a/src/util/threadnames.cpp b/src/util/threadnames.cpp
index a5a86d2598..91883fe4ff 100644
--- a/src/util/threadnames.cpp
+++ b/src/util/threadnames.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/time.cpp b/src/util/time.cpp
index 0b20849079..58200c83fc 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/time.h b/src/util/time.h
index 0ec79bec32..fcf85c1e03 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,7 +8,7 @@
#include <compat/compat.h>
-#include <chrono>
+#include <chrono> // IWYU pragma: export
#include <cstdint>
#include <string>
@@ -57,6 +57,7 @@ constexpr int64_t count_microseconds(std::chrono::microseconds t) { return t.cou
using HoursDouble = std::chrono::duration<double, std::chrono::hours::period>;
using SecondsDouble = std::chrono::duration<double, std::chrono::seconds::period>;
+using MillisecondsDouble = std::chrono::duration<double, std::chrono::milliseconds::period>;
/**
* DEPRECATED
diff --git a/src/util/tokenpipe.cpp b/src/util/tokenpipe.cpp
index 49456814e2..3c27d5e523 100644
--- a/src/util/tokenpipe.cpp
+++ b/src/util/tokenpipe.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <util/tokenpipe.h>
diff --git a/src/util/translation.h b/src/util/translation.h
index 07b7f43c8a..d2b49d00b0 100644
--- a/src/util/translation.h
+++ b/src/util/translation.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -47,11 +47,24 @@ inline bilingual_str operator+(bilingual_str lhs, const bilingual_str& rhs)
/** Mark a bilingual_str as untranslated */
inline bilingual_str Untranslated(std::string original) { return {original, original}; }
+// Provide an overload of tinyformat::format which can take bilingual_str arguments.
namespace tinyformat {
+inline std::string TranslateArg(const bilingual_str& arg, bool translated)
+{
+ return translated ? arg.translated : arg.original;
+}
+
+template <typename T>
+inline T const& TranslateArg(const T& arg, bool translated)
+{
+ return arg;
+}
+
template <typename... Args>
bilingual_str format(const bilingual_str& fmt, const Args&... args)
{
- return bilingual_str{format(fmt.original, args...), format(fmt.translated, args...)};
+ return bilingual_str{format(fmt.original, TranslateArg(args, false)...),
+ format(fmt.translated, TranslateArg(args, true)...)};
}
} // namespace tinyformat
diff --git a/src/util/vector.h b/src/util/vector.h
index ed745affe5..9b9218e54f 100644
--- a/src/util/vector.h
+++ b/src/util/vector.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/validation.cpp b/src/validation.cpp
index fb29ca3ae7..5b3a099dfc 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,7 +10,6 @@
#include <arith_uint256.h>
#include <chain.h>
-#include <chainparams.h>
#include <checkqueue.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
@@ -22,6 +21,8 @@
#include <flatfile.h>
#include <fs.h>
#include <hash.h>
+#include <kernel/chainparams.h>
+#include <kernel/mempool_entry.h>
#include <logging.h>
#include <logging/timer.h>
#include <node/blockstorage.h>
@@ -63,6 +64,7 @@
#include <numeric>
#include <optional>
#include <string>
+#include <utility>
using kernel::CCoinsStats;
using kernel::CoinStatsHashType;
@@ -74,17 +76,12 @@ using node::BlockManager;
using node::BlockMap;
using node::CBlockIndexHeightOnlyComparator;
using node::CBlockIndexWorkComparator;
-using node::fImporting;
-using node::fPruneMode;
using node::fReindex;
using node::ReadBlockFromDisk;
using node::SnapshotMetadata;
using node::UndoReadFromDisk;
using node::UnlinkPrunedFiles;
-#define MICRO 0.000001
-#define MILLI 0.001
-
/** Maximum kilobytes for transactions to store for processing during reorg */
static const unsigned int MAX_DISCONNECTED_TX_POOL_SIZE = 20000;
/** Time to wait between writing blocks/block index to disk. */
@@ -108,28 +105,9 @@ const std::vector<std::string> CHECKLEVEL_DOC {
* */
static constexpr int PRUNE_LOCK_BUFFER{10};
-/**
- * Mutex to guard access to validation specific variables, such as reading
- * or changing the chainstate.
- *
- * This may also need to be locked when updating the transaction pool, e.g. on
- * AcceptToMemoryPool. See CTxMemPool::cs comment for details.
- *
- * The transaction pool has a separate lock to allow reading from it and the
- * chainstate at the same time.
- */
-RecursiveMutex cs_main;
-
GlobalMutex g_best_block_mutex;
std::condition_variable g_best_block_cv;
uint256 g_best_block;
-bool g_parallel_script_checks{false};
-bool fCheckBlockIndex = false;
-bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
-int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
-
-uint256 hashAssumeValid;
-arith_uint256 nMinimumChainWork;
const CBlockIndex* Chainstate::FindForkInGlobalIndex(const CBlockLocator& locator) const
{
@@ -179,11 +157,89 @@ bool CheckFinalTxAtTip(const CBlockIndex& active_chain_tip, const CTransaction&
return IsFinalTx(tx, nBlockHeight, nBlockTime);
}
+namespace {
+/**
+ * A helper which calculates heights of inputs of a given transaction.
+ *
+ * @param[in] tip The current chain tip. If an input belongs to a mempool
+ * transaction, we assume it will be confirmed in the next block.
+ * @param[in] coins Any CCoinsView that provides access to the relevant coins.
+ * @param[in] tx The transaction being evaluated.
+ *
+ * @returns A vector of input heights or nullopt, in case of an error.
+ */
+std::optional<std::vector<int>> CalculatePrevHeights(
+ const CBlockIndex& tip,
+ const CCoinsView& coins,
+ const CTransaction& tx)
+{
+ std::vector<int> prev_heights;
+ prev_heights.resize(tx.vin.size());
+ for (size_t i = 0; i < tx.vin.size(); ++i) {
+ const CTxIn& txin = tx.vin[i];
+ Coin coin;
+ if (!coins.GetCoin(txin.prevout, coin)) {
+ LogPrintf("ERROR: %s: Missing input %d in transaction \'%s\'\n", __func__, i, tx.GetHash().GetHex());
+ return std::nullopt;
+ }
+ if (coin.nHeight == MEMPOOL_HEIGHT) {
+ // Assume all mempool transaction confirm in the next block.
+ prev_heights[i] = tip.nHeight + 1;
+ } else {
+ prev_heights[i] = coin.nHeight;
+ }
+ }
+ return prev_heights;
+}
+} // namespace
+
+std::optional<LockPoints> CalculateLockPointsAtTip(
+ CBlockIndex* tip,
+ const CCoinsView& coins_view,
+ const CTransaction& tx)
+{
+ assert(tip);
+
+ auto prev_heights{CalculatePrevHeights(*tip, coins_view, tx)};
+ if (!prev_heights.has_value()) return std::nullopt;
+
+ CBlockIndex next_tip;
+ next_tip.pprev = tip;
+ // When SequenceLocks() is called within ConnectBlock(), the height
+ // of the block *being* evaluated is what is used.
+ // Thus if we want to know if a transaction can be part of the
+ // *next* block, we need to use one more than active_chainstate.m_chain.Height()
+ next_tip.nHeight = tip->nHeight + 1;
+ const auto [min_height, min_time] = CalculateSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, prev_heights.value(), next_tip);
+
+ // Also store the hash of the block with the highest height of
+ // all the blocks which have sequence locked prevouts.
+ // This hash needs to still be on the chain
+ // for these LockPoint calculations to be valid
+ // Note: It is impossible to correctly calculate a maxInputBlock
+ // if any of the sequence locked inputs depend on unconfirmed txs,
+ // except in the special case where the relative lock time/height
+ // is 0, which is equivalent to no sequence lock. Since we assume
+ // input height of tip+1 for mempool txs and test the resulting
+ // min_height and min_time from CalculateSequenceLocks against tip+1.
+ int max_input_height{0};
+ for (const int height : prev_heights.value()) {
+ // Can ignore mempool inputs since we'll fail if they had non-zero locks
+ if (height != next_tip.nHeight) {
+ max_input_height = std::max(max_input_height, height);
+ }
+ }
+
+ // tip->GetAncestor(max_input_height) should never return a nullptr
+ // because max_input_height is always less than the tip height.
+ // It would, however, be a bad bug to continue execution, since a
+ // LockPoints object with the maxInputBlock member set to nullptr
+ // signifies no relative lock time.
+ return LockPoints{min_height, min_time, Assert(tip->GetAncestor(max_input_height))};
+}
+
bool CheckSequenceLocksAtTip(CBlockIndex* tip,
- const CCoinsView& coins_view,
- const CTransaction& tx,
- LockPoints* lp,
- bool useExistingLockPoints)
+ const LockPoints& lock_points)
{
assert(tip != nullptr);
@@ -197,61 +253,7 @@ bool CheckSequenceLocksAtTip(CBlockIndex* tip,
// *next* block, we need to use one more than active_chainstate.m_chain.Height()
index.nHeight = tip->nHeight + 1;
- std::pair<int, int64_t> lockPair;
- if (useExistingLockPoints) {
- assert(lp);
- lockPair.first = lp->height;
- lockPair.second = lp->time;
- }
- else {
- std::vector<int> prevheights;
- prevheights.resize(tx.vin.size());
- for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
- const CTxIn& txin = tx.vin[txinIndex];
- Coin coin;
- if (!coins_view.GetCoin(txin.prevout, coin)) {
- return error("%s: Missing input", __func__);
- }
- if (coin.nHeight == MEMPOOL_HEIGHT) {
- // Assume all mempool transaction confirm in the next block
- prevheights[txinIndex] = tip->nHeight + 1;
- } else {
- prevheights[txinIndex] = coin.nHeight;
- }
- }
- lockPair = CalculateSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, prevheights, index);
- if (lp) {
- lp->height = lockPair.first;
- lp->time = lockPair.second;
- // Also store the hash of the block with the highest height of
- // all the blocks which have sequence locked prevouts.
- // This hash needs to still be on the chain
- // for these LockPoint calculations to be valid
- // Note: It is impossible to correctly calculate a maxInputBlock
- // if any of the sequence locked inputs depend on unconfirmed txs,
- // except in the special case where the relative lock time/height
- // is 0, which is equivalent to no sequence lock. Since we assume
- // input height of tip+1 for mempool txs and test the resulting
- // lockPair from CalculateSequenceLocks against tip+1. We know
- // EvaluateSequenceLocks will fail if there was a non-zero sequence
- // lock on a mempool input, so we can use the return value of
- // CheckSequenceLocksAtTip to indicate the LockPoints validity
- int maxInputHeight = 0;
- for (const int height : prevheights) {
- // Can ignore mempool inputs since we'll fail if they had non-zero locks
- if (height != tip->nHeight+1) {
- maxInputHeight = std::max(maxInputHeight, height);
- }
- }
- // tip->GetAncestor(maxInputHeight) should never return a nullptr
- // because maxInputHeight is always less than the tip height.
- // It would, however, be a bad bug to continue execution, since a
- // LockPoints object with the maxInputBlock member set to nullptr
- // signifies no relative lock time.
- lp->maxInputBlock = Assert(tip->GetAncestor(maxInputHeight));
- }
- }
- return EvaluateSequenceLocks(index, lockPair);
+ return EvaluateSequenceLocks(index, {lock_points.height, lock_points.time});
}
// Returns the script flags which should be checked for a given block
@@ -337,20 +339,23 @@ void Chainstate::MaybeUpdateMempoolForReorg(
// The transaction must be final.
if (!CheckFinalTxAtTip(*Assert(m_chain.Tip()), tx)) return true;
- LockPoints lp = it->GetLockPoints();
- const bool validLP{TestLockPointValidity(m_chain, lp)};
- CCoinsViewMemPool view_mempool(&CoinsTip(), *m_mempool);
+
+ const LockPoints& lp = it->GetLockPoints();
// CheckSequenceLocksAtTip checks if the transaction will be final in the next block to be
- // created on top of the new chain. We use useExistingLockPoints=false so that, instead of
- // using the information in lp (which might now refer to a block that no longer exists in
- // the chain), it will update lp to contain LockPoints relevant to the new chain.
- if (!CheckSequenceLocksAtTip(m_chain.Tip(), view_mempool, tx, &lp, validLP)) {
- // If CheckSequenceLocksAtTip fails, remove the tx and don't depend on the LockPoints.
- return true;
- } else if (!validLP) {
- // If CheckSequenceLocksAtTip succeeded, it also updated the LockPoints.
- // Now update the mempool entry lockpoints as well.
- m_mempool->mapTx.modify(it, [&lp](CTxMemPoolEntry& e) { e.UpdateLockPoints(lp); });
+ // created on top of the new chain.
+ if (TestLockPointValidity(m_chain, lp)) {
+ if (!CheckSequenceLocksAtTip(m_chain.Tip(), lp)) {
+ return true;
+ }
+ } else {
+ const CCoinsViewMemPool view_mempool{&CoinsTip(), *m_mempool};
+ const std::optional<LockPoints> new_lock_points{CalculateLockPointsAtTip(m_chain.Tip(), view_mempool, tx)};
+ if (new_lock_points.has_value() && CheckSequenceLocksAtTip(m_chain.Tip(), *new_lock_points)) {
+ // Now update the mempool entry lockpoints as well.
+ m_mempool->mapTx.modify(it, [&new_lock_points](CTxMemPoolEntry& e) { e.UpdateLockPoints(*new_lock_points); });
+ } else {
+ return true;
+ }
}
// If the transaction spends any coinbase outputs, it must be mature.
@@ -424,11 +429,13 @@ namespace {
class MemPoolAccept
{
public:
- explicit MemPoolAccept(CTxMemPool& mempool, Chainstate& active_chainstate) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&active_chainstate.CoinsTip(), m_pool), m_active_chainstate(active_chainstate),
- m_limit_ancestors(m_pool.m_limits.ancestor_count),
- m_limit_ancestor_size(m_pool.m_limits.ancestor_size_vbytes),
- m_limit_descendants(m_pool.m_limits.descendant_count),
- m_limit_descendant_size(m_pool.m_limits.descendant_size_vbytes) {
+ explicit MemPoolAccept(CTxMemPool& mempool, Chainstate& active_chainstate) :
+ m_pool(mempool),
+ m_view(&m_dummy),
+ m_viewmempool(&active_chainstate.CoinsTip(), m_pool),
+ m_active_chainstate(active_chainstate),
+ m_limits{m_pool.m_limits}
+ {
}
// We put the arguments we're handed into a struct, so we can pass them
@@ -589,6 +596,11 @@ private:
/** Total virtual size of all transactions being replaced. */
size_t m_conflicting_size{0};
+ /** If we're doing package validation (i.e. m_package_feerates=true), the "effective"
+ * package feerate of this transaction is the total fees divided by the total size of
+ * transactions (which may include its ancestors and/or descendants). */
+ CFeeRate m_package_feerate{0};
+
const CTransactionRef& m_ptx;
/** Txid. */
const uint256& m_hash;
@@ -660,13 +672,7 @@ private:
Chainstate& m_active_chainstate;
- // The package limits in effect at the time of invocation.
- const size_t m_limit_ancestors;
- const size_t m_limit_ancestor_size;
- // These may be modified while evaluating a transaction (eg to account for
- // in-mempool conflicts; see below).
- size_t m_limit_descendants;
- size_t m_limit_descendant_size;
+ CTxMemPool::Limits m_limits;
/** Whether the transaction(s) would replace any mempool transactions. If so, RBF rules apply. */
bool m_rbf{false};
@@ -703,10 +709,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason);
}
- // Do not work on transactions that are too small.
- // A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes.
- // Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying
- // 64-byte transactions.
+ // Transactions smaller than 65 non-witness bytes are not relayed to mitigate CVE-2017-12842.
if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE)
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "tx-size-small");
@@ -756,7 +759,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
}
- LockPoints lp;
m_view.SetBackend(m_viewmempool);
const CCoinsViewCache& coins_cache = m_active_chainstate.CoinsTip();
@@ -798,7 +800,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// be mined yet.
// Pass in m_view which has all of the relevant inputs cached. Note that, since m_view's
// backend was removed, it no longer pulls coins from the mempool.
- if (!CheckSequenceLocksAtTip(m_active_chainstate.m_chain.Tip(), m_view, tx, &lp)) {
+ const std::optional<LockPoints> lock_points{CalculateLockPointsAtTip(m_active_chainstate.m_chain.Tip(), m_view, tx)};
+ if (!lock_points.has_value() || !CheckSequenceLocksAtTip(m_active_chainstate.m_chain.Tip(), *lock_points)) {
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final");
}
@@ -834,7 +837,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
entry.reset(new CTxMemPoolEntry(ptx, ws.m_base_fees, nAcceptTime, m_active_chainstate.m_chain.Height(),
- fSpendsCoinbase, nSigOpsCost, lp));
+ fSpendsCoinbase, nSigOpsCost, lock_points.value()));
ws.m_vsize = entry->GetTxSize();
if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)
@@ -879,15 +882,13 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
assert(ws.m_iters_conflicting.size() == 1);
CTxMemPool::txiter conflict = *ws.m_iters_conflicting.begin();
- m_limit_descendants += 1;
- m_limit_descendant_size += conflict->GetSizeWithDescendants();
+ m_limits.descendant_count += 1;
+ m_limits.descendant_size_vbytes += conflict->GetSizeWithDescendants();
}
- std::string errString;
- if (!m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants, m_limit_descendant_size, errString)) {
- ws.m_ancestors.clear();
+ auto ancestors{m_pool.CalculateMemPoolAncestors(*entry, m_limits)};
+ if (!ancestors) {
// If CalculateMemPoolAncestors fails second time, we want the original error string.
- std::string dummy_err_string;
// Contracting/payment channels CPFP carve-out:
// If the new transaction is relatively small (up to 40k weight)
// and has at most one ancestor (ie ancestor limit of 2, including
@@ -899,12 +900,22 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// to be secure by simply only having two immediately-spendable
// outputs - one for each counterparty. For more info on the uses for
// this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
- if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT ||
- !m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) {
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", errString);
+ CTxMemPool::Limits cpfp_carve_out_limits{
+ .ancestor_count = 2,
+ .ancestor_size_vbytes = m_limits.ancestor_size_vbytes,
+ .descendant_count = m_limits.descendant_count + 1,
+ .descendant_size_vbytes = m_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT,
+ };
+ const auto error_message{util::ErrorString(ancestors).original};
+ if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT) {
+ return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
}
+ ancestors = m_pool.CalculateMemPoolAncestors(*entry, cpfp_carve_out_limits);
+ if (!ancestors) return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
}
+ ws.m_ancestors = *ancestors;
+
// A transaction that spends outputs that would be replaced by it is invalid. Now
// that we have the set of all ancestors we can detect this
// pathological case by making sure ws.m_conflicts and ws.m_ancestors don't
@@ -976,8 +987,7 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
{ return !m_pool.exists(GenTxid::Txid(tx->GetHash()));}));
std::string err_string;
- if (!m_pool.CheckPackageLimits(txns, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants,
- m_limit_descendant_size, err_string)) {
+ if (!m_pool.CheckPackageLimits(txns, m_limits, err_string)) {
// This is a package-wide error, separate from an individual transaction error.
return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", err_string);
}
@@ -1120,17 +1130,18 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
// Re-calculate mempool ancestors to call addUnchecked(). They may have changed since the
// last calculation done in PreChecks, since package ancestors have already been submitted.
- std::string unused_err_string;
- if(!m_pool.CalculateMemPoolAncestors(*ws.m_entry, ws.m_ancestors, m_limit_ancestors,
- m_limit_ancestor_size, m_limit_descendants,
- m_limit_descendant_size, unused_err_string)) {
- results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
- // Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail.
- Assume(false);
- all_submitted = false;
- package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR,
- strprintf("BUG! Mempool ancestors or descendants were underestimated: %s",
- ws.m_ptx->GetHash().ToString()));
+ {
+ auto ancestors{m_pool.CalculateMemPoolAncestors(*ws.m_entry, m_limits)};
+ if(!ancestors) {
+ results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
+ // Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail.
+ Assume(false);
+ all_submitted = false;
+ package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR,
+ strprintf("BUG! Mempool ancestors or descendants were underestimated: %s",
+ ws.m_ptx->GetHash().ToString()));
+ }
+ ws.m_ancestors = std::move(ancestors).value_or(ws.m_ancestors);
}
// If we call LimitMempoolSize() for each individual Finalize(), the mempool will not take
// the transaction's descendant feerate into account because it hasn't seen them yet. Also,
@@ -1151,12 +1162,21 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
// make sure we haven't exceeded max mempool size.
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip());
+ std::vector<uint256> all_package_wtxids;
+ all_package_wtxids.reserve(workspaces.size());
+ std::transform(workspaces.cbegin(), workspaces.cend(), std::back_inserter(all_package_wtxids),
+ [](const auto& ws) { return ws.m_ptx->GetWitnessHash(); });
// Find the wtxids of the transactions that made it into the mempool. Allow partial submission,
// but don't report success unless they all made it into the mempool.
for (Workspace& ws : workspaces) {
+ const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate :
+ CFeeRate{ws.m_modified_fees, static_cast<uint32_t>(ws.m_vsize)};
+ const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids :
+ std::vector<uint256>({ws.m_ptx->GetWitnessHash()});
if (m_pool.exists(GenTxid::Wtxid(ws.m_ptx->GetWitnessHash()))) {
results.emplace(ws.m_ptx->GetWitnessHash(),
- MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees));
+ MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize,
+ ws.m_base_fees, effective_feerate, effective_feerate_wtxids));
GetMainSignals().TransactionAddedToMempool(ws.m_ptx, m_pool.GetAndIncrementSequence());
} else {
all_submitted = false;
@@ -1184,16 +1204,20 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
if (!ConsensusScriptChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
+ const CFeeRate effective_feerate{ws.m_modified_fees, static_cast<uint32_t>(ws.m_vsize)};
+ const std::vector<uint256> single_wtxid{ws.m_ptx->GetWitnessHash()};
// Tx was accepted, but not added
if (args.m_test_accept) {
- return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees);
+ return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize,
+ ws.m_base_fees, effective_feerate, single_wtxid);
}
if (!Finalize(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
GetMainSignals().TransactionAddedToMempool(ptx, m_pool.GetAndIncrementSequence());
- return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees);
+ return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees,
+ effective_feerate, single_wtxid);
}
PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::vector<CTransactionRef>& txns, ATMPArgs& args)
@@ -1240,7 +1264,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
if (args.m_package_feerates &&
!CheckFeeRate(m_total_vsize, m_total_modified_fees, placeholder_state)) {
package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-fee-too-low");
- return PackageMempoolAcceptResult(package_state, package_feerate, {});
+ return PackageMempoolAcceptResult(package_state, {});
}
// Apply package mempool ancestor/descendant limits. Skip if there is only one transaction,
@@ -1248,51 +1272,60 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
// transactions, but this exemption is not extended to packages in CheckPackageLimits().
std::string err_string;
if (txns.size() > 1 && !PackageMempoolChecks(txns, package_state)) {
- return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results));
+ return PackageMempoolAcceptResult(package_state, std::move(results));
}
+ std::vector<uint256> all_package_wtxids;
+ all_package_wtxids.reserve(workspaces.size());
+ std::transform(workspaces.cbegin(), workspaces.cend(), std::back_inserter(all_package_wtxids),
+ [](const auto& ws) { return ws.m_ptx->GetWitnessHash(); });
for (Workspace& ws : workspaces) {
+ ws.m_package_feerate = package_feerate;
if (!PolicyScriptChecks(args, ws)) {
// Exit early to avoid doing pointless work. Update the failed tx result; the rest are unfinished.
package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");
results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
- return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results));
+ return PackageMempoolAcceptResult(package_state, std::move(results));
}
if (args.m_test_accept) {
- // When test_accept=true, transactions that pass PolicyScriptChecks are valid because there are
- // no further mempool checks (passing PolicyScriptChecks implies passing ConsensusScriptChecks).
+ const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate :
+ CFeeRate{ws.m_modified_fees, static_cast<uint32_t>(ws.m_vsize)};
+ const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids :
+ std::vector<uint256>{ws.m_ptx->GetWitnessHash()};
results.emplace(ws.m_ptx->GetWitnessHash(),
MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions),
- ws.m_vsize, ws.m_base_fees));
+ ws.m_vsize, ws.m_base_fees, effective_feerate,
+ effective_feerate_wtxids));
}
}
- if (args.m_test_accept) return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results));
+ if (args.m_test_accept) return PackageMempoolAcceptResult(package_state, std::move(results));
if (!SubmitPackage(args, workspaces, package_state, results)) {
// PackageValidationState filled in by SubmitPackage().
- return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results));
+ return PackageMempoolAcceptResult(package_state, std::move(results));
}
- return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results));
+ return PackageMempoolAcceptResult(package_state, std::move(results));
}
PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, ATMPArgs& args)
{
AssertLockHeld(cs_main);
- PackageValidationState package_state;
+ // Used if returning a PackageMempoolAcceptResult directly from this function.
+ PackageValidationState package_state_quit_early;
// Check that the package is well-formed. If it isn't, we won't try to validate any of the
// transactions and thus won't return any MempoolAcceptResults, just a package-wide error.
// Context-free package checks.
- if (!CheckPackage(package, package_state)) return PackageMempoolAcceptResult(package_state, {});
+ if (!CheckPackage(package, package_state_quit_early)) return PackageMempoolAcceptResult(package_state_quit_early, {});
// All transactions in the package must be a parent of the last transaction. This is just an
// opportunity for us to fail fast on a context-free check without taking the mempool lock.
if (!IsChildWithParents(package)) {
- package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-parents");
- return PackageMempoolAcceptResult(package_state, {});
+ package_state_quit_early.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-parents");
+ return PackageMempoolAcceptResult(package_state_quit_early, {});
}
// IsChildWithParents() guarantees the package is > 1 transactions.
@@ -1324,15 +1357,16 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
return unconfirmed_parent_txids.count(input.prevout.hash) > 0 || m_view.HaveCoin(input.prevout);
};
if (!std::all_of(child->vin.cbegin(), child->vin.cend(), package_or_confirmed)) {
- package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-unconfirmed-parents");
- return PackageMempoolAcceptResult(package_state, {});
+ package_state_quit_early.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-unconfirmed-parents");
+ return PackageMempoolAcceptResult(package_state_quit_early, {});
}
// Protect against bugs where we pull more inputs from disk that miss being added to
// coins_to_uncache. The backend will be connected again when needed in PreChecks.
m_view.SetBackend(m_dummy);
LOCK(m_pool.cs);
- std::map<const uint256, const MempoolAcceptResult> results;
+ // Stores final results that won't change
+ std::map<const uint256, const MempoolAcceptResult> results_final;
// Node operators are free to set their mempool policies however they please, nodes may receive
// transactions in different orders, and malicious counterparties may try to take advantage of
// policy differences to pin or delay propagation of transactions. As such, it's possible for
@@ -1342,8 +1376,13 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
// the new transactions. This ensures we don't double-count transaction counts and sizes when
// checking ancestor/descendant limits, or double-count transaction fees for fee-related policy.
ATMPArgs single_args = ATMPArgs::SingleInPackageAccept(args);
+ // Results from individual validation. "Nonfinal" because if a transaction fails by itself but
+ // succeeds later (i.e. when evaluated with a fee-bumping child), the result changes (though not
+ // reflected in this map). If a transaction fails more than once, we want to return the first
+ // result, when it was considered on its own. So changes will only be from invalid -> valid.
+ std::map<uint256, MempoolAcceptResult> individual_results_nonfinal;
bool quit_early{false};
- std::vector<CTransactionRef> txns_new;
+ std::vector<CTransactionRef> txns_package_eval;
for (const auto& tx : package) {
const auto& wtxid = tx->GetWitnessHash();
const auto& txid = tx->GetHash();
@@ -1354,7 +1393,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
// Exact transaction already exists in the mempool.
auto iter = m_pool.GetIter(txid);
assert(iter != std::nullopt);
- results.emplace(wtxid, MempoolAcceptResult::MempoolTx(iter.value()->GetTxSize(), iter.value()->GetFee()));
+ results_final.emplace(wtxid, MempoolAcceptResult::MempoolTx(iter.value()->GetTxSize(), iter.value()->GetFee()));
} else if (m_pool.exists(GenTxid::Txid(txid))) {
// Transaction with the same non-witness data but different witness (same txid,
// different wtxid) already exists in the mempool.
@@ -1366,7 +1405,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
auto iter = m_pool.GetIter(txid);
assert(iter != std::nullopt);
// Provide the wtxid of the mempool tx so that the caller can look it up in the mempool.
- results.emplace(wtxid, MempoolAcceptResult::MempoolTxDifferentWitness(iter.value()->GetTx().GetWitnessHash()));
+ results_final.emplace(wtxid, MempoolAcceptResult::MempoolTxDifferentWitness(iter.value()->GetTx().GetWitnessHash()));
} else {
// Transaction does not already exist in the mempool.
// Try submitting the transaction on its own.
@@ -1375,7 +1414,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
// The transaction succeeded on its own and is now in the mempool. Don't include it
// in package validation, because its fees should only be "used" once.
assert(m_pool.exists(GenTxid::Wtxid(wtxid)));
- results.emplace(wtxid, single_res);
+ results_final.emplace(wtxid, single_res);
} else if (single_res.m_state.GetResult() != TxValidationResult::TX_MEMPOOL_POLICY &&
single_res.m_state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) {
// Package validation policy only differs from individual policy in its evaluation
@@ -1388,24 +1427,40 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
// future. Continue individually validating the rest of the transactions, because
// some of them may still be valid.
quit_early = true;
+ package_state_quit_early.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");
+ individual_results_nonfinal.emplace(wtxid, single_res);
} else {
- txns_new.push_back(tx);
+ individual_results_nonfinal.emplace(wtxid, single_res);
+ txns_package_eval.push_back(tx);
}
}
}
- // Nothing to do if the entire package has already been submitted.
- if (quit_early || txns_new.empty()) {
- // No package feerate when no package validation was done.
- return PackageMempoolAcceptResult(package_state, std::move(results));
+ // Quit early because package validation won't change the result or the entire package has
+ // already been submitted.
+ if (quit_early || txns_package_eval.empty()) {
+ for (const auto& [wtxid, mempoolaccept_res] : individual_results_nonfinal) {
+ Assume(results_final.emplace(wtxid, mempoolaccept_res).second);
+ Assume(mempoolaccept_res.m_result_type == MempoolAcceptResult::ResultType::INVALID);
+ }
+ return PackageMempoolAcceptResult(package_state_quit_early, std::move(results_final));
}
- // Validate the (deduplicated) transactions as a package.
- auto submission_result = AcceptMultipleTransactions(txns_new, args);
+ // Validate the (deduplicated) transactions as a package. Note that submission_result has its
+ // own PackageValidationState; package_state_quit_early is unused past this point.
+ auto submission_result = AcceptMultipleTransactions(txns_package_eval, args);
// Include already-in-mempool transaction results in the final result.
- for (const auto& [wtxid, mempoolaccept_res] : results) {
- submission_result.m_tx_results.emplace(wtxid, mempoolaccept_res);
+ for (const auto& [wtxid, mempoolaccept_res] : results_final) {
+ Assume(submission_result.m_tx_results.emplace(wtxid, mempoolaccept_res).second);
+ Assume(mempoolaccept_res.m_result_type != MempoolAcceptResult::ResultType::INVALID);
+ }
+ if (submission_result.m_state.GetResult() == PackageValidationResult::PCKG_TX) {
+ // Package validation failed because one or more transactions failed. Provide a result for
+ // each transaction; if AcceptMultipleTransactions() didn't return a result for a tx,
+ // include the previous individual failure reason.
+ submission_result.m_tx_results.insert(individual_results_nonfinal.cbegin(),
+ individual_results_nonfinal.cend());
+ Assume(submission_result.m_tx_results.size() == package.size());
}
- if (submission_result.m_state.IsValid()) assert(submission_result.m_package_feerate.has_value());
return submission_result;
}
@@ -1416,13 +1471,13 @@ MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTra
EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
- const CChainParams& chainparams{active_chainstate.m_params};
+ const CChainParams& chainparams{active_chainstate.m_chainman.GetParams()};
assert(active_chainstate.GetMempool() != nullptr);
CTxMemPool& pool{*active_chainstate.GetMempool()};
std::vector<COutPoint> coins_to_uncache;
auto args = MemPoolAccept::ATMPArgs::SingleAccept(chainparams, accept_time, bypass_limits, coins_to_uncache, test_accept);
- const MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args);
+ MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args);
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
// Remove coins that were not present in the coins cache before calling
// AcceptSingleTransaction(); this is to prevent memory DoS in case we receive a large
@@ -1446,8 +1501,8 @@ PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxM
assert(std::all_of(package.cbegin(), package.cend(), [](const auto& tx){return tx != nullptr;}));
std::vector<COutPoint> coins_to_uncache;
- const CChainParams& chainparams = active_chainstate.m_params;
- const auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
+ const CChainParams& chainparams = active_chainstate.m_chainman.GetParams();
+ auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
AssertLockHeld(cs_main);
if (test_accept) {
auto args = MemPoolAccept::ATMPArgs::PackageTestAccept(chainparams, GetTime(), coins_to_uncache);
@@ -1483,13 +1538,9 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
return nSubsidy;
}
-CoinsViews::CoinsViews(
- fs::path ldb_name,
- size_t cache_size_bytes,
- bool in_memory,
- bool should_wipe) : m_dbview(
- gArgs.GetDataDirNet() / ldb_name, cache_size_bytes, in_memory, should_wipe),
- m_catcherview(&m_dbview) {}
+CoinsViews::CoinsViews(DBParams db_params, CoinsViewOptions options)
+ : m_dbview{std::move(db_params), std::move(options)},
+ m_catcherview(&m_dbview) {}
void CoinsViews::InitCache()
{
@@ -1504,7 +1555,6 @@ Chainstate::Chainstate(
std::optional<uint256> from_snapshot_blockhash)
: m_mempool(mempool),
m_blockman(blockman),
- m_params(chainman.GetParams()),
m_chainman(chainman),
m_from_snapshot_blockhash(from_snapshot_blockhash) {}
@@ -1515,11 +1565,18 @@ void Chainstate::InitCoinsDB(
fs::path leveldb_name)
{
if (m_from_snapshot_blockhash) {
- leveldb_name += "_" + m_from_snapshot_blockhash->ToString();
+ leveldb_name += node::SNAPSHOT_CHAINSTATE_SUFFIX;
}
m_coins_views = std::make_unique<CoinsViews>(
- leveldb_name, cache_size_bytes, in_memory, should_wipe);
+ DBParams{
+ .path = m_chainman.m_options.datadir / leveldb_name,
+ .cache_bytes = cache_size_bytes,
+ .memory_only = in_memory,
+ .wipe_data = should_wipe,
+ .obfuscate = true,
+ .options = m_chainman.m_options.coins_db},
+ m_chainman.m_options.coins_view);
}
void Chainstate::InitCoinsCache(size_t cache_size_bytes)
@@ -1544,14 +1601,17 @@ bool Chainstate::IsInitialBlockDownload() const
LOCK(cs_main);
if (m_cached_finished_ibd.load(std::memory_order_relaxed))
return false;
- if (fImporting || fReindex)
+ if (m_chainman.m_blockman.LoadingBlocks()) {
return true;
+ }
if (m_chain.Tip() == nullptr)
return true;
- if (m_chain.Tip()->nChainWork < nMinimumChainWork)
+ if (m_chain.Tip()->nChainWork < m_chainman.MinimumChainWork()) {
return true;
- if (m_chain.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
+ }
+ if (m_chain.Tip()->Time() < Now<NodeSeconds>() - m_chainman.m_options.max_tip_age) {
return true;
+ }
LogPrintf("Leaving InitialBlockDownload (latching to false)\n");
m_cached_finished_ibd.store(true, std::memory_order_relaxed);
return false;
@@ -1840,11 +1900,21 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
return DISCONNECT_FAILED;
}
+ // Ignore blocks that contain transactions which are 'overwritten' by later transactions,
+ // unless those are already completely spent.
+ // See https://github.com/bitcoin/bitcoin/issues/22596 for additional information.
+ // Note: the blocks specified here are different than the ones used in ConnectBlock because DisconnectBlock
+ // unwinds the blocks in reverse. As a result, the inconsistency is not discovered until the earlier
+ // blocks with the duplicate coinbase transactions are disconnected.
+ bool fEnforceBIP30 = !((pindex->nHeight==91722 && pindex->GetBlockHash() == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) ||
+ (pindex->nHeight==91812 && pindex->GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f")));
+
// undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction &tx = *(block.vtx[i]);
uint256 hash = tx.GetHash();
bool is_coinbase = tx.IsCoinBase();
+ bool is_bip30_exception = (is_coinbase && !fEnforceBIP30);
// Check that all outputs are available and match the outputs in the block itself
// exactly.
@@ -1854,7 +1924,9 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
Coin coin;
bool is_spent = view.SpendCoin(out, &coin);
if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) {
- fClean = false; // transaction output mismatch
+ if (!is_bip30_exception) {
+ fClean = false; // transaction output mismatch
+ }
}
}
}
@@ -1965,14 +2037,14 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Ch
}
-static int64_t nTimeCheck = 0;
-static int64_t nTimeForks = 0;
-static int64_t nTimeConnect = 0;
-static int64_t nTimeVerify = 0;
-static int64_t nTimeUndo = 0;
-static int64_t nTimeIndex = 0;
-static int64_t nTimeTotal = 0;
-static int64_t nBlocksTotal = 0;
+static SteadyClock::duration time_check{};
+static SteadyClock::duration time_forks{};
+static SteadyClock::duration time_connect{};
+static SteadyClock::duration time_verify{};
+static SteadyClock::duration time_undo{};
+static SteadyClock::duration time_index{};
+static SteadyClock::duration time_total{};
+static int64_t num_blocks_total = 0;
/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
@@ -1985,8 +2057,10 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
uint256 block_hash{block.GetHash()};
assert(*pindex->phashBlock == block_hash);
+ const bool parallel_script_checks{scriptcheckqueue.HasThreads()};
- int64_t nTimeStart = GetTimeMicros();
+ const auto time_start{SteadyClock::now()};
+ const CChainParams& params{m_chainman.GetParams()};
// Check it again in case a previous version let a bad block in
// NOTE: We don't currently (re-)invoke ContextualCheckBlock() or
@@ -2001,7 +2075,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// is enforced in ContextualCheckBlockHeader(); we wouldn't want to
// re-enforce that rule here (at least until we make it impossible for
// m_adjusted_time_callback() to go backward).
- if (!CheckBlock(block, state, m_params.GetConsensus(), !fJustCheck, !fJustCheck)) {
+ if (!CheckBlock(block, state, params.GetConsensus(), !fJustCheck, !fJustCheck)) {
if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED) {
// We don't write down blocks to disk if they may have been
// corrupted, so this should be impossible unless we're having hardware
@@ -2015,28 +2089,28 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash();
assert(hashPrevBlock == view.GetBestBlock());
- nBlocksTotal++;
+ num_blocks_total++;
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
- if (block_hash == m_params.GetConsensus().hashGenesisBlock) {
+ if (block_hash == params.GetConsensus().hashGenesisBlock) {
if (!fJustCheck)
view.SetBestBlock(pindex->GetBlockHash());
return true;
}
bool fScriptChecks = true;
- if (!hashAssumeValid.IsNull()) {
+ if (!m_chainman.AssumedValidBlock().IsNull()) {
// We've been configured with the hash of a block which has been externally verified to have a valid history.
// A suitable default value is included with the software and updated from time to time. Because validity
// relative to a piece of software is an objective fact these defaults can be easily reviewed.
// This setting doesn't force the selection of any particular chain but makes validating some faster by
// effectively caching the result of part of the verification.
- BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid);
+ BlockMap::const_iterator it{m_blockman.m_block_index.find(m_chainman.AssumedValidBlock())};
if (it != m_blockman.m_block_index.end()) {
if (it->second.GetAncestor(pindex->nHeight) == pindex &&
m_chainman.m_best_header->GetAncestor(pindex->nHeight) == pindex &&
- m_chainman.m_best_header->nChainWork >= nMinimumChainWork) {
+ m_chainman.m_best_header->nChainWork >= m_chainman.MinimumChainWork()) {
// This block is a member of the assumed verified chain and an ancestor of the best header.
// Script verification is skipped when connecting blocks under the
// assumevalid block. Assuming the assumevalid block is valid this
@@ -2049,15 +2123,19 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// it hard to hide the implication of the demand. This also avoids having release candidates
// that are hardly doing any signature verification at all in testing without having to
// artificially set the default assumed verified block further back.
- // The test against nMinimumChainWork prevents the skipping when denied access to any chain at
+ // The test against the minimum chain work prevents the skipping when denied access to any chain at
// least as good as the expected chain.
- fScriptChecks = (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
+ fScriptChecks = (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
}
}
}
- int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart;
- LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime1 - nTimeStart), nTimeCheck * MICRO, nTimeCheck * MILLI / nBlocksTotal);
+ const auto time_1{SteadyClock::now()};
+ time_check += time_1 - time_start;
+ LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_1 - time_start),
+ Ticks<SecondsDouble>(time_check),
+ Ticks<MillisecondsDouble>(time_check) / num_blocks_total);
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
@@ -2069,8 +2147,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the
// two in the chain that violate it. This prevents exploiting the issue against nodes during their
// initial block download.
- bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
- (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
+ bool fEnforceBIP30 = !IsBIP30Repeat(*pindex);
// Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting
// with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the
@@ -2128,9 +2205,9 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// post BIP34 before approximately height 486,000,000. After block
// 1,983,702 testnet3 starts doing unnecessary BIP30 checking again.
assert(pindex->pprev);
- CBlockIndex* pindexBIP34height = pindex->pprev->GetAncestor(m_params.GetConsensus().BIP34Height);
+ CBlockIndex* pindexBIP34height = pindex->pprev->GetAncestor(params.GetConsensus().BIP34Height);
//Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond.
- fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == m_params.GetConsensus().BIP34Hash));
+ fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == params.GetConsensus().BIP34Hash));
// TODO: Remove BIP30 checking from block height 1,983,702 on, once we have a
// consensus change that ensures coinbases at those heights cannot
@@ -2155,8 +2232,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// Get the script flags for this block
unsigned int flags{GetBlockScriptFlags(*pindex, m_chainman)};
- int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
- LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal);
+ const auto time_2{SteadyClock::now()};
+ time_forks += time_2 - time_1;
+ LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_2 - time_1),
+ Ticks<SecondsDouble>(time_forks),
+ Ticks<MillisecondsDouble>(time_forks) / num_blocks_total);
CBlockUndo blockundo;
@@ -2165,7 +2246,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// in multiple threads). Preallocate the vector size so a new allocation
// doesn't invalidate pointers into the vector, and keep txsdata in scope
// for as long as `control`.
- CCheckQueueControl<CScriptCheck> control(fScriptChecks && g_parallel_script_checks ? &scriptcheckqueue : nullptr);
+ CCheckQueueControl<CScriptCheck> control(fScriptChecks && parallel_script_checks ? &scriptcheckqueue : nullptr);
std::vector<PrecomputedTransactionData> txsdata(block.vtx.size());
std::vector<int> prevheights;
@@ -2224,7 +2305,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
TxValidationState tx_state;
- if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], g_parallel_script_checks ? &vChecks : nullptr)) {
+ if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], parallel_script_checks ? &vChecks : nullptr)) {
// Any transaction validation failure in ConnectBlock is a block consensus failure
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
tx_state.GetRejectReason(), tx_state.GetDebugMessage());
@@ -2240,10 +2321,15 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
}
UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
}
- int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
- LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
+ const auto time_3{SteadyClock::now()};
+ time_connect += time_3 - time_2;
+ LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(),
+ Ticks<MillisecondsDouble>(time_3 - time_2), Ticks<MillisecondsDouble>(time_3 - time_2) / block.vtx.size(),
+ nInputs <= 1 ? 0 : Ticks<MillisecondsDouble>(time_3 - time_2) / (nInputs - 1),
+ Ticks<SecondsDouble>(time_connect),
+ Ticks<MillisecondsDouble>(time_connect) / num_blocks_total);
- CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, m_params.GetConsensus());
+ CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, params.GetConsensus());
if (block.vtx[0]->GetValueOut() > blockReward) {
LogPrintf("ERROR: ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)\n", block.vtx[0]->GetValueOut(), blockReward);
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount");
@@ -2253,18 +2339,27 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
LogPrintf("ERROR: %s: CheckQueue failed\n", __func__);
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "block-validation-failed");
}
- int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
- LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
+ const auto time_4{SteadyClock::now()};
+ time_verify += time_4 - time_2;
+ LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1,
+ Ticks<MillisecondsDouble>(time_4 - time_2),
+ nInputs <= 1 ? 0 : Ticks<MillisecondsDouble>(time_4 - time_2) / (nInputs - 1),
+ Ticks<SecondsDouble>(time_verify),
+ Ticks<MillisecondsDouble>(time_verify) / num_blocks_total);
if (fJustCheck)
return true;
- if (!m_blockman.WriteUndoDataForBlock(blockundo, state, pindex, m_params)) {
+ if (!m_blockman.WriteUndoDataForBlock(blockundo, state, pindex, params)) {
return false;
}
- int64_t nTime5 = GetTimeMicros(); nTimeUndo += nTime5 - nTime4;
- LogPrint(BCLog::BENCH, " - Write undo data: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeUndo * MICRO, nTimeUndo * MILLI / nBlocksTotal);
+ const auto time_5{SteadyClock::now()};
+ time_undo += time_5 - time_4;
+ LogPrint(BCLog::BENCH, " - Write undo data: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_5 - time_4),
+ Ticks<SecondsDouble>(time_undo),
+ Ticks<MillisecondsDouble>(time_undo) / num_blocks_total);
if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
@@ -2274,8 +2369,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
- int64_t nTime6 = GetTimeMicros(); nTimeIndex += nTime6 - nTime5;
- LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime6 - nTime5), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal);
+ const auto time_6{SteadyClock::now()};
+ time_index += time_6 - time_5;
+ LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_6 - time_5),
+ Ticks<SecondsDouble>(time_index),
+ Ticks<MillisecondsDouble>(time_index) / num_blocks_total);
TRACE6(validation, block_connected,
block_hash.data(),
@@ -2283,7 +2382,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
block.vtx.size(),
nInputs,
nSigOpsCost,
- nTime5 - nTimeStart // in microseconds (µs)
+ time_5 - time_start // in microseconds (µs)
);
return true;
@@ -2328,8 +2427,6 @@ bool Chainstate::FlushStateToDisk(
{
LOCK(cs_main);
assert(this->CanFlushToDisk());
- static std::chrono::microseconds nLastWrite{0};
- static std::chrono::microseconds nLastFlush{0};
std::set<int> setFilesToPrune;
bool full_flush_completed = false;
@@ -2343,7 +2440,7 @@ bool Chainstate::FlushStateToDisk(
CoinsCacheSizeState cache_state = GetCoinsCacheSizeState();
LOCK(m_blockman.cs_LastBlockFile);
- if (fPruneMode && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && !fReindex) {
+ if (m_blockman.IsPruneMode() && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && !fReindex) {
// make sure we don't prune above any of the prune locks bestblocks
// pruning is height-based
int last_prune{m_chain.Height()}; // last height we can prune
@@ -2370,7 +2467,7 @@ bool Chainstate::FlushStateToDisk(
} else {
LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", BCLog::BENCH);
- m_blockman.FindFilesToPrune(setFilesToPrune, m_params.PruneAfterHeight(), m_chain.Height(), last_prune, IsInitialBlockDownload());
+ m_blockman.FindFilesToPrune(setFilesToPrune, m_chainman.GetParams().PruneAfterHeight(), m_chain.Height(), last_prune, IsInitialBlockDownload());
m_blockman.m_check_for_pruning = false;
}
if (!setFilesToPrune.empty()) {
@@ -2381,22 +2478,22 @@ bool Chainstate::FlushStateToDisk(
}
}
}
- const auto nNow = GetTime<std::chrono::microseconds>();
+ const auto nNow{SteadyClock::now()};
// Avoid writing/flushing immediately after startup.
- if (nLastWrite.count() == 0) {
- nLastWrite = nNow;
+ if (m_last_write == decltype(m_last_write){}) {
+ m_last_write = nNow;
}
- if (nLastFlush.count() == 0) {
- nLastFlush = nNow;
+ if (m_last_flush == decltype(m_last_flush){}) {
+ m_last_flush = nNow;
}
// The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing).
bool fCacheLarge = mode == FlushStateMode::PERIODIC && cache_state >= CoinsCacheSizeState::LARGE;
// The cache is over the limit, we have to write now.
bool fCacheCritical = mode == FlushStateMode::IF_NEEDED && cache_state >= CoinsCacheSizeState::CRITICAL;
// It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash.
- bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow > nLastWrite + DATABASE_WRITE_INTERVAL;
+ bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow > m_last_write + DATABASE_WRITE_INTERVAL;
// It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
- bool fPeriodicFlush = mode == FlushStateMode::PERIODIC && nNow > nLastFlush + DATABASE_FLUSH_INTERVAL;
+ bool fPeriodicFlush = mode == FlushStateMode::PERIODIC && nNow > m_last_flush + DATABASE_FLUSH_INTERVAL;
// Combine all conditions that result in a full cache flush.
fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
// Write blocks and block index to disk.
@@ -2426,7 +2523,7 @@ bool Chainstate::FlushStateToDisk(
UnlinkPrunedFiles(setFilesToPrune);
}
- nLastWrite = nNow;
+ m_last_write = nNow;
}
// Flush best chain related state. This can only be done if the blocks / block index write was also done.
if (fDoFullFlush && !CoinsTip().GetBestBlock().IsNull()) {
@@ -2444,10 +2541,10 @@ bool Chainstate::FlushStateToDisk(
// Flush the chainstate (which may refer to block index entries).
if (!CoinsTip().Flush())
return AbortNode(state, "Failed to write to coin database");
- nLastFlush = nNow;
+ m_last_flush = nNow;
full_flush_completed = true;
TRACE5(utxocache, flush,
- (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs)
+ int64_t{Ticks<std::chrono::microseconds>(SteadyClock::now() - nNow)},
(uint32_t)mode,
(uint64_t)coins_count,
(uint64_t)coins_mem_usage,
@@ -2524,13 +2621,15 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew)
AssertLockHeld(::cs_main);
const auto& coins_tip = this->CoinsTip();
+ const CChainParams& params{m_chainman.GetParams()};
+
// The remainder of the function isn't relevant if we are not acting on
// the active chainstate, so return if need be.
if (this != &m_chainman.ActiveChainstate()) {
// Only log every so often so that we don't bury log messages at the tip.
constexpr int BACKGROUND_LOG_INTERVAL = 2000;
if (pindexNew->nHeight % BACKGROUND_LOG_INTERVAL == 0) {
- UpdateTipLog(coins_tip, pindexNew, m_params, __func__, "[background validation] ", "");
+ UpdateTipLog(coins_tip, pindexNew, params, __func__, "[background validation] ", "");
}
return;
}
@@ -2551,7 +2650,7 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew)
const CBlockIndex* pindex = pindexNew;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(m_chainman, bit);
- ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache.at(bit));
+ ThresholdState state = checker.GetStateFor(pindex, params.GetConsensus(), warningcache.at(bit));
if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
if (state == ThresholdState::ACTIVE) {
@@ -2562,7 +2661,7 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew)
}
}
}
- UpdateTipLog(coins_tip, pindexNew, m_params, __func__, "", warning_messages.original);
+ UpdateTipLog(coins_tip, pindexNew, params, __func__, "", warning_messages.original);
}
/** Disconnect m_chain's tip.
@@ -2586,11 +2685,11 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
// Read block from disk.
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
CBlock& block = *pblock;
- if (!ReadBlockFromDisk(block, pindexDelete, m_params.GetConsensus())) {
+ if (!ReadBlockFromDisk(block, pindexDelete, m_chainman.GetConsensus())) {
return error("DisconnectTip(): Failed to read block");
}
// Apply the block atomically to the chain state.
- int64_t nStart = GetTimeMicros();
+ const auto time_start{SteadyClock::now()};
{
CCoinsViewCache view(&CoinsTip());
assert(view.GetBestBlock() == pindexDelete->GetBlockHash());
@@ -2599,7 +2698,8 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
bool flushed = view.Flush();
assert(flushed);
}
- LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI);
+ LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n",
+ Ticks<MillisecondsDouble>(SteadyClock::now() - time_start));
{
// Prune locks that began at or after the tip should be moved backward so they get a chance to reorg
@@ -2639,11 +2739,11 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
return true;
}
-static int64_t nTimeReadFromDiskTotal = 0;
-static int64_t nTimeConnectTotal = 0;
-static int64_t nTimeFlush = 0;
-static int64_t nTimeChainState = 0;
-static int64_t nTimePostConnect = 0;
+static SteadyClock::duration time_read_from_disk_total{};
+static SteadyClock::duration time_connect_total{};
+static SteadyClock::duration time_flush{};
+static SteadyClock::duration time_chainstate{};
+static SteadyClock::duration time_post_connect{};
struct PerBlockConnectTrace {
CBlockIndex* pindex = nullptr;
@@ -2698,11 +2798,11 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
assert(pindexNew->pprev == m_chain.Tip());
// Read block from disk.
- int64_t nTime1 = GetTimeMicros();
+ const auto time_1{SteadyClock::now()};
std::shared_ptr<const CBlock> pthisBlock;
if (!pblock) {
std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
- if (!ReadBlockFromDisk(*pblockNew, pindexNew, m_params.GetConsensus())) {
+ if (!ReadBlockFromDisk(*pblockNew, pindexNew, m_chainman.GetConsensus())) {
return AbortNode(state, "Failed to read block");
}
pthisBlock = pblockNew;
@@ -2712,9 +2812,13 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
}
const CBlock& blockConnecting = *pthisBlock;
// Apply the block atomically to the chain state.
- int64_t nTime2 = GetTimeMicros(); nTimeReadFromDiskTotal += nTime2 - nTime1;
- int64_t nTime3;
- LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDiskTotal * MICRO, nTimeReadFromDiskTotal * MILLI / nBlocksTotal);
+ const auto time_2{SteadyClock::now()};
+ time_read_from_disk_total += time_2 - time_1;
+ SteadyClock::time_point time_3;
+ LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_2 - time_1),
+ Ticks<SecondsDouble>(time_read_from_disk_total),
+ Ticks<MillisecondsDouble>(time_read_from_disk_total) / num_blocks_total);
{
CCoinsViewCache view(&CoinsTip());
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view);
@@ -2724,20 +2828,32 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
InvalidBlockFound(pindexNew, state);
return error("%s: ConnectBlock %s failed, %s", __func__, pindexNew->GetBlockHash().ToString(), state.ToString());
}
- nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
- assert(nBlocksTotal > 0);
- LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal);
+ time_3 = SteadyClock::now();
+ time_connect_total += time_3 - time_2;
+ assert(num_blocks_total > 0);
+ LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_3 - time_2),
+ Ticks<SecondsDouble>(time_connect_total),
+ Ticks<MillisecondsDouble>(time_connect_total) / num_blocks_total);
bool flushed = view.Flush();
assert(flushed);
}
- int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
- LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal);
+ const auto time_4{SteadyClock::now()};
+ time_flush += time_4 - time_3;
+ LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_4 - time_3),
+ Ticks<SecondsDouble>(time_flush),
+ Ticks<MillisecondsDouble>(time_flush) / num_blocks_total);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(state, FlushStateMode::IF_NEEDED)) {
return false;
}
- int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
- LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal);
+ const auto time_5{SteadyClock::now()};
+ time_chainstate += time_5 - time_4;
+ LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_5 - time_4),
+ Ticks<SecondsDouble>(time_chainstate),
+ Ticks<MillisecondsDouble>(time_chainstate) / num_blocks_total);
// Remove conflicting transactions from the mempool.;
if (m_mempool) {
m_mempool->removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
@@ -2747,9 +2863,25 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
m_chain.SetTip(*pindexNew);
UpdateTip(pindexNew);
- int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
- LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal);
- LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime1) * MILLI, nTimeTotal * MICRO, nTimeTotal * MILLI / nBlocksTotal);
+ const auto time_6{SteadyClock::now()};
+ time_post_connect += time_6 - time_5;
+ time_total += time_6 - time_1;
+ LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_6 - time_5),
+ Ticks<SecondsDouble>(time_post_connect),
+ Ticks<MillisecondsDouble>(time_post_connect) / num_blocks_total);
+ LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks<MillisecondsDouble>(time_6 - time_1),
+ Ticks<SecondsDouble>(time_total),
+ Ticks<MillisecondsDouble>(time_total) / num_blocks_total);
+
+ // If we are the background validation chainstate, check to see if we are done
+ // validating the snapshot (i.e. our tip has reached the snapshot's base block).
+ if (this != &m_chainman.ActiveChainstate()) {
+ // This call may set `m_disabled`, which is referenced immediately afterwards in
+ // ActivateBestChain, so that we stop connecting blocks past the snapshot base.
+ m_chainman.MaybeCompleteSnapshotValidation();
+ }
connectTrace.BlockConnected(pindexNew, std::move(pthisBlock));
return true;
@@ -2973,6 +3105,14 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
// we use m_chainstate_mutex to enforce mutual exclusion so that only one caller may execute this function at a time
LOCK(m_chainstate_mutex);
+ // Belt-and-suspenders check that we aren't attempting to advance the background
+ // chainstate past the snapshot base block.
+ if (WITH_LOCK(::cs_main, return m_disabled)) {
+ LogPrintf("m_disabled is set - this chainstate should not be in operation. " /* Continued */
+ "Please report this as a bug. %s\n", PACKAGE_BUGREPORT);
+ return false;
+ }
+
CBlockIndex *pindexMostWork = nullptr;
CBlockIndex *pindexNewTip = nullptr;
int nStopAtHeight = gArgs.GetIntArg("-stopatheight", DEFAULT_STOPATHEIGHT);
@@ -3023,6 +3163,15 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
assert(trace.pblock && trace.pindex);
GetMainSignals().BlockConnected(trace.pblock, trace.pindex);
}
+
+ // This will have been toggled in
+ // ActivateBestChainStep -> ConnectTip -> MaybeCompleteSnapshotValidation,
+ // if at all, so we should catch it here.
+ //
+ // Break this do-while to ensure we don't advance past the base snapshot.
+ if (m_disabled) {
+ break;
+ }
} while (!m_chain.Tip() || (starting_tip && CBlockIndexWorkComparator()(m_chain.Tip(), starting_tip)));
if (!blocks_connected) return true;
@@ -3043,6 +3192,11 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();
+ if (WITH_LOCK(::cs_main, return m_disabled)) {
+ // Background chainstate has reached the snapshot base block, so exit.
+ break;
+ }
+
// We check shutdown only after giving ActivateBestChainStep a chance to run once so that we
// never shutdown before connecting the genesis block during LoadChainTip(). Previously this
// caused an assert() failure during shutdown in such cases as the UTXO DB flushing checks
@@ -3469,7 +3623,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-diffbits", "incorrect proof of work");
// Check against checkpoints
- if (fCheckpointsEnabled) {
+ if (chainman.m_options.checkpoints_enabled) {
// Don't accept any forks from the main chain prior to last checkpoint.
// GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's in our
// BlockIndex().
@@ -3617,12 +3771,12 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
CBlockIndex* pindexPrev = nullptr;
BlockMap::iterator mi{m_blockman.m_block_index.find(block.hashPrevBlock)};
if (mi == m_blockman.m_block_index.end()) {
- LogPrint(BCLog::VALIDATION, "%s: %s prev block not found\n", __func__, hash.ToString());
+ LogPrint(BCLog::VALIDATION, "header %s has prev block not found: %s\n", hash.ToString(), block.hashPrevBlock.ToString());
return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, "prev-blk-not-found");
}
pindexPrev = &((*mi).second);
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) {
- LogPrint(BCLog::VALIDATION, "%s: %s prev block invalid\n", __func__, hash.ToString());
+ LogPrint(BCLog::VALIDATION, "header %s has prev block invalid: %s\n", hash.ToString(), block.hashPrevBlock.ToString());
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk");
}
if (!ContextualCheckBlockHeader(block, state, m_blockman, *this, pindexPrev, m_options.adjusted_time_callback())) {
@@ -3663,7 +3817,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
m_blockman.m_dirty_blockindex.insert(invalid_walk);
invalid_walk = invalid_walk->pprev;
}
- LogPrint(BCLog::VALIDATION, "%s: %s prev block invalid\n", __func__, hash.ToString());
+ LogPrint(BCLog::VALIDATION, "header %s has prev block invalid: %s\n", hash.ToString(), block.hashPrevBlock.ToString());
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk");
}
}
@@ -3783,10 +3937,12 @@ bool Chainstate::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockV
// If our tip is behind, a peer could try to send us
// low-work blocks on a fake chain that we would never
// request; don't process these.
- if (pindex->nChainWork < nMinimumChainWork) return true;
+ if (pindex->nChainWork < m_chainman.MinimumChainWork()) return true;
}
- if (!CheckBlock(block, state, m_params.GetConsensus()) ||
+ const CChainParams& params{m_chainman.GetParams()};
+
+ if (!CheckBlock(block, state, params.GetConsensus()) ||
!ContextualCheckBlock(block, state, m_chainman, pindex->pprev)) {
if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
pindex->nStatus |= BLOCK_FAILED_VALID;
@@ -3803,7 +3959,7 @@ bool Chainstate::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockV
// Write block to history file
if (fNewBlock) *fNewBlock = true;
try {
- FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, pindex->nHeight, m_chain, m_params, dbp)};
+ FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, pindex->nHeight, m_chain, params, dbp)};
if (blockPos.IsNull()) {
state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__));
return false;
@@ -3947,7 +4103,7 @@ bool Chainstate::LoadChainTip()
tip->GetBlockHash().ToString(),
m_chain.Height(),
FormatISO8601DateTime(tip->GetBlockTime()),
- GuessVerificationProgress(m_params.TxData(), tip));
+ GuessVerificationProgress(m_chainman.GetParams().TxData(), tip));
return true;
}
@@ -3961,7 +4117,7 @@ CVerifyDB::~CVerifyDB()
uiInterface.ShowProgress("", 100, false);
}
-bool CVerifyDB::VerifyDB(
+VerifyDBResult CVerifyDB::VerifyDB(
Chainstate& chainstate,
const Consensus::Params& consensus_params,
CCoinsView& coinsview,
@@ -3970,7 +4126,7 @@ bool CVerifyDB::VerifyDB(
AssertLockHeld(cs_main);
if (chainstate.m_chain.Tip() == nullptr || chainstate.m_chain.Tip()->pprev == nullptr) {
- return true;
+ return VerifyDBResult::SUCCESS;
}
// Verify blocks in the best chain
@@ -3985,7 +4141,9 @@ bool CVerifyDB::VerifyDB(
int nGoodTransactions = 0;
BlockValidationState state;
int reportDone = 0;
- LogPrintf("[0%%]..."); /* Continued */
+ bool skipped_no_block_data{false};
+ bool skipped_l3_checks{false};
+ LogPrintf("Verification progress: 0%%\n");
const bool is_snapshot_cs{!chainstate.m_from_snapshot_blockhash};
@@ -3993,88 +4151,109 @@ bool CVerifyDB::VerifyDB(
const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
if (reportDone < percentageDone / 10) {
// report every 10% step
- LogPrintf("[%d%%]...", percentageDone); /* Continued */
+ LogPrintf("Verification progress: %d%%\n", percentageDone);
reportDone = percentageDone / 10;
}
uiInterface.ShowProgress(_("Verifying blocks…").translated, percentageDone, false);
if (pindex->nHeight <= chainstate.m_chain.Height() - nCheckDepth) {
break;
}
- if ((fPruneMode || is_snapshot_cs) && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
+ if ((chainstate.m_blockman.IsPruneMode() || is_snapshot_cs) && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
// If pruning or running under an assumeutxo snapshot, only go
// back as far as we have data.
- LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight);
+ LogPrintf("VerifyDB(): block verification stopping at height %d (no data). This could be due to pruning or use of an assumeutxo snapshot.\n", pindex->nHeight);
+ skipped_no_block_data = true;
break;
}
CBlock block;
// check level 0: read from disk
if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
- return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
+ LogPrintf("Verification error: ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
// check level 1: verify block validity
if (nCheckLevel >= 1 && !CheckBlock(block, state, consensus_params)) {
- return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__,
- pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
+ LogPrintf("Verification error: found bad block at %d, hash=%s (%s)\n",
+ pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
+ return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {
CBlockUndo undo;
if (!pindex->GetUndoPos().IsNull()) {
if (!UndoReadFromDisk(undo, pindex)) {
- return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ LogPrintf("Verification error: found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
}
}
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
size_t curr_coins_usage = coins.DynamicMemoryUsage() + chainstate.CoinsTip().DynamicMemoryUsage();
- if (nCheckLevel >= 3 && curr_coins_usage <= chainstate.m_coinstip_cache_size_bytes) {
- assert(coins.GetBestBlock() == pindex->GetBlockHash());
- DisconnectResult res = chainstate.DisconnectBlock(block, pindex, coins);
- if (res == DISCONNECT_FAILED) {
- return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
- }
- if (res == DISCONNECT_UNCLEAN) {
- nGoodTransactions = 0;
- pindexFailure = pindex;
+ if (nCheckLevel >= 3) {
+ if (curr_coins_usage <= chainstate.m_coinstip_cache_size_bytes) {
+ assert(coins.GetBestBlock() == pindex->GetBlockHash());
+ DisconnectResult res = chainstate.DisconnectBlock(block, pindex, coins);
+ if (res == DISCONNECT_FAILED) {
+ LogPrintf("Verification error: irrecoverable inconsistency in block data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ return VerifyDBResult::CORRUPTED_BLOCK_DB;
+ }
+ if (res == DISCONNECT_UNCLEAN) {
+ nGoodTransactions = 0;
+ pindexFailure = pindex;
+ } else {
+ nGoodTransactions += block.vtx.size();
+ }
} else {
- nGoodTransactions += block.vtx.size();
+ skipped_l3_checks = true;
}
}
- if (ShutdownRequested()) return true;
+ if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED;
}
if (pindexFailure) {
- return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainstate.m_chain.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
+ LogPrintf("Verification error: coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainstate.m_chain.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
+ return VerifyDBResult::CORRUPTED_BLOCK_DB;
+ }
+ if (skipped_l3_checks) {
+ LogPrintf("Skipped verification of level >=3 (insufficient database cache size). Consider increasing -dbcache.\n");
}
// store block count as we move pindex at check level >= 4
int block_count = chainstate.m_chain.Height() - pindex->nHeight;
// check level 4: try reconnecting blocks
- if (nCheckLevel >= 4) {
+ if (nCheckLevel >= 4 && !skipped_l3_checks) {
while (pindex != chainstate.m_chain.Tip()) {
const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)));
if (reportDone < percentageDone / 10) {
// report every 10% step
- LogPrintf("[%d%%]...", percentageDone); /* Continued */
+ LogPrintf("Verification progress: %d%%\n", percentageDone);
reportDone = percentageDone / 10;
}
uiInterface.ShowProgress(_("Verifying blocks…").translated, percentageDone, false);
pindex = chainstate.m_chain.Next(pindex);
CBlock block;
- if (!ReadBlockFromDisk(block, pindex, consensus_params))
- return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
+ if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
+ LogPrintf("Verification error: ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ return VerifyDBResult::CORRUPTED_BLOCK_DB;
+ }
if (!chainstate.ConnectBlock(block, state, pindex, coins)) {
- return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
+ LogPrintf("Verification error: found unconnectable block at %d, hash=%s (%s)\n", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
+ return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
- if (ShutdownRequested()) return true;
+ if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED;
}
}
- LogPrintf("[DONE].\n");
- LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", block_count, nGoodTransactions);
+ LogPrintf("Verification: No coin database inconsistencies in last %i blocks (%i transactions)\n", block_count, nGoodTransactions);
- return true;
+ if (skipped_l3_checks) {
+ return VerifyDBResult::SKIPPED_L3_CHECKS;
+ }
+ if (skipped_no_block_data) {
+ return VerifyDBResult::SKIPPED_MISSING_BLOCKS;
+ }
+ return VerifyDBResult::SUCCESS;
}
/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */
@@ -4083,7 +4262,7 @@ bool Chainstate::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& in
AssertLockHeld(cs_main);
// TODO: merge with ConnectBlock
CBlock block;
- if (!ReadBlockFromDisk(block, pindex, m_params.GetConsensus())) {
+ if (!ReadBlockFromDisk(block, pindex, m_chainman.GetConsensus())) {
return error("ReplayBlock(): ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
@@ -4135,7 +4314,7 @@ bool Chainstate::ReplayBlocks()
while (pindexOld != pindexFork) {
if (pindexOld->nHeight > 0) { // Never disconnect the genesis block.
CBlock block;
- if (!ReadBlockFromDisk(block, pindexOld, m_params.GetConsensus())) {
+ if (!ReadBlockFromDisk(block, pindexOld, m_chainman.GetConsensus())) {
return error("RollbackBlock(): ReadBlockFromDisk() failed at %d, hash=%s", pindexOld->nHeight, pindexOld->GetBlockHash().ToString());
}
LogPrintf("Rolling back %s (%i)\n", pindexOld->GetBlockHash().ToString(), pindexOld->nHeight);
@@ -4201,6 +4380,8 @@ bool ChainstateManager::LoadBlockIndex()
bool ret = m_blockman.LoadBlockIndexDB(GetConsensus());
if (!ret) return false;
+ m_blockman.ScanAndUnlinkAlreadyPrunedFiles();
+
std::vector<CBlockIndex*> vSortedByHeight{m_blockman.GetAllBlockIndices()};
std::sort(vSortedByHeight.begin(), vSortedByHeight.end(),
CBlockIndexHeightOnlyComparator());
@@ -4221,6 +4402,8 @@ bool ChainstateManager::LoadBlockIndex()
assert(any_chain([](auto chainstate) { return !chainstate->reliesOnAssumedValid(); }));
first_assumed_valid_height = block->nHeight;
+ LogPrintf("Saw first assumedvalid block at height %d (%s)\n",
+ first_assumed_valid_height, block->ToString());
break;
}
}
@@ -4287,16 +4470,18 @@ bool Chainstate::LoadGenesisBlock()
{
LOCK(cs_main);
+ const CChainParams& params{m_chainman.GetParams()};
+
// Check whether we're already initialized by checking for genesis in
// m_blockman.m_block_index. Note that we can't use m_chain here, since it is
// set based on the coins db, not the block index db, which is the only
// thing loaded at this point.
- if (m_blockman.m_block_index.count(m_params.GenesisBlock().GetHash()))
+ if (m_blockman.m_block_index.count(params.GenesisBlock().GetHash()))
return true;
try {
- const CBlock& block = m_params.GenesisBlock();
- FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, 0, m_chain, m_params, nullptr)};
+ const CBlock& block = params.GenesisBlock();
+ FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, 0, m_chain, params, nullptr)};
if (blockPos.IsNull()) {
return error("%s: writing genesis block to disk failed", __func__);
}
@@ -4320,11 +4505,14 @@ void Chainstate::LoadExternalBlockFile(
assert(!dbp == !blocks_with_unknown_parent);
const auto start{SteadyClock::now()};
+ const CChainParams& params{m_chainman.GetParams()};
int nLoaded = 0;
try {
// This takes over fileIn and calls fclose() on it in the CBufferedFile destructor
CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SERIALIZED_SIZE, MAX_BLOCK_SERIALIZED_SIZE+8, SER_DISK, CLIENT_VERSION);
+ // nRewind indicates where to resume scanning in case something goes wrong,
+ // such as a block fails to deserialize.
uint64_t nRewind = blkdat.GetPos();
while (!blkdat.eof()) {
if (ShutdownRequested()) return;
@@ -4336,10 +4524,10 @@ void Chainstate::LoadExternalBlockFile(
try {
// locate a header
unsigned char buf[CMessageHeader::MESSAGE_START_SIZE];
- blkdat.FindByte(m_params.MessageStart()[0]);
+ blkdat.FindByte(params.MessageStart()[0]);
nRewind = blkdat.GetPos() + 1;
blkdat >> buf;
- if (memcmp(buf, m_params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE)) {
+ if (memcmp(buf, params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE)) {
continue;
}
// read size
@@ -4348,28 +4536,30 @@ void Chainstate::LoadExternalBlockFile(
continue;
} catch (const std::exception&) {
// no valid block header found; don't complain
+ // (this happens at the end of every blk.dat file)
break;
}
try {
- // read block
- uint64_t nBlockPos = blkdat.GetPos();
+ // read block header
+ const uint64_t nBlockPos{blkdat.GetPos()};
if (dbp)
dbp->nPos = nBlockPos;
blkdat.SetLimit(nBlockPos + nSize);
- std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
- CBlock& block = *pblock;
- blkdat >> block;
- nRewind = blkdat.GetPos();
-
- uint256 hash = block.GetHash();
+ CBlockHeader header;
+ blkdat >> header;
+ const uint256 hash{header.GetHash()};
+ // Skip the rest of this block (this may read from disk into memory); position to the marker before the
+ // next block, but it's still possible to rewind to the start of the current block (without a disk read).
+ nRewind = nBlockPos + nSize;
+ blkdat.SkipTo(nRewind);
{
LOCK(cs_main);
// detect out of order blocks, and store them for later
- if (hash != m_params.GetConsensus().hashGenesisBlock && !m_blockman.LookupBlockIndex(block.hashPrevBlock)) {
+ if (hash != params.GetConsensus().hashGenesisBlock && !m_blockman.LookupBlockIndex(header.hashPrevBlock)) {
LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(),
- block.hashPrevBlock.ToString());
+ header.hashPrevBlock.ToString());
if (dbp && blocks_with_unknown_parent) {
- blocks_with_unknown_parent->emplace(block.hashPrevBlock, *dbp);
+ blocks_with_unknown_parent->emplace(header.hashPrevBlock, *dbp);
}
continue;
}
@@ -4377,20 +4567,26 @@ void Chainstate::LoadExternalBlockFile(
// process in case the block isn't known yet
const CBlockIndex* pindex = m_blockman.LookupBlockIndex(hash);
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
- BlockValidationState state;
- if (AcceptBlock(pblock, state, nullptr, true, dbp, nullptr, true)) {
- nLoaded++;
- }
- if (state.IsError()) {
- break;
- }
- } else if (hash != m_params.GetConsensus().hashGenesisBlock && pindex->nHeight % 1000 == 0) {
+ // This block can be processed immediately; rewind to its start, read and deserialize it.
+ blkdat.SetPos(nBlockPos);
+ std::shared_ptr<CBlock> pblock{std::make_shared<CBlock>()};
+ blkdat >> *pblock;
+ nRewind = blkdat.GetPos();
+
+ BlockValidationState state;
+ if (AcceptBlock(pblock, state, nullptr, true, dbp, nullptr, true)) {
+ nLoaded++;
+ }
+ if (state.IsError()) {
+ break;
+ }
+ } else if (hash != params.GetConsensus().hashGenesisBlock && pindex->nHeight % 1000 == 0) {
LogPrint(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), pindex->nHeight);
}
}
// Activate the genesis block so normal node progress can continue
- if (hash == m_params.GetConsensus().hashGenesisBlock) {
+ if (hash == params.GetConsensus().hashGenesisBlock) {
BlockValidationState state;
if (!ActivateBestChain(state, nullptr)) {
break;
@@ -4411,7 +4607,7 @@ void Chainstate::LoadExternalBlockFile(
while (range.first != range.second) {
std::multimap<uint256, FlatFilePos>::iterator it = range.first;
std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>();
- if (ReadBlockFromDisk(*pblockrecursive, it->second, m_params.GetConsensus())) {
+ if (ReadBlockFromDisk(*pblockrecursive, it->second, params.GetConsensus())) {
LogPrint(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(),
head.ToString());
LOCK(cs_main);
@@ -4427,7 +4623,18 @@ void Chainstate::LoadExternalBlockFile(
}
}
} catch (const std::exception& e) {
- LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, e.what());
+ // historical bugs added extra data to the block files that does not deserialize cleanly.
+ // commonly this data is between readable blocks, but it does not really matter. such data is not fatal to the import process.
+ // the code that reads the block files deals with invalid data by simply ignoring it.
+ // it continues to search for the next {4 byte magic message start bytes + 4 byte length + block} that does deserialize cleanly
+ // and passes all of the other block validation checks dealing with POW and the merkle root, etc...
+ // we merely note with this informational log message when unexpected data is encountered.
+ // we could also be experiencing a storage system read error, or a read of a previous bad write. these are possible, but
+ // less likely scenarios. we don't have enough information to tell a difference here.
+ // the reindex process is not the place to attempt to clean and/or compact the block files. if so desired, a studious node operator
+ // may use knowledge of the fact that the block files are not entirely pristine in order to prepare a set of pristine, and
+ // perhaps ordered, block files for later reindexing.
+ LogPrint(BCLog::REINDEX, "%s: unexpected data at file offset 0x%x - %s. continuing\n", __func__, (nRewind - 1), e.what());
}
}
} catch (const std::runtime_error& e) {
@@ -4438,7 +4645,7 @@ void Chainstate::LoadExternalBlockFile(
void Chainstate::CheckBlockIndex()
{
- if (!fCheckBlockIndex) {
+ if (!m_chainman.ShouldCheckBlockIndex()) {
return;
}
@@ -4511,7 +4718,7 @@ void Chainstate::CheckBlockIndex()
// Begin: actual consistency checks.
if (pindex->pprev == nullptr) {
// Genesis block checks.
- assert(pindex->GetBlockHash() == m_params.GetConsensus().hashGenesisBlock); // Genesis block's hash must match.
+ assert(pindex->GetBlockHash() == m_chainman.GetConsensus().hashGenesisBlock); // Genesis block's hash must match.
assert(pindex == m_chain.Genesis()); // The current active chain's genesis block must be this block.
}
if (!pindex->HaveTxsDownloaded()) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
@@ -4733,39 +4940,22 @@ std::vector<Chainstate*> ChainstateManager::GetAll()
LOCK(::cs_main);
std::vector<Chainstate*> out;
- if (!IsSnapshotValidated() && m_ibd_chainstate) {
- out.push_back(m_ibd_chainstate.get());
- }
-
- if (m_snapshot_chainstate) {
- out.push_back(m_snapshot_chainstate.get());
+ for (Chainstate* cs : {m_ibd_chainstate.get(), m_snapshot_chainstate.get()}) {
+ if (this->IsUsable(cs)) out.push_back(cs);
}
return out;
}
-Chainstate& ChainstateManager::InitializeChainstate(
- CTxMemPool* mempool, const std::optional<uint256>& snapshot_blockhash)
+Chainstate& ChainstateManager::InitializeChainstate(CTxMemPool* mempool)
{
AssertLockHeld(::cs_main);
- bool is_snapshot = snapshot_blockhash.has_value();
- std::unique_ptr<Chainstate>& to_modify =
- is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate;
+ assert(!m_ibd_chainstate);
+ assert(!m_active_chainstate);
- if (to_modify) {
- throw std::logic_error("should not be overwriting a chainstate");
- }
- to_modify.reset(new Chainstate(mempool, m_blockman, *this, snapshot_blockhash));
-
- // Snapshot chainstates and initial IBD chaintates always become active.
- if (is_snapshot || (!is_snapshot && !m_active_chainstate)) {
- LogPrintf("Switching active chainstate to %s\n", to_modify->ToString());
- m_active_chainstate = to_modify.get();
- } else {
- throw std::logic_error("unexpected chainstate activation");
- }
-
- return *to_modify;
+ m_ibd_chainstate = std::make_unique<Chainstate>(mempool, m_blockman, *this);
+ m_active_chainstate = m_ibd_chainstate.get();
+ return *m_active_chainstate;
}
const AssumeutxoData* ExpectedAssumeutxo(
@@ -4780,6 +4970,46 @@ const AssumeutxoData* ExpectedAssumeutxo(
return nullptr;
}
+static bool DeleteCoinsDBFromDisk(const fs::path db_path, bool is_snapshot)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
+{
+ AssertLockHeld(::cs_main);
+
+ if (is_snapshot) {
+ fs::path base_blockhash_path = db_path / node::SNAPSHOT_BLOCKHASH_FILENAME;
+
+ if (fs::exists(base_blockhash_path)) {
+ bool removed = fs::remove(base_blockhash_path);
+ if (!removed) {
+ LogPrintf("[snapshot] failed to remove file %s\n",
+ fs::PathToString(base_blockhash_path));
+ }
+ } else {
+ LogPrintf("[snapshot] snapshot chainstate dir being removed lacks %s file\n",
+ fs::PathToString(node::SNAPSHOT_BLOCKHASH_FILENAME));
+ }
+ }
+
+ std::string path_str = fs::PathToString(db_path);
+ LogPrintf("Removing leveldb dir at %s\n", path_str);
+
+ // We have to destruct before this call leveldb::DB in order to release the db
+ // lock, otherwise `DestroyDB` will fail. See `leveldb::~DBImpl()`.
+ const bool destroyed = dbwrapper::DestroyDB(path_str, {}).ok();
+
+ if (!destroyed) {
+ LogPrintf("error: leveldb DestroyDB call failed on %s\n", path_str);
+ }
+
+ // Datadir should be removed from filesystem; otherwise initialization may detect
+ // it on subsequent statups and get confused.
+ //
+ // If the base_blockhash_path removal above fails in the case of snapshot
+ // chainstates, this will return false since leveldb won't remove a non-empty
+ // directory.
+ return destroyed && !fs::exists(db_path);
+}
+
bool ChainstateManager::ActivateSnapshot(
AutoFile& coins_file,
const SnapshotMetadata& metadata,
@@ -4837,11 +5067,34 @@ bool ChainstateManager::ActivateSnapshot(
static_cast<size_t>(current_coinstip_cache_size * SNAPSHOT_CACHE_PERC));
}
- const bool snapshot_ok = this->PopulateAndValidateSnapshot(
+ bool snapshot_ok = this->PopulateAndValidateSnapshot(
*snapshot_chainstate, coins_file, metadata);
+ // If not in-memory, persist the base blockhash for use during subsequent
+ // initialization.
+ if (!in_memory) {
+ LOCK(::cs_main);
+ if (!node::WriteSnapshotBaseBlockhash(*snapshot_chainstate)) {
+ snapshot_ok = false;
+ }
+ }
if (!snapshot_ok) {
- WITH_LOCK(::cs_main, this->MaybeRebalanceCaches());
+ LOCK(::cs_main);
+ this->MaybeRebalanceCaches();
+
+ // PopulateAndValidateSnapshot can return (in error) before the leveldb datadir
+ // has been created, so only attempt removal if we got that far.
+ if (auto snapshot_datadir = node::FindSnapshotChainstateDir()) {
+ // We have to destruct leveldb::DB in order to release the db lock, otherwise
+ // DestroyDB() (in DeleteCoinsDBFromDisk()) will fail. See `leveldb::~DBImpl()`.
+ // Destructing the chainstate (and so resetting the coinsviews object) does this.
+ snapshot_chainstate.reset();
+ bool removed = DeleteCoinsDBFromDisk(*snapshot_datadir, /*is_snapshot=*/true);
+ if (!removed) {
+ AbortNode(strprintf("Failed to remove snapshot chainstate dir (%s). "
+ "Manually remove it before restarting.\n", fs::PathToString(*snapshot_datadir)));
+ }
+ }
return false;
}
@@ -4874,6 +5127,19 @@ static void FlushSnapshotToDisk(CCoinsViewCache& coins_cache, bool snapshot_load
coins_cache.Flush();
}
+struct StopHashingException : public std::exception
+{
+ const char* what() const throw() override
+ {
+ return "ComputeUTXOStats interrupted by shutdown.";
+ }
+};
+
+static void SnapshotUTXOHashBreakpoint()
+{
+ if (ShutdownRequested()) throw StopHashingException();
+}
+
bool ChainstateManager::PopulateAndValidateSnapshot(
Chainstate& snapshot_chainstate,
AutoFile& coins_file,
@@ -4997,13 +5263,18 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
assert(coins_cache.GetBestBlock() == base_blockhash);
- auto breakpoint_fnc = [] { /* TODO insert breakpoint here? */ };
-
// As above, okay to immediately release cs_main here since no other context knows
// about the snapshot_chainstate.
CCoinsViewDB* snapshot_coinsdb = WITH_LOCK(::cs_main, return &snapshot_chainstate.CoinsDB());
- const std::optional<CCoinsStats> maybe_stats = ComputeUTXOStats(CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, breakpoint_fnc);
+ std::optional<CCoinsStats> maybe_stats;
+
+ try {
+ maybe_stats = ComputeUTXOStats(
+ CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, SnapshotUTXOHashBreakpoint);
+ } catch (StopHashingException const&) {
+ return false;
+ }
if (!maybe_stats.has_value()) {
LogPrintf("[snapshot] failed to generate coins stats\n");
return false;
@@ -5071,6 +5342,149 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
return true;
}
+// Currently, this function holds cs_main for its duration, which could be for
+// multiple minutes due to the ComputeUTXOStats call. This hold is necessary
+// because we need to avoid advancing the background validation chainstate
+// farther than the snapshot base block - and this function is also invoked
+// from within ConnectTip, i.e. from within ActivateBestChain, so cs_main is
+// held anyway.
+//
+// Eventually (TODO), we could somehow separate this function's runtime from
+// maintenance of the active chain, but that will either require
+//
+// (i) setting `m_disabled` immediately and ensuring all chainstate accesses go
+// through IsUsable() checks, or
+//
+// (ii) giving each chainstate its own lock instead of using cs_main for everything.
+SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
+ std::function<void(bilingual_str)> shutdown_fnc)
+{
+ AssertLockHeld(cs_main);
+ if (m_ibd_chainstate.get() == &this->ActiveChainstate() ||
+ !this->IsUsable(m_snapshot_chainstate.get()) ||
+ !this->IsUsable(m_ibd_chainstate.get()) ||
+ !m_ibd_chainstate->m_chain.Tip()) {
+ // Nothing to do - this function only applies to the background
+ // validation chainstate.
+ return SnapshotCompletionResult::SKIPPED;
+ }
+ const int snapshot_tip_height = this->ActiveHeight();
+ const int snapshot_base_height = *Assert(this->GetSnapshotBaseHeight());
+ const CBlockIndex& index_new = *Assert(m_ibd_chainstate->m_chain.Tip());
+
+ if (index_new.nHeight < snapshot_base_height) {
+ // Background IBD not complete yet.
+ return SnapshotCompletionResult::SKIPPED;
+ }
+
+ assert(SnapshotBlockhash());
+ uint256 snapshot_blockhash = *Assert(SnapshotBlockhash());
+
+ auto handle_invalid_snapshot = [&]() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
+ bilingual_str user_error = strprintf(_(
+ "%s failed to validate the -assumeutxo snapshot state. "
+ "This indicates a hardware problem, or a bug in the software, or a "
+ "bad software modification that allowed an invalid snapshot to be "
+ "loaded. As a result of this, the node will shut down and stop using any "
+ "state that was built on the snapshot, resetting the chain height "
+ "from %d to %d. On the next "
+ "restart, the node will resume syncing from %d "
+ "without using any snapshot data. "
+ "Please report this incident to %s, including how you obtained the snapshot. "
+ "The invalid snapshot chainstate has been left on disk in case it is "
+ "helpful in diagnosing the issue that caused this error."),
+ PACKAGE_NAME, snapshot_tip_height, snapshot_base_height, snapshot_base_height, PACKAGE_BUGREPORT
+ );
+
+ LogPrintf("[snapshot] !!! %s\n", user_error.original);
+ LogPrintf("[snapshot] deleting snapshot, reverting to validated chain, and stopping node\n");
+
+ m_active_chainstate = m_ibd_chainstate.get();
+ m_snapshot_chainstate->m_disabled = true;
+ assert(!this->IsUsable(m_snapshot_chainstate.get()));
+ assert(this->IsUsable(m_ibd_chainstate.get()));
+
+ m_snapshot_chainstate->InvalidateCoinsDBOnDisk();
+
+ shutdown_fnc(user_error);
+ };
+
+ if (index_new.GetBlockHash() != snapshot_blockhash) {
+ LogPrintf("[snapshot] supposed base block %s does not match the " /* Continued */
+ "snapshot base block %s (height %d). Snapshot is not valid.",
+ index_new.ToString(), snapshot_blockhash.ToString(), snapshot_base_height);
+ handle_invalid_snapshot();
+ return SnapshotCompletionResult::BASE_BLOCKHASH_MISMATCH;
+ }
+
+ assert(index_new.nHeight == snapshot_base_height);
+
+ int curr_height = m_ibd_chainstate->m_chain.Height();
+
+ assert(snapshot_base_height == curr_height);
+ assert(snapshot_base_height == index_new.nHeight);
+ assert(this->IsUsable(m_snapshot_chainstate.get()));
+ assert(this->GetAll().size() == 2);
+
+ CCoinsViewDB& ibd_coins_db = m_ibd_chainstate->CoinsDB();
+ m_ibd_chainstate->ForceFlushStateToDisk();
+
+ auto maybe_au_data = ExpectedAssumeutxo(curr_height, m_options.chainparams);
+ if (!maybe_au_data) {
+ LogPrintf("[snapshot] assumeutxo data not found for height " /* Continued */
+ "(%d) - refusing to validate snapshot\n", curr_height);
+ handle_invalid_snapshot();
+ return SnapshotCompletionResult::MISSING_CHAINPARAMS;
+ }
+
+ const AssumeutxoData& au_data = *maybe_au_data;
+ std::optional<CCoinsStats> maybe_ibd_stats;
+ LogPrintf("[snapshot] computing UTXO stats for background chainstate to validate " /* Continued */
+ "snapshot - this could take a few minutes\n");
+ try {
+ maybe_ibd_stats = ComputeUTXOStats(
+ CoinStatsHashType::HASH_SERIALIZED,
+ &ibd_coins_db,
+ m_blockman,
+ SnapshotUTXOHashBreakpoint);
+ } catch (StopHashingException const&) {
+ return SnapshotCompletionResult::STATS_FAILED;
+ }
+
+ // XXX note that this function is slow and will hold cs_main for potentially minutes.
+ if (!maybe_ibd_stats) {
+ LogPrintf("[snapshot] failed to generate stats for validation coins db\n");
+ // While this isn't a problem with the snapshot per se, this condition
+ // prevents us from validating the snapshot, so we should shut down and let the
+ // user handle the issue manually.
+ handle_invalid_snapshot();
+ return SnapshotCompletionResult::STATS_FAILED;
+ }
+ const auto& ibd_stats = *maybe_ibd_stats;
+
+ // Compare the background validation chainstate's UTXO set hash against the hard-coded
+ // assumeutxo hash we expect.
+ //
+ // TODO: For belt-and-suspenders, we could cache the UTXO set
+ // hash for the snapshot when it's loaded in its chainstate's leveldb. We could then
+ // reference that here for an additional check.
+ if (AssumeutxoHash{ibd_stats.hashSerialized} != au_data.hash_serialized) {
+ LogPrintf("[snapshot] hash mismatch: actual=%s, expected=%s\n",
+ ibd_stats.hashSerialized.ToString(),
+ au_data.hash_serialized.ToString());
+ handle_invalid_snapshot();
+ return SnapshotCompletionResult::HASH_MISMATCH;
+ }
+
+ LogPrintf("[snapshot] snapshot beginning at %s has been fully validated\n",
+ snapshot_blockhash.ToString());
+
+ m_ibd_chainstate->m_disabled = true;
+ this->MaybeRebalanceCaches();
+
+ return SnapshotCompletionResult::SUCCESS;
+}
+
Chainstate& ChainstateManager::ActiveChainstate() const
{
LOCK(::cs_main);
@@ -5087,17 +5501,22 @@ bool ChainstateManager::IsSnapshotActive() const
void ChainstateManager::MaybeRebalanceCaches()
{
AssertLockHeld(::cs_main);
- if (m_ibd_chainstate && !m_snapshot_chainstate) {
+ bool ibd_usable = this->IsUsable(m_ibd_chainstate.get());
+ bool snapshot_usable = this->IsUsable(m_snapshot_chainstate.get());
+ assert(ibd_usable || snapshot_usable);
+
+ if (ibd_usable && !snapshot_usable) {
LogPrintf("[snapshot] allocating all cache to the IBD chainstate\n");
// Allocate everything to the IBD chainstate.
m_ibd_chainstate->ResizeCoinsCaches(m_total_coinstip_cache, m_total_coinsdb_cache);
}
- else if (m_snapshot_chainstate && !m_ibd_chainstate) {
+ else if (snapshot_usable && !ibd_usable) {
+ // If background validation has completed and snapshot is our active chain...
LogPrintf("[snapshot] allocating all cache to the snapshot chainstate\n");
// Allocate everything to the snapshot chainstate.
m_snapshot_chainstate->ResizeCoinsCaches(m_total_coinstip_cache, m_total_coinsdb_cache);
}
- else if (m_ibd_chainstate && m_snapshot_chainstate) {
+ else if (ibd_usable && snapshot_usable) {
// If both chainstates exist, determine who needs more cache based on IBD status.
//
// Note: shrink caches first so that we don't inadvertently overwhelm available memory.
@@ -5115,6 +5534,31 @@ void ChainstateManager::MaybeRebalanceCaches()
}
}
+void ChainstateManager::ResetChainstates()
+{
+ m_ibd_chainstate.reset();
+ m_snapshot_chainstate.reset();
+ m_active_chainstate = nullptr;
+}
+
+/**
+ * Apply default chain params to nullopt members.
+ * This helps to avoid coding errors around the accidental use of the compare
+ * operators that accept nullopt, thus ignoring the intended default value.
+ */
+static ChainstateManager::Options&& Flatten(ChainstateManager::Options&& opts)
+{
+ if (!opts.check_block_index.has_value()) opts.check_block_index = opts.chainparams.DefaultConsistencyChecks();
+ if (!opts.minimum_chain_work.has_value()) opts.minimum_chain_work = UintToArith256(opts.chainparams.GetConsensus().nMinimumChainWork);
+ if (!opts.assumed_valid_block.has_value()) opts.assumed_valid_block = opts.chainparams.GetConsensus().defaultAssumeValid;
+ Assert(opts.adjusted_time_callback);
+ return std::move(opts);
+}
+
+ChainstateManager::ChainstateManager(Options options, node::BlockManager::Options blockman_options)
+ : m_options{Flatten(std::move(options))},
+ m_blockman{std::move(blockman_options)} {}
+
ChainstateManager::~ChainstateManager()
{
LOCK(::cs_main);
@@ -5126,3 +5570,181 @@ ChainstateManager::~ChainstateManager()
i.clear();
}
}
+
+bool ChainstateManager::DetectSnapshotChainstate(CTxMemPool* mempool)
+{
+ assert(!m_snapshot_chainstate);
+ std::optional<fs::path> path = node::FindSnapshotChainstateDir();
+ if (!path) {
+ return false;
+ }
+ std::optional<uint256> base_blockhash = node::ReadSnapshotBaseBlockhash(*path);
+ if (!base_blockhash) {
+ return false;
+ }
+ LogPrintf("[snapshot] detected active snapshot chainstate (%s) - loading\n",
+ fs::PathToString(*path));
+
+ this->ActivateExistingSnapshot(mempool, *base_blockhash);
+ return true;
+}
+
+Chainstate& ChainstateManager::ActivateExistingSnapshot(CTxMemPool* mempool, uint256 base_blockhash)
+{
+ assert(!m_snapshot_chainstate);
+ m_snapshot_chainstate =
+ std::make_unique<Chainstate>(mempool, m_blockman, *this, base_blockhash);
+ LogPrintf("[snapshot] switching active chainstate to %s\n", m_snapshot_chainstate->ToString());
+ m_active_chainstate = m_snapshot_chainstate.get();
+ return *m_snapshot_chainstate;
+}
+
+bool IsBIP30Repeat(const CBlockIndex& block_index)
+{
+ return (block_index.nHeight==91842 && block_index.GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
+ (block_index.nHeight==91880 && block_index.GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"));
+}
+
+bool IsBIP30Unspendable(const CBlockIndex& block_index)
+{
+ return (block_index.nHeight==91722 && block_index.GetBlockHash() == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) ||
+ (block_index.nHeight==91812 && block_index.GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"));
+}
+
+void Chainstate::InvalidateCoinsDBOnDisk()
+{
+ AssertLockHeld(::cs_main);
+ // Should never be called on a non-snapshot chainstate.
+ assert(m_from_snapshot_blockhash);
+ auto storage_path_maybe = this->CoinsDB().StoragePath();
+ // Should never be called with a non-existent storage path.
+ assert(storage_path_maybe);
+ fs::path snapshot_datadir = *storage_path_maybe;
+
+ // Coins views no longer usable.
+ m_coins_views.reset();
+
+ auto invalid_path = snapshot_datadir + "_INVALID";
+ std::string dbpath = fs::PathToString(snapshot_datadir);
+ std::string target = fs::PathToString(invalid_path);
+ LogPrintf("[snapshot] renaming snapshot datadir %s to %s\n", dbpath, target);
+
+ // The invalid snapshot datadir is simply moved and not deleted because we may
+ // want to do forensics later during issue investigation. The user is instructed
+ // accordingly in MaybeCompleteSnapshotValidation().
+ try {
+ fs::rename(snapshot_datadir, invalid_path);
+ } catch (const fs::filesystem_error& e) {
+ auto src_str = fs::PathToString(snapshot_datadir);
+ auto dest_str = fs::PathToString(invalid_path);
+
+ LogPrintf("%s: error renaming file '%s' -> '%s': %s\n",
+ __func__, src_str, dest_str, e.what());
+ AbortNode(strprintf(
+ "Rename of '%s' -> '%s' failed. "
+ "You should resolve this by manually moving or deleting the invalid "
+ "snapshot directory %s, otherwise you will encounter the same error again "
+ "on the next startup.",
+ src_str, dest_str, src_str));
+ }
+}
+
+const CBlockIndex* ChainstateManager::GetSnapshotBaseBlock() const
+{
+ const auto blockhash_op = this->SnapshotBlockhash();
+ if (!blockhash_op) return nullptr;
+ return Assert(m_blockman.LookupBlockIndex(*blockhash_op));
+}
+
+std::optional<int> ChainstateManager::GetSnapshotBaseHeight() const
+{
+ const CBlockIndex* base = this->GetSnapshotBaseBlock();
+ return base ? std::make_optional(base->nHeight) : std::nullopt;
+}
+
+bool ChainstateManager::ValidatedSnapshotCleanup()
+{
+ AssertLockHeld(::cs_main);
+ auto get_storage_path = [](auto& chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) -> std::optional<fs::path> {
+ if (!(chainstate && chainstate->HasCoinsViews())) {
+ return {};
+ }
+ return chainstate->CoinsDB().StoragePath();
+ };
+ std::optional<fs::path> ibd_chainstate_path_maybe = get_storage_path(m_ibd_chainstate);
+ std::optional<fs::path> snapshot_chainstate_path_maybe = get_storage_path(m_snapshot_chainstate);
+
+ if (!this->IsSnapshotValidated()) {
+ // No need to clean up.
+ return false;
+ }
+ // If either path doesn't exist, that means at least one of the chainstates
+ // is in-memory, in which case we can't do on-disk cleanup. You'd better be
+ // in a unittest!
+ if (!ibd_chainstate_path_maybe || !snapshot_chainstate_path_maybe) {
+ LogPrintf("[snapshot] snapshot chainstate cleanup cannot happen with " /* Continued */
+ "in-memory chainstates. You are testing, right?\n");
+ return false;
+ }
+
+ const auto& snapshot_chainstate_path = *snapshot_chainstate_path_maybe;
+ const auto& ibd_chainstate_path = *ibd_chainstate_path_maybe;
+
+ // Since we're going to be moving around the underlying leveldb filesystem content
+ // for each chainstate, make sure that the chainstates (and their constituent
+ // CoinsViews members) have been destructed first.
+ //
+ // The caller of this method will be responsible for reinitializing chainstates
+ // if they want to continue operation.
+ this->ResetChainstates();
+
+ // No chainstates should be considered usable.
+ assert(this->GetAll().size() == 0);
+
+ LogPrintf("[snapshot] deleting background chainstate directory (now unnecessary) (%s)\n",
+ fs::PathToString(ibd_chainstate_path));
+
+ fs::path tmp_old{ibd_chainstate_path + "_todelete"};
+
+ auto rename_failed_abort = [](
+ fs::path p_old,
+ fs::path p_new,
+ const fs::filesystem_error& err) {
+ LogPrintf("%s: error renaming file (%s): %s\n",
+ __func__, fs::PathToString(p_old), err.what());
+ AbortNode(strprintf(
+ "Rename of '%s' -> '%s' failed. "
+ "Cannot clean up the background chainstate leveldb directory.",
+ fs::PathToString(p_old), fs::PathToString(p_new)));
+ };
+
+ try {
+ fs::rename(ibd_chainstate_path, tmp_old);
+ } catch (const fs::filesystem_error& e) {
+ rename_failed_abort(ibd_chainstate_path, tmp_old, e);
+ throw;
+ }
+
+ LogPrintf("[snapshot] moving snapshot chainstate (%s) to " /* Continued */
+ "default chainstate directory (%s)\n",
+ fs::PathToString(snapshot_chainstate_path), fs::PathToString(ibd_chainstate_path));
+
+ try {
+ fs::rename(snapshot_chainstate_path, ibd_chainstate_path);
+ } catch (const fs::filesystem_error& e) {
+ rename_failed_abort(snapshot_chainstate_path, ibd_chainstate_path, e);
+ throw;
+ }
+
+ if (!DeleteCoinsDBFromDisk(tmp_old, /*is_snapshot=*/false)) {
+ // No need to AbortNode because once the unneeded bg chainstate data is
+ // moved, it will not interfere with subsequent initialization.
+ LogPrintf("Deletion of %s failed. Please remove it manually, as the " /* Continued */
+ "directory is now unnecessary.\n",
+ fs::PathToString(tmp_old));
+ } else {
+ LogPrintf("[snapshot] deleted background chainstate directory (%s)\n",
+ fs::PathToString(ibd_chainstate_path));
+ }
+ return true;
+}
diff --git a/src/validation.h b/src/validation.h
index c882eac408..53e9a7ee50 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,16 +13,18 @@
#include <arith_uint256.h>
#include <attributes.h>
#include <chain.h>
-#include <chainparams.h>
-#include <kernel/chainstatemanager_opts.h>
#include <consensus/amount.h>
#include <deploymentstatus.h>
#include <fs.h>
+#include <kernel/chainparams.h>
+#include <kernel/chainstatemanager_opts.h>
+#include <kernel/cs_main.h> // IWYU pragma: export
#include <node/blockstorage.h>
#include <policy/feerate.h>
#include <policy/packages.h>
#include <policy/policy.h>
#include <script/script_error.h>
+#include <shutdown.h>
#include <sync.h>
#include <txdb.h>
#include <txmempool.h> // For CTxMemPool::cs
@@ -63,8 +65,6 @@ struct Params;
static const int MAX_SCRIPTCHECK_THREADS = 15;
/** -par default (number of script-checking threads, 0 = auto) */
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
-static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
-static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
/** Default for -stopatheight */
static const int DEFAULT_STOPATHEIGHT = 0;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pruned. */
@@ -88,25 +88,10 @@ enum class SynchronizationState {
POST_INIT
};
-extern RecursiveMutex cs_main;
extern GlobalMutex g_best_block_mutex;
extern std::condition_variable g_best_block_cv;
/** Used to notify getblocktemplate RPC of new tips. */
extern uint256 g_best_block;
-/** Whether there are dedicated script-checking threads running.
- * False indicates all script checking is done on the main threadMessageHandler thread.
- */
-extern bool g_parallel_script_checks;
-extern bool fCheckBlockIndex;
-extern bool fCheckpointsEnabled;
-/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
-extern int64_t nMaxTipAge;
-
-/** Block hash whose ancestors we will assume to have valid scripts without checking them. */
-extern uint256 hashAssumeValid;
-
-/** Minimum work we will assume exists on some valid chain. */
-extern arith_uint256 nMinimumChainWork;
/** Documentation for argument 'checklevel'. */
extern const std::vector<std::string> CHECKLEVEL_DOC;
@@ -150,6 +135,19 @@ struct MempoolAcceptResult {
const std::optional<int64_t> m_vsize;
/** Raw base fees in satoshis. */
const std::optional<CAmount> m_base_fees;
+ /** The feerate at which this transaction was considered. This includes any fee delta added
+ * using prioritisetransaction (i.e. modified fees). If this transaction was submitted as a
+ * package, this is the package feerate, which may also include its descendants and/or
+ * ancestors (see m_wtxids_fee_calculations below).
+ * Only present when m_result_type = ResultType::VALID.
+ */
+ const std::optional<CFeeRate> m_effective_feerate;
+ /** Contains the wtxids of the transactions used for fee-related checks. Includes this
+ * transaction's wtxid and may include others if this transaction was validated as part of a
+ * package. This is not necessarily equivalent to the list of transactions passed to
+ * ProcessNewPackage().
+ * Only present when m_result_type = ResultType::VALID. */
+ const std::optional<std::vector<uint256>> m_wtxids_fee_calculations;
// The following field is only present when m_result_type = ResultType::DIFFERENT_WITNESS
/** The wtxid of the transaction in the mempool which has the same txid but different witness. */
@@ -159,8 +157,13 @@ struct MempoolAcceptResult {
return MempoolAcceptResult(state);
}
- static MempoolAcceptResult Success(std::list<CTransactionRef>&& replaced_txns, int64_t vsize, CAmount fees) {
- return MempoolAcceptResult(std::move(replaced_txns), vsize, fees);
+ static MempoolAcceptResult Success(std::list<CTransactionRef>&& replaced_txns,
+ int64_t vsize,
+ CAmount fees,
+ CFeeRate effective_feerate,
+ const std::vector<uint256>& wtxids_fee_calculations) {
+ return MempoolAcceptResult(std::move(replaced_txns), vsize, fees,
+ effective_feerate, wtxids_fee_calculations);
}
static MempoolAcceptResult MempoolTx(int64_t vsize, CAmount fees) {
@@ -180,9 +183,17 @@ private:
}
/** Constructor for success case */
- explicit MempoolAcceptResult(std::list<CTransactionRef>&& replaced_txns, int64_t vsize, CAmount fees)
+ explicit MempoolAcceptResult(std::list<CTransactionRef>&& replaced_txns,
+ int64_t vsize,
+ CAmount fees,
+ CFeeRate effective_feerate,
+ const std::vector<uint256>& wtxids_fee_calculations)
: m_result_type(ResultType::VALID),
- m_replaced_transactions(std::move(replaced_txns)), m_vsize{vsize}, m_base_fees(fees) {}
+ m_replaced_transactions(std::move(replaced_txns)),
+ m_vsize{vsize},
+ m_base_fees(fees),
+ m_effective_feerate(effective_feerate),
+ m_wtxids_fee_calculations(wtxids_fee_calculations) {}
/** Constructor for already-in-mempool case. It wouldn't replace any transactions. */
explicit MempoolAcceptResult(int64_t vsize, CAmount fees)
@@ -206,10 +217,6 @@ struct PackageMempoolAcceptResult
* was a package-wide error (see result in m_state), m_tx_results will be empty.
*/
std::map<const uint256, const MempoolAcceptResult> m_tx_results;
- /** Package feerate, defined as the aggregated modified fees divided by the total virtual size
- * of all transactions in the package. May be unavailable if some inputs were not available or
- * a transaction failure caused validation to terminate early. */
- std::optional<CFeeRate> m_package_feerate;
explicit PackageMempoolAcceptResult(PackageValidationState state,
std::map<const uint256, const MempoolAcceptResult>&& results)
@@ -217,7 +224,7 @@ struct PackageMempoolAcceptResult
explicit PackageMempoolAcceptResult(PackageValidationState state, CFeeRate feerate,
std::map<const uint256, const MempoolAcceptResult>&& results)
- : m_state{state}, m_tx_results(std::move(results)), m_package_feerate{feerate} {}
+ : m_state{state}, m_tx_results(std::move(results)) {}
/** Constructor to create a PackageMempoolAcceptResult from a single MempoolAcceptResult */
explicit PackageMempoolAcceptResult(const uint256& wtxid, const MempoolAcceptResult& result)
@@ -261,27 +268,39 @@ PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxM
bool CheckFinalTxAtTip(const CBlockIndex& active_chain_tip, const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
/**
- * Check if transaction will be BIP68 final in the next block to be created on top of tip.
- * @param[in] tip Chain tip to check tx sequence locks against. For example,
- * the tip of the current active chain.
+ * Calculate LockPoints required to check if transaction will be BIP68 final in the next block
+ * to be created on top of tip.
+ *
+ * @param[in] tip Chain tip for which tx sequence locks are calculated. For
+ * example, the tip of the current active chain.
* @param[in] coins_view Any CCoinsView that provides access to the relevant coins for
* checking sequence locks. For example, it can be a CCoinsViewCache
* that isn't connected to anything but contains all the relevant
* coins, or a CCoinsViewMemPool that is connected to the
- * mempool and chainstate UTXO set. In the latter case, the caller is
- * responsible for holding the appropriate locks to ensure that
+ * mempool and chainstate UTXO set. In the latter case, the caller
+ * is responsible for holding the appropriate locks to ensure that
* calls to GetCoin() return correct coins.
+ * @param[in] tx The transaction being evaluated.
+ *
+ * @returns The resulting height and time calculated and the hash of the block needed for
+ * calculation, or std::nullopt if there is an error.
+ */
+std::optional<LockPoints> CalculateLockPointsAtTip(
+ CBlockIndex* tip,
+ const CCoinsView& coins_view,
+ const CTransaction& tx);
+
+/**
+ * Check if transaction will be BIP68 final in the next block to be created on top of tip.
+ * @param[in] tip Chain tip to check tx sequence locks against. For example,
+ * the tip of the current active chain.
+ * @param[in] lock_points LockPoints containing the height and time at which this
+ * transaction is final.
* Simulates calling SequenceLocks() with data from the tip passed in.
- * Optionally stores in LockPoints the resulting height and time calculated and the hash
- * of the block needed for calculation or skips the calculation and uses the LockPoints
- * passed in for evaluation.
* The LockPoints should not be considered valid if CheckSequenceLocksAtTip returns false.
*/
bool CheckSequenceLocksAtTip(CBlockIndex* tip,
- const CCoinsView& coins_view,
- const CTransaction& tx,
- LockPoints* lp = nullptr,
- bool useExistingLockPoints = false);
+ const LockPoints& lock_points);
/**
* Closure representing one script verification
@@ -343,12 +362,20 @@ bool HasValidProofOfWork(const std::vector<CBlockHeader>& headers, const Consens
/** Return the sum of the work on a given set of headers */
arith_uint256 CalculateHeadersWork(const std::vector<CBlockHeader>& headers);
+enum class VerifyDBResult {
+ SUCCESS,
+ CORRUPTED_BLOCK_DB,
+ INTERRUPTED,
+ SKIPPED_L3_CHECKS,
+ SKIPPED_MISSING_BLOCKS,
+};
+
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
class CVerifyDB {
public:
CVerifyDB();
~CVerifyDB();
- bool VerifyDB(
+ [[nodiscard]] VerifyDBResult VerifyDB(
Chainstate& chainstate,
const Consensus::Params& consensus_params,
CCoinsView& coinsview,
@@ -402,7 +429,7 @@ public:
//! state to disk, which should not be done until the health of the database is verified.
//!
//! All arguments forwarded onto CCoinsViewDB.
- CoinsViews(fs::path ldb_name, size_t cache_size_bytes, bool in_memory, bool should_wipe);
+ CoinsViews(DBParams db_params, CoinsViewOptions options);
//! Initialize the CCoinsViewCache member.
void InitCache() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
@@ -467,15 +494,24 @@ protected:
//! Manages the UTXO set, which is a reflection of the contents of `m_chain`.
std::unique_ptr<CoinsViews> m_coins_views;
+ //! This toggle exists for use when doing background validation for UTXO
+ //! snapshots.
+ //!
+ //! In the expected case, it is set once the background validation chain reaches the
+ //! same height as the base of the snapshot and its UTXO set is found to hash to
+ //! the expected assumeutxo value. It signals that we should no longer connect
+ //! blocks to the background chainstate. When set on the background validation
+ //! chainstate, it signifies that we have fully validated the snapshot chainstate.
+ //!
+ //! In the unlikely case that the snapshot chainstate is found to be invalid, this
+ //! is set to true on the snapshot chainstate.
+ bool m_disabled GUARDED_BY(::cs_main) {false};
+
public:
//! Reference to a BlockManager instance which itself is shared across all
//! Chainstate instances.
node::BlockManager& m_blockman;
- /** Chain parameters for this chainstate */
- /* TODO: replace with m_chainman.GetParams() */
- const CChainParams& m_params;
-
//! The chainstate manager that owns this chainstate. The reference is
//! necessary so that this instance can check whether it is the active
//! chainstate within deeply nested method calls.
@@ -538,15 +574,15 @@ public:
CCoinsViewCache& CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
- assert(m_coins_views->m_cacheview);
- return *m_coins_views->m_cacheview.get();
+ Assert(m_coins_views);
+ return *Assert(m_coins_views->m_cacheview);
}
//! @returns A reference to the on-disk UTXO set database.
CCoinsViewDB& CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
- return m_coins_views->m_dbview;
+ return Assert(m_coins_views)->m_dbview;
}
//! @returns A pointer to the mempool.
@@ -560,12 +596,15 @@ public:
CCoinsViewErrorCatcher& CoinsErrorCatcher() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
- return m_coins_views->m_catcherview;
+ return Assert(m_coins_views)->m_catcherview;
}
//! Destructs all objects related to accessing the UTXO set.
void ResetCoinsViews() { m_coins_views.reset(); }
+ //! Does this chainstate have a UTXO set attached?
+ bool HasCoinsViews() const { return (bool)m_coins_views; }
+
//! The cache size of the on-disk coins view.
size_t m_coinsdb_cache_size_bytes{0};
@@ -645,6 +684,12 @@ public:
* May not be called with cs_main held. May not be called in a
* validationinterface callback.
*
+ * Note that if this is called while a snapshot chainstate is active, and if
+ * it is called on a background chainstate whose tip has reached the base block
+ * of the snapshot, its execution will take *MINUTES* while it hashes the
+ * background UTXO set to verify the assumeutxo value the snapshot was activated
+ * with. `cs_main` will be held during this time.
+ *
* @returns true unless a system error occurred
*/
bool ActivateBestChain(
@@ -702,7 +747,7 @@ public:
/**
* Make various assertions about the state of the block index.
*
- * By default this only executes fully when using the Regtest chain; see: fCheckBlockIndex.
+ * By default this only executes fully when using the Regtest chain; see: m_options.check_block_index.
*/
void CheckBlockIndex();
@@ -723,6 +768,12 @@ public:
std::string ToString() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ //! Indirection necessary to make lock annotations work with an optional mempool.
+ RecursiveMutex* MempoolMutex() const LOCK_RETURNED(m_mempool->cs)
+ {
+ return m_mempool ? &m_mempool->cs : nullptr;
+ }
+
private:
bool ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
bool ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
@@ -736,12 +787,6 @@ private:
void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- //! Indirection necessary to make lock annotations work with an optional mempool.
- RecursiveMutex* MempoolMutex() const LOCK_RETURNED(m_mempool->cs)
- {
- return m_mempool ? &m_mempool->cs : nullptr;
- }
-
/**
* Make mempool consistent after a reorg, by re-adding or recursively erasing
* disconnected block transactions from the mempool, and also removing any
@@ -763,9 +808,40 @@ private:
void UpdateTip(const CBlockIndex* pindexNew)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ SteadyClock::time_point m_last_write{};
+ SteadyClock::time_point m_last_flush{};
+
+ /**
+ * In case of an invalid snapshot, rename the coins leveldb directory so
+ * that it can be examined for issue diagnosis.
+ */
+ void InvalidateCoinsDBOnDisk() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
friend ChainstateManager;
};
+
+enum class SnapshotCompletionResult {
+ SUCCESS,
+ SKIPPED,
+
+ // Expected assumeutxo configuration data is not found for the height of the
+ // base block.
+ MISSING_CHAINPARAMS,
+
+ // Failed to generate UTXO statistics (to check UTXO set hash) for the background
+ // chainstate.
+ STATS_FAILED,
+
+ // The UTXO set hash of the background validation chainstate does not match
+ // the one expected by assumeutxo chainparams.
+ HASH_MISMATCH,
+
+ // The blockhash of the current tip of the background validation chainstate does
+ // not match the one expected by the snapshot chainstate.
+ BASE_BLOCKHASH_MISMATCH,
+};
+
/**
* Provides an interface for creating and interacting with one or two
* chainstates: an IBD chainstate generated by downloading blocks, and
@@ -835,10 +911,6 @@ private:
//! that call.
Chainstate* m_active_chainstate GUARDED_BY(::cs_main) {nullptr};
- //! If true, the assumed-valid chainstate has been fully validated
- //! by the background validation chainstate.
- bool m_snapshot_validated GUARDED_BY(::cs_main){false};
-
CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr};
//! Internal helper for ActivateSnapshot().
@@ -864,16 +936,32 @@ private:
/** Most recent headers presync progress update, for rate-limiting. */
std::chrono::time_point<std::chrono::steady_clock> m_last_presync_update GUARDED_BY(::cs_main) {};
+ //! Returns nullptr if no snapshot has been loaded.
+ const CBlockIndex* GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
+ //! Return the height of the base block of the snapshot in use, if one exists, else
+ //! nullopt.
+ std::optional<int> GetSnapshotBaseHeight() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
+ //! Return true if a chainstate is considered usable.
+ //!
+ //! This is false when a background validation chainstate has completed its
+ //! validation of an assumed-valid chainstate, or when a snapshot
+ //! chainstate has been found to be invalid.
+ bool IsUsable(const Chainstate* const cs) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
+ return cs && !cs->m_disabled;
+ }
+
public:
using Options = kernel::ChainstateManagerOpts;
- explicit ChainstateManager(Options options) : m_options{std::move(options)}
- {
- Assert(m_options.adjusted_time_callback);
- }
+ explicit ChainstateManager(Options options, node::BlockManager::Options blockman_options);
const CChainParams& GetParams() const { return m_options.chainparams; }
const Consensus::Params& GetConsensus() const { return m_options.chainparams.GetConsensus(); }
+ bool ShouldCheckBlockIndex() const { return *Assert(m_options.check_block_index); }
+ const arith_uint256& MinimumChainWork() const { return *Assert(m_options.minimum_chain_work); }
+ const uint256& AssumedValidBlock() const { return *Assert(m_options.assumed_valid_block); }
/**
* Alias for ::cs_main.
@@ -926,17 +1014,11 @@ public:
//! coins databases. This will be split somehow across chainstates.
int64_t m_total_coinsdb_cache{0};
- //! Instantiate a new chainstate and assign it based upon whether it is
- //! from a snapshot.
+ //! Instantiate a new chainstate.
//!
//! @param[in] mempool The mempool to pass to the chainstate
// constructor
- //! @param[in] snapshot_blockhash If given, signify that this chainstate
- //! is based on a snapshot.
- Chainstate& InitializeChainstate(
- CTxMemPool* mempool,
- const std::optional<uint256>& snapshot_blockhash = std::nullopt)
- LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ Chainstate& InitializeChainstate(CTxMemPool* mempool) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
//! Get all chainstates currently being used.
std::vector<Chainstate*> GetAll();
@@ -957,6 +1039,18 @@ public:
[[nodiscard]] bool ActivateSnapshot(
AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory);
+ //! Once the background validation chainstate has reached the height which
+ //! is the base of the UTXO snapshot in use, compare its coins to ensure
+ //! they match those expected by the snapshot.
+ //!
+ //! If the coins match (expected), then mark the validation chainstate for
+ //! deletion and continue using the snapshot chainstate as active.
+ //! Otherwise, revert to using the ibd chainstate and shutdown.
+ SnapshotCompletionResult MaybeCompleteSnapshotValidation(
+ std::function<void(bilingual_str)> shutdown_fnc =
+ [](bilingual_str msg) { AbortNode(msg.original, msg); })
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
//! The most-work chain.
Chainstate& ActiveChainstate() const;
CChain& ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChainstate().m_chain; }
@@ -981,7 +1075,10 @@ public:
std::optional<uint256> SnapshotBlockhash() const;
//! Is there a snapshot in use and has it been fully validated?
- bool IsSnapshotValidated() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { return m_snapshot_validated; }
+ bool IsSnapshotValidated() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
+ {
+ return m_snapshot_chainstate && m_ibd_chainstate && m_ibd_chainstate->m_disabled;
+ }
/**
* Process an incoming block. This only returns after the best known valid
@@ -1050,6 +1147,28 @@ public:
* information. */
void ReportHeadersPresync(const arith_uint256& work, int64_t height, int64_t timestamp);
+ //! When starting up, search the datadir for a chainstate based on a UTXO
+ //! snapshot that is in the process of being validated.
+ bool DetectSnapshotChainstate(CTxMemPool* mempool) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
+ void ResetChainstates() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
+ //! Switch the active chainstate to one based on a UTXO snapshot that was loaded
+ //! previously.
+ Chainstate& ActivateExistingSnapshot(CTxMemPool* mempool, uint256 base_blockhash)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
+ //! If we have validated a snapshot chain during this runtime, copy its
+ //! chainstate directory over to the main `chainstate` location, completing
+ //! validation of the snapshot.
+ //!
+ //! If the cleanup succeeds, the caller will need to ensure chainstates are
+ //! reinitialized, since ResetChainstates() will be called before leveldb
+ //! directories are moved or deleted.
+ //!
+ //! @sa node/chainstate:LoadChainstate()
+ bool ValidatedSnapshotCleanup() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
~ChainstateManager();
};
@@ -1081,4 +1200,10 @@ bool DeploymentEnabled(const ChainstateManager& chainman, DEP dep)
*/
const AssumeutxoData* ExpectedAssumeutxo(const int height, const CChainParams& params);
+/** Identifies blocks that overwrote an existing coinbase output in the UTXO set (see BIP30) */
+bool IsBIP30Repeat(const CBlockIndex& block_index);
+
+/** Identifies blocks which coinbase output was subsequently overwritten in the UTXO set (see BIP30) */
+bool IsBIP30Unspendable(const CBlockIndex& block_index);
+
#endif // BITCOIN_VALIDATION_H
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 613c5b65ef..d344c8bfbd 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,6 +17,8 @@
#include <unordered_map>
#include <utility>
+std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept;
+
/**
* MainSignalsImpl manages a list of shared_ptr<CValidationInterface> callbacks.
*
@@ -215,9 +217,10 @@ void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemP
auto event = [tx, reason, mempool_sequence, this] {
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason, mempool_sequence); });
};
- ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
+ ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s reason=%s", __func__,
tx->GetHash().ToString(),
- tx->GetWitnessHash().ToString());
+ tx->GetWitnessHash().ToString(),
+ RemovalReasonToString(reason));
}
void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
diff --git a/src/validationinterface.h b/src/validationinterface.h
index a929a3d56b..8c20cc8ffb 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -1,18 +1,18 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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_VALIDATIONINTERFACE_H
#define BITCOIN_VALIDATIONINTERFACE_H
+#include <kernel/cs_main.h>
#include <primitives/transaction.h> // CTransaction(Ref)
#include <sync.h>
#include <functional>
#include <memory>
-extern RecursiveMutex cs_main;
class BlockValidationState;
class CBlock;
class CBlockIndex;
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index dc85655028..fa9d1fe9c9 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -195,7 +195,7 @@ protected:
public:
explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
- uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }
+ uint32_t Mask(const Consensus::Params& params) const { return (uint32_t{1}) << params.vDeployments[id].bit; }
};
} // namespace
diff --git a/src/versionbits.h b/src/versionbits.h
index 9f7ee1b48e..09313d2054 100644
--- a/src/versionbits.h
+++ b/src/versionbits.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 3a9d277f65..653115aa81 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,6 +8,7 @@
#include <wallet/bdb.h>
#include <wallet/db.h>
+#include <util/check.h>
#include <util/strencodings.h>
#include <util/translation.h>
@@ -100,7 +101,7 @@ void BerkeleyEnvironment::Close()
if (ret != 0)
LogPrintf("BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
- DbEnv((uint32_t)0).remove(strPath.c_str(), 0);
+ DbEnv(uint32_t{0}).remove(strPath.c_str(), 0);
if (error_file) fclose(error_file);
@@ -220,17 +221,17 @@ BerkeleyEnvironment::BerkeleyEnvironment() : m_use_shared_memory(false)
fMockDb = true;
}
-BerkeleyBatch::SafeDbt::SafeDbt()
+SafeDbt::SafeDbt()
{
m_dbt.set_flags(DB_DBT_MALLOC);
}
-BerkeleyBatch::SafeDbt::SafeDbt(void* data, size_t size)
+SafeDbt::SafeDbt(void* data, size_t size)
: m_dbt(data, size)
{
}
-BerkeleyBatch::SafeDbt::~SafeDbt()
+SafeDbt::~SafeDbt()
{
if (m_dbt.get_data() != nullptr) {
// Clear memory, e.g. in case it was a private key
@@ -244,17 +245,17 @@ BerkeleyBatch::SafeDbt::~SafeDbt()
}
}
-const void* BerkeleyBatch::SafeDbt::get_data() const
+const void* SafeDbt::get_data() const
{
return m_dbt.get_data();
}
-uint32_t BerkeleyBatch::SafeDbt::get_size() const
+uint32_t SafeDbt::get_size() const
{
return m_dbt.get_size();
}
-BerkeleyBatch::SafeDbt::operator Dbt*()
+SafeDbt::operator Dbt*()
{
return &m_dbt;
}
@@ -307,7 +308,7 @@ BerkeleyDatabase::~BerkeleyDatabase()
}
}
-BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const bool read_only, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr), m_cursor(nullptr), m_database(database)
+BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const bool read_only, bool fFlushOnCloseIn) : m_database(database)
{
database.AddRef();
database.Open();
@@ -398,7 +399,6 @@ void BerkeleyBatch::Close()
activeTxn->abort();
activeTxn = nullptr;
pdb = nullptr;
- CloseCursor();
if (fFlushOnClose)
Flush();
@@ -476,15 +476,15 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip)
fSuccess = false;
}
- if (db.StartCursor()) {
+ std::unique_ptr<DatabaseCursor> cursor = db.GetNewCursor();
+ if (cursor) {
while (fSuccess) {
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- bool complete;
- bool ret1 = db.ReadAtCursor(ssKey, ssValue, complete);
- if (complete) {
+ DataStream ssKey{};
+ DataStream ssValue{};
+ DatabaseCursor::Status ret1 = cursor->Next(ssKey, ssValue);
+ if (ret1 == DatabaseCursor::Status::DONE) {
break;
- } else if (!ret1) {
+ } else if (ret1 == DatabaseCursor::Status::FAIL) {
fSuccess = false;
break;
}
@@ -502,7 +502,7 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip)
if (ret2 > 0)
fSuccess = false;
}
- db.CloseCursor();
+ cursor.reset();
}
if (fSuccess) {
db.Close();
@@ -656,48 +656,52 @@ void BerkeleyDatabase::ReloadDbEnv()
env->ReloadDbEnv();
}
-bool BerkeleyBatch::StartCursor()
+BerkeleyCursor::BerkeleyCursor(BerkeleyDatabase& database)
{
- assert(!m_cursor);
- if (!pdb)
- return false;
- int ret = pdb->cursor(nullptr, &m_cursor, 0);
- return ret == 0;
+ if (!database.m_db.get()) {
+ throw std::runtime_error(STR_INTERNAL_BUG("BerkeleyDatabase does not exist"));
+ }
+ int ret = database.m_db->cursor(nullptr, &m_cursor, 0);
+ if (ret != 0) {
+ throw std::runtime_error(STR_INTERNAL_BUG(strprintf("BDB Cursor could not be created. Returned %d", ret)));
+ }
}
-bool BerkeleyBatch::ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete)
+DatabaseCursor::Status BerkeleyCursor::Next(DataStream& ssKey, DataStream& ssValue)
{
- complete = false;
- if (m_cursor == nullptr) return false;
+ if (m_cursor == nullptr) return Status::FAIL;
// Read at cursor
SafeDbt datKey;
SafeDbt datValue;
int ret = m_cursor->get(datKey, datValue, DB_NEXT);
if (ret == DB_NOTFOUND) {
- complete = true;
+ return Status::DONE;
+ }
+ if (ret != 0 || datKey.get_data() == nullptr || datValue.get_data() == nullptr) {
+ return Status::FAIL;
}
- if (ret != 0)
- return false;
- else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr)
- return false;
// Convert to streams
- ssKey.SetType(SER_DISK);
ssKey.clear();
ssKey.write({AsBytePtr(datKey.get_data()), datKey.get_size()});
- ssValue.SetType(SER_DISK);
ssValue.clear();
ssValue.write({AsBytePtr(datValue.get_data()), datValue.get_size()});
- return true;
+ return Status::MORE;
}
-void BerkeleyBatch::CloseCursor()
+BerkeleyCursor::~BerkeleyCursor()
{
if (!m_cursor) return;
m_cursor->close();
m_cursor = nullptr;
}
+std::unique_ptr<DatabaseCursor> BerkeleyBatch::GetNewCursor()
+{
+ if (!pdb) return nullptr;
+ return std::make_unique<BerkeleyCursor>(m_database);
+}
+
bool BerkeleyBatch::TxnBegin()
{
if (!pdb || activeTxn)
@@ -749,7 +753,7 @@ std::string BerkeleyDatabaseVersion()
return DbEnv::version(nullptr, nullptr, nullptr);
}
-bool BerkeleyBatch::ReadKey(CDataStream&& key, CDataStream& value)
+bool BerkeleyBatch::ReadKey(DataStream&& key, DataStream& value)
{
if (!pdb)
return false;
@@ -765,7 +769,7 @@ bool BerkeleyBatch::ReadKey(CDataStream&& key, CDataStream& value)
return false;
}
-bool BerkeleyBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite)
+bool BerkeleyBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite)
{
if (!pdb)
return false;
@@ -780,7 +784,7 @@ bool BerkeleyBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwr
return (ret == 0);
}
-bool BerkeleyBatch::EraseKey(CDataStream&& key)
+bool BerkeleyBatch::EraseKey(DataStream&& key)
{
if (!pdb)
return false;
@@ -793,7 +797,7 @@ bool BerkeleyBatch::EraseKey(CDataStream&& key)
return (ret == 0 || ret == DB_NOTFOUND);
}
-bool BerkeleyBatch::HasKey(CDataStream&& key)
+bool BerkeleyBatch::HasKey(DataStream&& key)
{
if (!pdb)
return false;
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index ddab85521b..06c98972b0 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -165,40 +165,51 @@ public:
std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override;
};
-/** RAII class that provides access to a Berkeley database */
-class BerkeleyBatch : public DatabaseBatch
+/** RAII class that automatically cleanses its data on destruction */
+class SafeDbt final
{
- /** RAII class that automatically cleanses its data on destruction */
- class SafeDbt final
- {
- Dbt m_dbt;
+ Dbt m_dbt;
- public:
- // construct Dbt with internally-managed data
- SafeDbt();
- // construct Dbt with provided data
- SafeDbt(void* data, size_t size);
- ~SafeDbt();
+public:
+ // construct Dbt with internally-managed data
+ SafeDbt();
+ // construct Dbt with provided data
+ SafeDbt(void* data, size_t size);
+ ~SafeDbt();
+
+ // delegate to Dbt
+ const void* get_data() const;
+ uint32_t get_size() const;
+
+ // conversion operator to access the underlying Dbt
+ operator Dbt*();
+};
- // delegate to Dbt
- const void* get_data() const;
- uint32_t get_size() const;
+class BerkeleyCursor : public DatabaseCursor
+{
+private:
+ Dbc* m_cursor;
- // conversion operator to access the underlying Dbt
- operator Dbt*();
- };
+public:
+ explicit BerkeleyCursor(BerkeleyDatabase& database);
+ ~BerkeleyCursor() override;
+
+ Status Next(DataStream& key, DataStream& value) override;
+};
+/** RAII class that provides access to a Berkeley database */
+class BerkeleyBatch : public DatabaseBatch
+{
private:
- bool ReadKey(CDataStream&& key, CDataStream& value) override;
- bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite = true) override;
- bool EraseKey(CDataStream&& key) override;
- bool HasKey(CDataStream&& key) override;
+ bool ReadKey(DataStream&& key, DataStream& value) override;
+ bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override;
+ bool EraseKey(DataStream&& key) override;
+ bool HasKey(DataStream&& key) override;
protected:
- Db* pdb;
+ Db* pdb{nullptr};
std::string strFile;
- DbTxn* activeTxn;
- Dbc* m_cursor;
+ DbTxn* activeTxn{nullptr};
bool fReadOnly;
bool fFlushOnClose;
BerkeleyEnvironment *env;
@@ -214,9 +225,7 @@ public:
void Flush() override;
void Close() override;
- bool StartCursor() override;
- bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) override;
- void CloseCursor() override;
+ std::unique_ptr<DatabaseCursor> GetNewCursor() override;
bool TxnBegin() override;
bool TxnCommit() override;
bool TxnAbort() override;
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index d08d3664c4..cb6f0a1635 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -37,7 +37,7 @@ public:
bool m_include_unsafe_inputs = false;
//! If true, the selection process can add extra unselected inputs from the wallet
//! while requires all selected inputs be used
- bool m_allow_other_inputs = false;
+ bool m_allow_other_inputs = true;
//! Includes watch only addresses which are solvable
bool fAllowWatchOnly = false;
//! Override automatic min/max checks on fee, m_feerate must be set if true
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index b568e90998..9cf61dbe51 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 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 <wallet/coinselection.h>
#include <consensus/amount.h>
+#include <consensus/consensus.h>
#include <policy/feerate.h>
#include <util/check.h>
#include <util/system.h>
@@ -87,13 +88,15 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
std::vector<size_t> best_selection;
CAmount best_waste = MAX_MONEY;
+ bool is_feerate_high = utxo_pool.at(0).fee > utxo_pool.at(0).long_term_fee;
+
// Depth First search loop for choosing the UTXOs
for (size_t curr_try = 0, utxo_pool_index = 0; curr_try < TOTAL_TRIES; ++curr_try, ++utxo_pool_index) {
// Conditions for starting a backtrack
bool backtrack = false;
if (curr_value + curr_available_value < selection_target || // Cannot possibly reach target with the amount remaining in the curr_available_value.
curr_value > selection_target + cost_of_change || // Selected value is out of range, go back and try other branch
- (curr_waste > best_waste && (utxo_pool.at(0).fee - utxo_pool.at(0).long_term_fee) > 0)) { // Don't select things which we know will be more wasteful if the waste is increasing
+ (curr_waste > best_waste && is_feerate_high)) { // Don't select things which we know will be more wasteful if the waste is increasing
backtrack = true;
} else if (curr_value >= selection_target) { // Selected value is within range
curr_waste += (curr_value - selection_target); // This is the excess value which is added to the waste for the below comparison
@@ -330,12 +333,9 @@ std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups,
******************************************************************************/
-void OutputGroup::Insert(const COutput& output, size_t ancestors, size_t descendants, bool positive_only) {
- // Filter for positive only here before adding the coin
- if (positive_only && output.GetEffectiveValue() <= 0) return;
-
+void OutputGroup::Insert(const std::shared_ptr<COutput>& output, size_t ancestors, size_t descendants) {
m_outputs.push_back(output);
- COutput& coin = m_outputs.back();
+ auto& coin = *m_outputs.back();
fee += coin.GetFee();
@@ -354,6 +354,10 @@ void OutputGroup::Insert(const COutput& output, size_t ancestors, size_t descend
// descendants is the count as seen from the top ancestor, not the descendants as seen from the
// coin itself; thus, this value is counted as the max, not the sum
m_descendants = std::max(m_descendants, descendants);
+
+ if (output->input_bytes > 0) {
+ m_weight += output->input_bytes * WITNESS_SCALE_FACTOR;
+ }
}
bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const
@@ -368,7 +372,22 @@ CAmount OutputGroup::GetSelectionAmount() const
return m_subtract_fee_outputs ? m_value : effective_value;
}
-CAmount GetSelectionWaste(const std::set<COutput>& inputs, CAmount change_cost, CAmount target, bool use_effective_value)
+void OutputGroupTypeMap::Push(const OutputGroup& group, OutputType type, bool insert_positive, bool insert_mixed)
+{
+ if (group.m_outputs.empty()) return;
+
+ Groups& groups = groups_by_type[type];
+ if (insert_positive && group.GetSelectionAmount() > 0) {
+ groups.positive_group.emplace_back(group);
+ all_groups.positive_group.emplace_back(group);
+ }
+ if (insert_mixed) {
+ groups.mixed_group.emplace_back(group);
+ all_groups.mixed_group.emplace_back(group);
+ }
+}
+
+CAmount GetSelectionWaste(const std::set<std::shared_ptr<COutput>>& inputs, CAmount change_cost, CAmount target, bool use_effective_value)
{
// This function should not be called with empty inputs as that would mean the selection failed
assert(!inputs.empty());
@@ -376,7 +395,8 @@ CAmount GetSelectionWaste(const std::set<COutput>& inputs, CAmount change_cost,
// Always consider the cost of spending an input now vs in the future.
CAmount waste = 0;
CAmount selected_effective_value = 0;
- for (const COutput& coin : inputs) {
+ for (const auto& coin_ptr : inputs) {
+ const COutput& coin = *coin_ptr;
waste += coin.GetFee() - coin.long_term_fee;
selected_effective_value += use_effective_value ? coin.GetEffectiveValue() : coin.txout.nValue;
}
@@ -424,44 +444,63 @@ CAmount SelectionResult::GetWaste() const
CAmount SelectionResult::GetSelectedValue() const
{
- return std::accumulate(m_selected_inputs.cbegin(), m_selected_inputs.cend(), CAmount{0}, [](CAmount sum, const auto& coin) { return sum + coin.txout.nValue; });
+ return std::accumulate(m_selected_inputs.cbegin(), m_selected_inputs.cend(), CAmount{0}, [](CAmount sum, const auto& coin) { return sum + coin->txout.nValue; });
}
CAmount SelectionResult::GetSelectedEffectiveValue() const
{
- return std::accumulate(m_selected_inputs.cbegin(), m_selected_inputs.cend(), CAmount{0}, [](CAmount sum, const auto& coin) { return sum + coin.GetEffectiveValue(); });
+ return std::accumulate(m_selected_inputs.cbegin(), m_selected_inputs.cend(), CAmount{0}, [](CAmount sum, const auto& coin) { return sum + coin->GetEffectiveValue(); });
}
void SelectionResult::Clear()
{
m_selected_inputs.clear();
m_waste.reset();
+ m_weight = 0;
}
void SelectionResult::AddInput(const OutputGroup& group)
{
- util::insert(m_selected_inputs, group.m_outputs);
+ // As it can fail, combine inputs first
+ InsertInputs(group.m_outputs);
m_use_effective = !group.m_subtract_fee_outputs;
+
+ m_weight += group.m_weight;
+}
+
+void SelectionResult::AddInputs(const std::set<std::shared_ptr<COutput>>& inputs, bool subtract_fee_outputs)
+{
+ // As it can fail, combine inputs first
+ InsertInputs(inputs);
+ m_use_effective = !subtract_fee_outputs;
+
+ m_weight += std::accumulate(inputs.cbegin(), inputs.cend(), 0, [](int sum, const auto& coin) {
+ return sum + std::max(coin->input_bytes, 0) * WITNESS_SCALE_FACTOR;
+ });
}
void SelectionResult::Merge(const SelectionResult& other)
{
+ // As it can fail, combine inputs first
+ InsertInputs(other.m_selected_inputs);
+
m_target += other.m_target;
m_use_effective |= other.m_use_effective;
if (m_algo == SelectionAlgorithm::MANUAL) {
m_algo = other.m_algo;
}
- util::insert(m_selected_inputs, other.m_selected_inputs);
+
+ m_weight += other.m_weight;
}
-const std::set<COutput>& SelectionResult::GetInputSet() const
+const std::set<std::shared_ptr<COutput>>& SelectionResult::GetInputSet() const
{
return m_selected_inputs;
}
-std::vector<COutput> SelectionResult::GetShuffledInputVector() const
+std::vector<std::shared_ptr<COutput>> SelectionResult::GetShuffledInputVector() const
{
- std::vector<COutput> coins(m_selected_inputs.begin(), m_selected_inputs.end());
+ std::vector<std::shared_ptr<COutput>> coins(m_selected_inputs.begin(), m_selected_inputs.end());
Shuffle(coins.begin(), coins.end(), FastRandomContext());
return coins;
}
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index 761c2be0b3..5a7b748be1 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,9 +6,13 @@
#define BITCOIN_WALLET_COINSELECTION_H
#include <consensus/amount.h>
+#include <consensus/consensus.h>
+#include <outputtype.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <random.h>
+#include <util/system.h>
+#include <util/check.h>
#include <optional>
@@ -110,6 +114,8 @@ public:
assert(effective_value.has_value());
return effective_value.value();
}
+
+ bool HasEffectiveValue() const { return effective_value.has_value(); }
};
/** Parameters for one iteration of Coin Selection. */
@@ -147,6 +153,11 @@ struct CoinSelectionParams {
* associated with the same address. This helps reduce privacy leaks resulting from address
* reuse. Dust outputs are not eligible to be added to output groups and thus not considered. */
bool m_avoid_partial_spends = false;
+ /**
+ * When true, allow unsafe coins to be selected during Coin Selection. This may spend unconfirmed outputs:
+ * 1) Received from other wallets, 2) replacing other txs, 3) that have been replaced.
+ */
+ bool m_include_unsafe_inputs = false;
CoinSelectionParams(FastRandomContext& rng_fast, size_t change_output_size, size_t change_spend_size,
CAmount min_change_target, CFeeRate effective_feerate,
@@ -183,16 +194,22 @@ struct CoinEligibilityFilter
/** When avoid_reuse=true and there are full groups (OUTPUT_GROUP_MAX_ENTRIES), whether or not to use any partial groups.*/
const bool m_include_partial_groups{false};
+ CoinEligibilityFilter() = delete;
CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors) : conf_mine(conf_mine), conf_theirs(conf_theirs), max_ancestors(max_ancestors), max_descendants(max_ancestors) {}
CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors, uint64_t max_descendants) : conf_mine(conf_mine), conf_theirs(conf_theirs), max_ancestors(max_ancestors), max_descendants(max_descendants) {}
CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors, uint64_t max_descendants, bool include_partial) : conf_mine(conf_mine), conf_theirs(conf_theirs), max_ancestors(max_ancestors), max_descendants(max_descendants), m_include_partial_groups(include_partial) {}
+
+ bool operator<(const CoinEligibilityFilter& other) const {
+ return std::tie(conf_mine, conf_theirs, max_ancestors, max_descendants, m_include_partial_groups)
+ < std::tie(other.conf_mine, other.conf_theirs, other.max_ancestors, other.max_descendants, other.m_include_partial_groups);
+ }
};
/** A group of UTXOs paid to the same output script. */
struct OutputGroup
{
/** The list of UTXOs contained in this output group. */
- std::vector<COutput> m_outputs;
+ std::vector<std::shared_ptr<COutput>> m_outputs;
/** Whether the UTXOs were sent by the wallet to itself. This is relevant because we may want at
* least a certain number of confirmations on UTXOs received from outside wallets while trusting
* our own UTXOs more. */
@@ -210,8 +227,6 @@ struct OutputGroup
CAmount effective_value{0};
/** The fee to spend these UTXOs at the effective feerate. */
CAmount fee{0};
- /** The target feerate of the transaction we're trying to build. */
- CFeeRate m_effective_feerate{0};
/** The fee to spend these UTXOs at the long term feerate. */
CAmount long_term_fee{0};
/** The feerate for spending a created change output eventually (i.e. not urgently, and thus at
@@ -221,19 +236,44 @@ struct OutputGroup
/** Indicate that we are subtracting the fee from outputs.
* When true, the value that is used for coin selection is the UTXO's real value rather than effective value */
bool m_subtract_fee_outputs{false};
+ /** Total weight of the UTXOs in this group. */
+ int m_weight{0};
OutputGroup() {}
OutputGroup(const CoinSelectionParams& params) :
- m_effective_feerate(params.m_effective_feerate),
m_long_term_feerate(params.m_long_term_feerate),
m_subtract_fee_outputs(params.m_subtract_fee_outputs)
{}
- void Insert(const COutput& output, size_t ancestors, size_t descendants, bool positive_only);
+ void Insert(const std::shared_ptr<COutput>& output, size_t ancestors, size_t descendants);
bool EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const;
CAmount GetSelectionAmount() const;
};
+struct Groups {
+ // Stores 'OutputGroup' containing only positive UTXOs (value > 0).
+ std::vector<OutputGroup> positive_group;
+ // Stores 'OutputGroup' which may contain both positive and negative UTXOs.
+ std::vector<OutputGroup> mixed_group;
+};
+
+/** Stores several 'Groups' whose were mapped by output type. */
+struct OutputGroupTypeMap
+{
+ // Maps output type to output groups.
+ std::map<OutputType, Groups> groups_by_type;
+ // All inserted groups, no type distinction.
+ Groups all_groups;
+
+ // Based on the insert flag; appends group to the 'mixed_group' and, if value > 0, to the 'positive_group'.
+ // This affects both; the groups filtered by type and the overall groups container.
+ void Push(const OutputGroup& group, OutputType type, bool insert_positive, bool insert_mixed);
+ // Different output types count
+ size_t TypesCount() { return groups_by_type.size(); }
+};
+
+typedef std::map<CoinEligibilityFilter, OutputGroupTypeMap> FilteredOutputGroups;
+
/** Compute the waste for this result given the cost of change
* and the opportunity cost of spending these inputs now vs in the future.
* If change exists, waste = change_cost + inputs * (effective_feerate - long_term_feerate)
@@ -251,7 +291,7 @@ struct OutputGroup
* @param[in] use_effective_value Whether to use the input's effective value (when true) or the real value (when false).
* @return The waste
*/
-[[nodiscard]] CAmount GetSelectionWaste(const std::set<COutput>& inputs, CAmount change_cost, CAmount target, bool use_effective_value = true);
+[[nodiscard]] CAmount GetSelectionWaste(const std::set<std::shared_ptr<COutput>>& inputs, CAmount change_cost, CAmount target, bool use_effective_value = true);
/** Choose a random change target for each transaction to make it harder to fingerprint the Core
@@ -284,7 +324,7 @@ struct SelectionResult
{
private:
/** Set of inputs selected by the algorithm to use in the transaction */
- std::set<COutput> m_selected_inputs;
+ std::set<std::shared_ptr<COutput>> m_selected_inputs;
/** The target the algorithm selected for. Equal to the recipient amount plus non-input fees */
CAmount m_target;
/** The algorithm used to produce this result */
@@ -293,6 +333,19 @@ private:
bool m_use_effective{false};
/** The computed waste */
std::optional<CAmount> m_waste;
+ /** Total weight of the selected inputs */
+ int m_weight{0};
+
+ template<typename T>
+ void InsertInputs(const T& inputs)
+ {
+ // Store sum of combined input sets to check that the results have no shared UTXOs
+ const size_t expected_count = m_selected_inputs.size() + inputs.size();
+ util::insert(m_selected_inputs, inputs);
+ if (m_selected_inputs.size() != expected_count) {
+ throw std::runtime_error(STR_INTERNAL_BUG("Shared UTXOs among selection results"));
+ }
+ }
public:
explicit SelectionResult(const CAmount target, SelectionAlgorithm algo)
@@ -308,17 +361,24 @@ public:
void Clear();
void AddInput(const OutputGroup& group);
+ void AddInputs(const std::set<std::shared_ptr<COutput>>& inputs, bool subtract_fee_outputs);
/** Calculates and stores the waste for this selection via GetSelectionWaste */
void ComputeAndSetWaste(const CAmount min_viable_change, const CAmount change_cost, const CAmount change_fee);
[[nodiscard]] CAmount GetWaste() const;
+ /**
+ * Combines the @param[in] other selection result into 'this' selection result.
+ *
+ * Important note:
+ * There must be no shared 'COutput' among the two selection results being combined.
+ */
void Merge(const SelectionResult& other);
/** Get m_selected_inputs */
- const std::set<COutput>& GetInputSet() const;
+ const std::set<std::shared_ptr<COutput>>& GetInputSet() const;
/** Get the vector of COutputs that will be used to fill in a CTransaction's vin */
- std::vector<COutput> GetShuffledInputVector() const;
+ std::vector<std::shared_ptr<COutput>> GetShuffledInputVector() const;
bool operator<(SelectionResult other) const;
@@ -344,6 +404,8 @@ public:
CAmount GetTarget() const { return m_target; }
SelectionAlgorithm GetAlgo() const { return m_algo; }
+
+ int GetWeight() const { return m_weight; }
};
std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change);
diff --git a/src/wallet/context.cpp b/src/wallet/context.cpp
index 3d4bf9d703..39c3b54bf1 100644
--- a/src/wallet/context.cpp
+++ b/src/wallet/context.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index 4d325c7557..b776a9c497 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/db.h b/src/wallet/db.h
index f09844c37e..d4c590fac7 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -22,14 +22,33 @@ struct bilingual_str;
namespace wallet {
void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename);
+class DatabaseCursor
+{
+public:
+ explicit DatabaseCursor() {}
+ virtual ~DatabaseCursor() {}
+
+ DatabaseCursor(const DatabaseCursor&) = delete;
+ DatabaseCursor& operator=(const DatabaseCursor&) = delete;
+
+ enum class Status
+ {
+ FAIL,
+ MORE,
+ DONE,
+ };
+
+ virtual Status Next(DataStream& key, DataStream& value) { return Status::FAIL; }
+};
+
/** RAII class that provides access to a WalletDatabase */
class DatabaseBatch
{
private:
- virtual bool ReadKey(CDataStream&& key, CDataStream& value) = 0;
- virtual bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite=true) = 0;
- virtual bool EraseKey(CDataStream&& key) = 0;
- virtual bool HasKey(CDataStream&& key) = 0;
+ virtual bool ReadKey(DataStream&& key, DataStream& value) = 0;
+ virtual bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) = 0;
+ virtual bool EraseKey(DataStream&& key) = 0;
+ virtual bool HasKey(DataStream&& key) = 0;
public:
explicit DatabaseBatch() {}
@@ -44,7 +63,7 @@ public:
template <typename K, typename T>
bool Read(const K& key, T& value)
{
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ DataStream ssKey{};
ssKey.reserve(1000);
ssKey << key;
@@ -61,7 +80,7 @@ public:
template <typename K, typename T>
bool Write(const K& key, const T& value, bool fOverwrite = true)
{
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ DataStream ssKey{};
ssKey.reserve(1000);
ssKey << key;
@@ -75,7 +94,7 @@ public:
template <typename K>
bool Erase(const K& key)
{
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ DataStream ssKey{};
ssKey.reserve(1000);
ssKey << key;
@@ -85,16 +104,14 @@ public:
template <typename K>
bool Exists(const K& key)
{
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ DataStream ssKey{};
ssKey.reserve(1000);
ssKey << key;
return HasKey(std::move(ssKey));
}
- virtual bool StartCursor() = 0;
- virtual bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) = 0;
- virtual void CloseCursor() = 0;
+ virtual std::unique_ptr<DatabaseCursor> GetNewCursor() = 0;
virtual bool TxnBegin() = 0;
virtual bool TxnCommit() = 0;
virtual bool TxnAbort() = 0;
@@ -106,7 +123,7 @@ class WalletDatabase
{
public:
/** Create dummy DB handle */
- WalletDatabase() : nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0) {}
+ WalletDatabase() : nUpdateCounter(0) {}
virtual ~WalletDatabase() {};
/** Open the database if it is not already opened. */
@@ -148,30 +165,33 @@ public:
virtual std::string Format() = 0;
std::atomic<unsigned int> nUpdateCounter;
- unsigned int nLastSeen;
- unsigned int nLastFlushed;
- int64_t nLastWalletUpdate;
+ unsigned int nLastSeen{0};
+ unsigned int nLastFlushed{0};
+ int64_t nLastWalletUpdate{0};
/** Make a DatabaseBatch connected to this database */
virtual std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) = 0;
};
+class DummyCursor : public DatabaseCursor
+{
+ Status Next(DataStream& key, DataStream& value) override { return Status::FAIL; }
+};
+
/** RAII class that provides access to a DummyDatabase. Never fails. */
class DummyBatch : public DatabaseBatch
{
private:
- bool ReadKey(CDataStream&& key, CDataStream& value) override { return true; }
- bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite=true) override { return true; }
- bool EraseKey(CDataStream&& key) override { return true; }
- bool HasKey(CDataStream&& key) override { return true; }
+ bool ReadKey(DataStream&& key, DataStream& value) override { return true; }
+ bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override { return true; }
+ bool EraseKey(DataStream&& key) override { return true; }
+ bool HasKey(DataStream&& key) override { return true; }
public:
void Flush() override {}
void Close() override {}
- bool StartCursor() override { return true; }
- bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) override { return true; }
- void CloseCursor() override {}
+ std::unique_ptr<DatabaseCursor> GetNewCursor() override { return std::make_unique<DummyCursor>(); }
bool TxnBegin() override { return true; }
bool TxnCommit() override { return true; }
bool TxnAbort() override { return true; }
diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp
index f7fee443d0..69208c19dc 100644
--- a/src/wallet/dump.cpp
+++ b/src/wallet/dump.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 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 <wallet/dump.h>
#include <fs.h>
+#include <util/system.h>
#include <util/translation.h>
#include <wallet/wallet.h>
@@ -47,7 +48,8 @@ bool DumpWallet(const ArgsManager& args, CWallet& wallet, bilingual_str& error)
std::unique_ptr<DatabaseBatch> batch = db.MakeBatch();
bool ret = true;
- if (!batch->StartCursor()) {
+ std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
+ if (!cursor) {
error = _("Error: Couldn't create cursor into database");
ret = false;
}
@@ -66,15 +68,15 @@ bool DumpWallet(const ArgsManager& args, CWallet& wallet, bilingual_str& error)
// Read the records
while (true) {
- CDataStream ss_key(SER_DISK, CLIENT_VERSION);
- CDataStream ss_value(SER_DISK, CLIENT_VERSION);
- bool complete;
- ret = batch->ReadAtCursor(ss_key, ss_value, complete);
- if (complete) {
+ DataStream ss_key{};
+ DataStream ss_value{};
+ DatabaseCursor::Status status = cursor->Next(ss_key, ss_value);
+ if (status == DatabaseCursor::Status::DONE) {
ret = true;
break;
- } else if (!ret) {
+ } else if (status == DatabaseCursor::Status::FAIL) {
error = _("Error reading next record from wallet database");
+ ret = false;
break;
}
std::string key_str = HexStr(ss_key);
@@ -85,7 +87,7 @@ bool DumpWallet(const ArgsManager& args, CWallet& wallet, bilingual_str& error)
}
}
- batch->CloseCursor();
+ cursor.reset();
batch.reset();
// Close the wallet after we're done with it. The caller won't be doing this
@@ -201,7 +203,7 @@ bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::
// dummy chain interface
bool ret = true;
- std::shared_ptr<CWallet> wallet(new CWallet(nullptr /* chain */, name, gArgs, std::move(database)), WalletToolReleaseWallet);
+ std::shared_ptr<CWallet> wallet(new CWallet(/*chain=*/nullptr, name, std::move(database)), WalletToolReleaseWallet);
{
LOCK(wallet->cs_wallet);
DBErrors load_wallet_ret = wallet->LoadWallet();
@@ -254,8 +256,8 @@ bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::
std::vector<unsigned char> k = ParseHex(key);
std::vector<unsigned char> v = ParseHex(value);
- CDataStream ss_key(k, SER_DISK, CLIENT_VERSION);
- CDataStream ss_value(v, SER_DISK, CLIENT_VERSION);
+ DataStream ss_key{k};
+ DataStream ss_value{v};
if (!batch->Write(ss_key, ss_value)) {
error = strprintf(_("Error: Unable to write record to new wallet"));
diff --git a/src/wallet/dump.h b/src/wallet/dump.h
index bf683e9843..ff0d94e4b2 100644
--- a/src/wallet/dump.h
+++ b/src/wallet/dump.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp
index 76de51ac3e..cb861d835e 100644
--- a/src/wallet/external_signer_scriptpubkeyman.cpp
+++ b/src/wallet/external_signer_scriptpubkeyman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/external_signer_scriptpubkeyman.h b/src/wallet/external_signer_scriptpubkeyman.h
index 9918979a81..01dc80b1ca 100644
--- a/src/wallet/external_signer_scriptpubkeyman.h
+++ b/src/wallet/external_signer_scriptpubkeyman.h
@@ -13,11 +13,11 @@ namespace wallet {
class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan
{
public:
- ExternalSignerScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor)
- : DescriptorScriptPubKeyMan(storage, descriptor)
+ ExternalSignerScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size)
+ : DescriptorScriptPubKeyMan(storage, descriptor, keypool_size)
{}
- ExternalSignerScriptPubKeyMan(WalletStorage& storage)
- : DescriptorScriptPubKeyMan(storage)
+ ExternalSignerScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size)
+ : DescriptorScriptPubKeyMan(storage, keypool_size)
{}
/** Provide a descriptor at setup time
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 6d7bb299cc..37a704bfa4 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -155,7 +155,7 @@ bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid)
}
Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCoinControl& coin_control, std::vector<bilingual_str>& errors,
- CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx, bool require_mine)
+ CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx, bool require_mine, const std::vector<CTxOut>& outputs)
{
// We are going to modify coin control later, copy to re-use
CCoinControl new_coin_control(coin_control);
@@ -222,11 +222,19 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
return result;
}
- // Fill in recipients(and preserve a single change key if there is one)
- // While we're here, calculate the output amount
- std::vector<CRecipient> recipients;
+ // Calculate the old output amount.
CAmount output_value = 0;
- for (const auto& output : wtx.tx->vout) {
+ for (const auto& old_output : wtx.tx->vout) {
+ output_value += old_output.nValue;
+ }
+
+ old_fee = input_value - output_value;
+
+ // Fill in recipients (and preserve a single change key if there
+ // is one). If outputs vector is non-empty, replace original
+ // outputs with its contents, otherwise use original outputs.
+ std::vector<CRecipient> recipients;
+ for (const auto& output : outputs.empty() ? wtx.tx->vout : outputs) {
if (!OutputIsChange(wallet, output)) {
CRecipient recipient = {output.scriptPubKey, output.nValue, false};
recipients.push_back(recipient);
@@ -235,11 +243,8 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
ExtractDestination(output.scriptPubKey, change_dest);
new_coin_control.destChange = change_dest;
}
- output_value += output.nValue;
}
- old_fee = input_value - output_value;
-
if (coin_control.m_feerate) {
// The user provided a feeRate argument.
// We calculate this here to avoid compiler warning on the cs_wallet lock
@@ -293,7 +298,22 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) {
LOCK(wallet.cs_wallet);
- return wallet.SignTransaction(mtx);
+
+ if (wallet.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
+ // Make a blank psbt
+ PartiallySignedTransaction psbtx(mtx);
+
+ // First fill transaction with our data without signing,
+ // so external signers are not asked to sign more than once.
+ bool complete;
+ wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, false /* sign */, true /* bip32derivs */);
+ const TransactionError err = wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, true /* sign */, false /* bip32derivs */);
+ if (err != TransactionError::OK) return false;
+ complete = FinalizeAndExtractPSBT(psbtx, mtx);
+ return complete;
+ } else {
+ return wallet.SignTransaction(mtx);
+ }
}
Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, uint256& bumped_txid)
diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h
index 760ab58e5c..53cf16e0f1 100644
--- a/src/wallet/feebumper.h
+++ b/src/wallet/feebumper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2020 The Bitcoin Core developers
+// Copyright (c) 2017-2021 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,8 @@ Result CreateRateBumpTransaction(CWallet& wallet,
CAmount& old_fee,
CAmount& new_fee,
CMutableTransaction& mtx,
- bool require_mine);
+ bool require_mine,
+ const std::vector<CTxOut>& outputs);
//! Sign the new transaction,
//! @return false if the tx couldn't be found or if it was
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
index 3514d018b7..eda6d319ec 100644
--- a/src/wallet/fees.cpp
+++ b/src/wallet/fees.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -84,7 +84,7 @@ CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_contr
CFeeRate GetDiscardRate(const CWallet& wallet)
{
unsigned int highest_target = wallet.chain().estimateMaxBlocks();
- CFeeRate discard_rate = wallet.chain().estimateSmartFee(highest_target, false /* conservative */);
+ CFeeRate discard_rate = wallet.chain().estimateSmartFee(highest_target, /*conservative=*/false);
// Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate);
// Discard rate must be at least dust relay feerate
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 174c68744c..5403e38950 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -122,9 +122,6 @@ bool WalletInit::ParameterInteraction() const
return InitError(Untranslated("-zapwallettxes has been removed. If you are attempting to remove a stuck transaction from your wallet, please use abandontransaction instead."));
}
- if (gArgs.GetBoolArg("-sysperms", false))
- return InitError(Untranslated("-sysperms is not allowed in combination with enabled wallet functionality"));
-
return true;
}
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 9cf2b677e6..1a76e46c54 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -36,7 +36,7 @@
using interfaces::Chain;
using interfaces::FoundBlock;
using interfaces::Handler;
-using interfaces::MakeHandler;
+using interfaces::MakeSignalHandler;
using interfaces::Wallet;
using interfaces::WalletAddress;
using interfaces::WalletBalances;
@@ -291,7 +291,8 @@ public:
CAmount& new_fee,
CMutableTransaction& mtx) override
{
- return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx, /* require_mine= */ true) == feebumper::Result::OK;
+ std::vector<CTxOut> outputs; // just an empty list of new recipients for now
+ return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx, /* require_mine= */ true, outputs) == feebumper::Result::OK;
}
bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); }
bool commitBumpTransaction(const uint256& txid,
@@ -481,39 +482,39 @@ public:
CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
void remove() override
{
- RemoveWallet(m_context, m_wallet, false /* load_on_start */);
+ RemoveWallet(m_context, m_wallet, /*load_on_start=*/false);
}
bool isLegacy() override { return m_wallet->IsLegacy(); }
std::unique_ptr<Handler> handleUnload(UnloadFn fn) override
{
- return MakeHandler(m_wallet->NotifyUnload.connect(fn));
+ return MakeSignalHandler(m_wallet->NotifyUnload.connect(fn));
}
std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
{
- return MakeHandler(m_wallet->ShowProgress.connect(fn));
+ return MakeSignalHandler(m_wallet->ShowProgress.connect(fn));
}
std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override
{
- return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); }));
+ return MakeSignalHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); }));
}
std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
{
- return MakeHandler(m_wallet->NotifyAddressBookChanged.connect(
+ return MakeSignalHandler(m_wallet->NotifyAddressBookChanged.connect(
[fn](const CTxDestination& address, const std::string& label, bool is_mine,
const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
}
std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override
{
- return MakeHandler(m_wallet->NotifyTransactionChanged.connect(
+ return MakeSignalHandler(m_wallet->NotifyTransactionChanged.connect(
[fn](const uint256& txid, ChangeType status) { fn(txid, status); }));
}
std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override
{
- return MakeHandler(m_wallet->NotifyWatchonlyChanged.connect(fn));
+ return MakeSignalHandler(m_wallet->NotifyWatchonlyChanged.connect(fn));
}
std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override
{
- return MakeHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn));
+ return MakeSignalHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn));
}
CWallet* wallet() override { return m_wallet.get(); }
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 6eb0ef5e7a..8c60a2da72 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/load.h b/src/wallet/load.h
index 5c2bbdabe4..0882f7f8ad 100644
--- a/src/wallet/load.h
+++ b/src/wallet/load.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp
index 7fbf2ff8cf..0a75bb6d92 100644
--- a/src/wallet/receive.cpp
+++ b/src/wallet/receive.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/receive.h b/src/wallet/receive.h
index 9125b1e9aa..87be0fc2ae 100644
--- a/src/wallet/receive.h
+++ b/src/wallet/receive.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp
index 903a569cb9..da63d45d11 100644
--- a/src/wallet/rpc/addresses.cpp
+++ b/src/wallet/rpc/addresses.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -43,9 +43,7 @@ RPCHelpMan getnewaddress()
}
// Parse the label first so we don't generate a key if there's an error
- std::string label;
- if (!request.params[0].isNull())
- label = LabelFromValue(request.params[0]);
+ const std::string label{LabelFromValue(request.params[0])};
OutputType output_type = pwallet->m_default_address_type;
if (!request.params[1].isNull()) {
@@ -140,7 +138,7 @@ RPCHelpMan setlabel()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
}
- std::string label = LabelFromValue(request.params[1]);
+ const std::string label{LabelFromValue(request.params[1])};
if (pwallet->IsMine(dest)) {
pwallet->SetAddressBook(dest, label, "receive");
@@ -228,7 +226,7 @@ RPCHelpMan addmultisigaddress()
{"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address or hex-encoded public key"},
},
},
- {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A label to assign the addresses to."},
+ {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A label to assign the addresses to."},
{"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
},
RPCResult{
@@ -258,9 +256,7 @@ RPCHelpMan addmultisigaddress()
LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
- std::string label;
- if (!request.params[2].isNull())
- label = LabelFromValue(request.params[2]);
+ const std::string label{LabelFromValue(request.params[2])};
int required = request.params[0].getInt<int>();
@@ -662,7 +658,7 @@ RPCHelpMan getaddressesbylabel()
LOCK(pwallet->cs_wallet);
- std::string label = LabelFromValue(request.params[0]);
+ const std::string label{LabelFromValue(request.params[0])};
// Find all addresses that have the given label
UniValue ret(UniValue::VOBJ);
@@ -700,7 +696,7 @@ RPCHelpMan listlabels()
return RPCHelpMan{"listlabels",
"\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",
{
- {"purpose", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
+ {"purpose", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
},
RPCResult{
RPCResult::Type::ARR, "", "",
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp
index 8babbb4298..09cfc07bc2 100644
--- a/src/wallet/rpc/backup.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,6 +6,7 @@
#include <clientversion.h>
#include <core_io.h>
#include <fs.h>
+#include <hash.h>
#include <interfaces/chain.h>
#include <key_io.h>
#include <merkleblock.h>
@@ -14,8 +15,8 @@
#include <script/script.h>
#include <script/standard.h>
#include <sync.h>
+#include <uint256.h>
#include <util/bip32.h>
-#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>
#include <wallet/rpc/util.h>
@@ -93,6 +94,22 @@ static void RescanWallet(CWallet& wallet, const WalletRescanReserver& reserver,
}
}
+static void EnsureBlockDataFromTime(const CWallet& wallet, int64_t timestamp)
+{
+ auto& chain{wallet.chain()};
+ if (!chain.havePruned()) {
+ return;
+ }
+
+ int height{0};
+ const bool found{chain.findFirstBlockWithTimeAndHeight(timestamp - TIMESTAMP_WINDOW, 0, FoundBlock().height(height))};
+
+ uint256 tip_hash{WITH_LOCK(wallet.cs_wallet, return wallet.GetLastBlockHash())};
+ if (found && !chain.hasBlocks(tip_hash, height)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Pruned blocks from height %d required to import keys. Use RPC call getblockchaininfo to determine your pruned height.", height));
+ }
+}
+
RPCHelpMan importprivkey()
{
return RPCHelpMan{"importprivkey",
@@ -140,9 +157,7 @@ RPCHelpMan importprivkey()
EnsureWalletIsUnlocked(*pwallet);
std::string strSecret = request.params[0].get_str();
- std::string strLabel;
- if (!request.params[1].isNull())
- strLabel = request.params[1].get_str();
+ const std::string strLabel{LabelFromValue(request.params[1])};
// Whether to perform rescan after import
if (!request.params[2].isNull())
@@ -184,7 +199,7 @@ RPCHelpMan importprivkey()
// Add the wpkh script for this key if possible
if (pubkey.IsCompressed()) {
- pwallet->ImportScripts({GetScriptForDestination(WitnessV0KeyHash(vchAddress))}, 0 /* timestamp */);
+ pwallet->ImportScripts({GetScriptForDestination(WitnessV0KeyHash(vchAddress))}, /*timestamp=*/0);
}
}
}
@@ -233,9 +248,7 @@ RPCHelpMan importaddress()
EnsureLegacyScriptPubKeyMan(*pwallet, true);
- std::string strLabel;
- if (!request.params[1].isNull())
- strLabel = request.params[1].get_str();
+ const std::string strLabel{LabelFromValue(request.params[1])};
// Whether to perform rescan after import
bool fRescan = true;
@@ -273,19 +286,19 @@ RPCHelpMan importaddress()
pwallet->MarkDirty();
- pwallet->ImportScriptPubKeys(strLabel, {GetScriptForDestination(dest)}, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
+ pwallet->ImportScriptPubKeys(strLabel, {GetScriptForDestination(dest)}, /*have_solving_data=*/false, /*apply_label=*/true, /*timestamp=*/1);
} else if (IsHex(request.params[0].get_str())) {
std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
CScript redeem_script(data.begin(), data.end());
std::set<CScript> scripts = {redeem_script};
- pwallet->ImportScripts(scripts, 0 /* timestamp */);
+ pwallet->ImportScripts(scripts, /*timestamp=*/0);
if (fP2SH) {
scripts.insert(GetScriptForDestination(ScriptHash(redeem_script)));
}
- pwallet->ImportScriptPubKeys(strLabel, scripts, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
+ pwallet->ImportScriptPubKeys(strLabel, scripts, /*have_solving_data=*/false, /*apply_label=*/true, /*timestamp=*/1);
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
}
@@ -293,10 +306,7 @@ RPCHelpMan importaddress()
if (fRescan)
{
RescanWallet(*pwallet, reserver);
- {
- LOCK(pwallet->cs_wallet);
- pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
- }
+ pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
}
return UniValue::VNULL;
@@ -325,7 +335,7 @@ RPCHelpMan importprunedfunds()
}
uint256 hashTx = tx.GetHash();
- CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
+ DataStream ssMB{ParseHexV(request.params[1], "proof")};
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
@@ -429,9 +439,7 @@ RPCHelpMan importpubkey()
EnsureLegacyScriptPubKeyMan(*pwallet, true);
- std::string strLabel;
- if (!request.params[1].isNull())
- strLabel = request.params[1].get_str();
+ const std::string strLabel{LabelFromValue(request.params[1])};
// Whether to perform rescan after import
bool fRescan = true;
@@ -467,17 +475,14 @@ RPCHelpMan importpubkey()
pwallet->MarkDirty();
- pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, true /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
+ pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, /*have_solving_data=*/true, /*apply_label=*/true, /*timestamp=*/1);
- pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , {} /* key_origins */, false /* add_keypool */, false /* internal */, 1 /* timestamp */);
+ pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*internal=*/false, /*timestamp=*/1);
}
if (fRescan)
{
RescanWallet(*pwallet, reserver);
- {
- LOCK(pwallet->cs_wallet);
- pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
- }
+ pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
}
return UniValue::VNULL;
@@ -510,13 +515,6 @@ RPCHelpMan importwallet()
EnsureLegacyScriptPubKeyMan(*pwallet, true);
- if (pwallet->chain().havePruned()) {
- // Exit early and print an error.
- // If a block is pruned after this check, we will import the key(s),
- // but fail the rescan with a generic error.
- throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned");
- }
-
WalletRescanReserver reserver(*pwallet);
if (!reserver.reserve()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
@@ -571,15 +569,18 @@ RPCHelpMan importwallet()
fLabel = true;
}
}
+ 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());
int64_t birth_time = ParseISO8601DateTime(vstr[1]);
+ if (birth_time > 0) nTimeBegin = std::min(nTimeBegin, birth_time);
scripts.push_back(std::pair<CScript, int64_t>(script, birth_time));
}
}
file.close();
+ EnsureBlockDataFromTime(*pwallet, nTimeBegin);
// 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)) {
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
@@ -608,8 +609,6 @@ RPCHelpMan importwallet()
if (has_label)
pwallet->SetAddressBook(PKHash(keyid), label, "receive");
-
- nTimeBegin = std::min(nTimeBegin, time);
progress++;
}
for (const auto& script_pair : scripts) {
@@ -622,16 +621,13 @@ RPCHelpMan importwallet()
fGood = false;
continue;
}
- if (time > 0) {
- nTimeBegin = std::min(nTimeBegin, time);
- }
progress++;
}
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
}
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
- RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
+ RescanWallet(*pwallet, reserver, nTimeBegin, /*update=*/false);
pwallet->MarkDirty();
if (!fGood)
@@ -891,9 +887,7 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
}
case TxoutType::WITNESS_V0_SCRIPTHASH: {
if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WSH inside another P2WSH");
- uint256 fullid(solverdata[0]);
- CScriptID id;
- CRIPEMD160().Write(fullid.begin(), fullid.size()).Finalize(id.begin());
+ CScriptID id{RIPEMD160(solverdata[0])};
auto subscript = std::move(import_data.witnessscript); // Remove redeemscript from import_data to check for superfluous script later.
if (!subscript) return "missing witnessscript";
if (CScriptID(*subscript) != id) return "witnessScript does not match the scriptPubKey or redeemScript";
@@ -1169,7 +1163,7 @@ static UniValue ProcessImport(CWallet& wallet, const UniValue& data, const int64
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() : "";
+ const std::string label{LabelFromValue(data["label"])};
const bool add_keypool = data.exists("keypool") ? data["keypool"].get_bool() : false;
// Add to keypool only works with privkeys disabled
@@ -1297,7 +1291,7 @@ RPCHelpMan importmulti()
},
},
RPCArgOptions{.oneline_description="\"requests\""}},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
+ {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
{"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Scan the chain and mempool for wallet transactions after all imports."},
},
@@ -1335,8 +1329,6 @@ RPCHelpMan importmulti()
// the user could have gotten from another RPC command prior to now
wallet.BlockUntilSyncedToCurrentChain();
- RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
-
EnsureLegacyScriptPubKeyMan(*pwallet, true);
const UniValue& requests = mainRequest.params[0];
@@ -1405,11 +1397,8 @@ RPCHelpMan importmulti()
}
}
if (fRescan && fRunScan && requests.size()) {
- int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
- {
- LOCK(pwallet->cs_wallet);
- pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
- }
+ int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, /*update=*/true);
+ pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
if (pwallet->IsAbortingRescan()) {
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
@@ -1466,7 +1455,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
const std::string& descriptor = data["desc"].get_str();
const bool active = data.exists("active") ? data["active"].get_bool() : false;
const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
- const std::string& label = data.exists("label") ? data["label"].get_str() : "";
+ const std::string label{LabelFromValue(data["label"])};
// Parse descriptor string
FlatSigningProvider keys;
@@ -1488,7 +1477,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
} else {
warnings.push_back("Range not given, using default keypool range");
range_start = 0;
- range_end = gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE);
+ range_end = wallet.m_keypool_size;
}
next_index = range_start;
@@ -1598,7 +1587,8 @@ RPCHelpMan importdescriptors()
return RPCHelpMan{"importdescriptors",
"\nImport descriptors. This will trigger a rescan of the blockchain based on the earliest timestamp of all descriptors being imported. Requires a new wallet backup.\n"
"\nNote: This call can take over an hour to complete if using an early timestamp; during that time, other rpc calls\n"
- "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n",
+ "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
+ "The rescan is significantly faster if block filters are available (using startup option \"-blockfilterindex=1\").\n",
{
{"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
{
@@ -1659,13 +1649,15 @@ RPCHelpMan importdescriptors()
throw JSONRPCError(RPC_WALLET_ERROR, "importdescriptors is not available for non-descriptor wallets");
}
- RPCTypeCheck(main_request.params, {UniValue::VARR, UniValue::VOBJ});
-
WalletRescanReserver reserver(*pwallet);
- if (!reserver.reserve()) {
+ if (!reserver.reserve(/*with_passphrase=*/true)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
}
+ // Ensure that the wallet is not locked for the remainder of this RPC, as
+ // the passphrase is used to top up the keypool.
+ LOCK(pwallet->m_relock_mutex);
+
const UniValue& requests = main_request.params[0];
const int64_t minimum_timestamp = 1;
int64_t now = 0;
@@ -1699,11 +1691,8 @@ RPCHelpMan importdescriptors()
// Rescan the blockchain using the lowest timestamp
if (rescan) {
- int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver, true /* update */);
- {
- LOCK(pwallet->cs_wallet);
- pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
- }
+ int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver, /*update=*/true);
+ pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
if (pwallet->IsAbortingRescan()) {
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
@@ -1771,7 +1760,8 @@ RPCHelpMan listdescriptors()
{RPCResult::Type::NUM, "", "Range start inclusive"},
{RPCResult::Type::NUM, "", "Range end inclusive"},
}},
- {RPCResult::Type::NUM, "next", /*optional=*/true, "The next index to generate addresses from; defined only for ranged descriptors"},
+ {RPCResult::Type::NUM, "next", /*optional=*/true, "Same as next_index field. Kept for compatibility reason."},
+ {RPCResult::Type::NUM, "next_index", /*optional=*/true, "The next index to generate addresses from; defined only for ranged descriptors"},
}},
}}
}},
@@ -1848,6 +1838,7 @@ RPCHelpMan listdescriptors()
range.push_back(info.range->second - 1);
spk.pushKV("range", range);
spk.pushKV("next", info.next_index);
+ spk.pushKV("next_index", info.next_index);
}
descriptors.push_back(spk);
}
@@ -1899,11 +1890,13 @@ RPCHelpMan restorewallet()
{
return RPCHelpMan{
"restorewallet",
- "\nRestore and loads a wallet from backup.\n",
+ "\nRestore and loads a wallet from backup.\n"
+ "\nThe rescan is significantly faster if a descriptor wallet is restored"
+ "\nand block filters are available (using startup option \"-blockfilterindex=1\").\n",
{
{"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name that will be applied to the restored wallet"},
{"backup_file", RPCArg::Type::STR, RPCArg::Optional::NO, "The backup file that will be used to restore the wallet."},
- {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
+ {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp
index 9c0c953a7a..4c386789f1 100644
--- a/src/wallet/rpc/coins.cpp
+++ b/src/wallet/rpc/coins.cpp
@@ -1,8 +1,9 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 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 <core_io.h>
+#include <hash.h>
#include <key_io.h>
#include <rpc/util.h>
#include <util/moneystr.h>
@@ -165,7 +166,7 @@ RPCHelpMan getbalance()
"The available balance is what the wallet considers currently spendable, and is\n"
"thus affected by options which limit spendability such as -spendzeroconfchange.\n",
{
- {"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
+ {"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
{"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "Only include transactions confirmed at least this many times."},
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also include balance in watch-only addresses (see 'importaddress')"},
{"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
@@ -509,12 +510,13 @@ RPCHelpMan listunspent()
},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include outputs that are not safe to spend\n"
"See description of \"safe\" attribute below."},
- {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "JSON with query options",
+ {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "JSON with query options",
{
{"minimumAmount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(0)}, "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
{"maximumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
{"maximumCount", RPCArg::Type::NUM, RPCArg::DefaultHint{"unlimited"}, "Maximum number of UTXOs"},
{"minimumSumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""},
+ {"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase UTXOs"}
},
RPCArgOptions{.oneline_description="query_options"}},
},
@@ -590,10 +592,8 @@ RPCHelpMan listunspent()
include_unsafe = request.params[3].get_bool();
}
- CAmount nMinimumAmount = 0;
- CAmount nMaximumAmount = MAX_MONEY;
- CAmount nMinimumSumAmount = MAX_MONEY;
- uint64_t nMaximumCount = 0;
+ CoinFilterParams filter_coins;
+ filter_coins.min_amount = 0;
if (!request.params[4].isNull()) {
const UniValue& options = request.params[4].get_obj();
@@ -604,20 +604,25 @@ RPCHelpMan listunspent()
{"maximumAmount", UniValueType()},
{"minimumSumAmount", UniValueType()},
{"maximumCount", UniValueType(UniValue::VNUM)},
+ {"include_immature_coinbase", UniValueType(UniValue::VBOOL)}
},
true, true);
if (options.exists("minimumAmount"))
- nMinimumAmount = AmountFromValue(options["minimumAmount"]);
+ filter_coins.min_amount = AmountFromValue(options["minimumAmount"]);
if (options.exists("maximumAmount"))
- nMaximumAmount = AmountFromValue(options["maximumAmount"]);
+ filter_coins.max_amount = AmountFromValue(options["maximumAmount"]);
if (options.exists("minimumSumAmount"))
- nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]);
+ filter_coins.min_sum_amount = AmountFromValue(options["minimumSumAmount"]);
if (options.exists("maximumCount"))
- nMaximumCount = options["maximumCount"].getInt<int64_t>();
+ filter_coins.max_count = options["maximumCount"].getInt<int64_t>();
+
+ if (options.exists("include_immature_coinbase")) {
+ filter_coins.include_immature_coinbase = options["include_immature_coinbase"].get_bool();
+ }
}
// Make sure the results are valid at least up to the most recent block
@@ -633,7 +638,7 @@ RPCHelpMan listunspent()
cctl.m_max_depth = nMaxDepth;
cctl.m_include_unsafe_inputs = include_unsafe;
LOCK(pwallet->cs_wallet);
- vecOutputs = AvailableCoinsListUnspent(*pwallet, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount).All();
+ vecOutputs = AvailableCoinsListUnspent(*pwallet, &cctl, filter_coins).All();
}
LOCK(pwallet->cs_wallet);
@@ -675,8 +680,7 @@ RPCHelpMan listunspent()
CHECK_NONFATAL(extracted);
// Also return the witness script
const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(witness_destination);
- CScriptID id;
- CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
+ CScriptID id{RIPEMD160(whash)};
CScript witnessScript;
if (provider->GetCScript(id, witnessScript)) {
entry.pushKV("witnessScript", HexStr(witnessScript));
@@ -685,8 +689,7 @@ RPCHelpMan listunspent()
}
} else if (scriptPubKey.IsPayToWitnessScriptHash()) {
const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(address);
- CScriptID id;
- CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
+ CScriptID id{RIPEMD160(whash)};
CScript witnessScript;
if (provider->GetCScript(id, witnessScript)) {
entry.pushKV("witnessScript", HexStr(witnessScript));
diff --git a/src/wallet/rpc/encrypt.cpp b/src/wallet/rpc/encrypt.cpp
index a68f52a718..0226d15698 100644
--- a/src/wallet/rpc/encrypt.cpp
+++ b/src/wallet/rpc/encrypt.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -49,9 +49,7 @@ RPCHelpMan walletpassphrase()
// Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
SecureString strWalletPass;
strWalletPass.reserve(100);
- // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make request.params[0] mlock()'d to begin with.
- strWalletPass = request.params[0].get_str().c_str();
+ strWalletPass = std::string_view{request.params[0].get_str()};
// Get the timeout
nSleepTime = request.params[1].getInt<int64_t>();
@@ -70,7 +68,17 @@ RPCHelpMan walletpassphrase()
}
if (!pwallet->Unlock(strWalletPass)) {
- throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
+ // Check if the passphrase has a null character (see #27067 for details)
+ if (strWalletPass.find('\0') == std::string::npos) {
+ throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
+ } else {
+ throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered is incorrect. "
+ "It contains a null character (ie - a zero byte). "
+ "If the passphrase was set with a version of this software prior to 25.0, "
+ "please try again with only the characters up to — but not including — "
+ "the first null character. If this is successful, please set a new "
+ "passphrase to avoid this issue in the future.");
+ }
}
pwallet->TopUpKeyPool();
@@ -90,7 +98,7 @@ RPCHelpMan walletpassphrase()
std::weak_ptr<CWallet> weak_wallet = wallet;
pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet, relock_time] {
if (auto shared_wallet = weak_wallet.lock()) {
- LOCK(shared_wallet->cs_wallet);
+ LOCK2(shared_wallet->m_relock_mutex, shared_wallet->cs_wallet);
// Skip if this is not the most recent rpcRunLater callback.
if (shared_wallet->nRelockTime != relock_time) return;
shared_wallet->Lock();
@@ -122,28 +130,39 @@ RPCHelpMan walletpassphrasechange()
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
- LOCK(pwallet->cs_wallet);
-
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
}
- // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make request.params[0] mlock()'d to begin with.
+ if (pwallet->IsScanningWithPassphrase()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before changing the passphrase.");
+ }
+
+ LOCK2(pwallet->m_relock_mutex, pwallet->cs_wallet);
+
SecureString strOldWalletPass;
strOldWalletPass.reserve(100);
- strOldWalletPass = request.params[0].get_str().c_str();
+ strOldWalletPass = std::string_view{request.params[0].get_str()};
SecureString strNewWalletPass;
strNewWalletPass.reserve(100);
- strNewWalletPass = request.params[1].get_str().c_str();
+ strNewWalletPass = std::string_view{request.params[1].get_str()};
if (strOldWalletPass.empty() || strNewWalletPass.empty()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase cannot be empty");
}
if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {
- throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
+ // Check if the old passphrase had a null character (see #27067 for details)
+ if (strOldWalletPass.find('\0') == std::string::npos) {
+ throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
+ } else {
+ throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The old wallet passphrase entered is incorrect. "
+ "It contains a null character (ie - a zero byte). "
+ "If the old passphrase was set with a version of this software prior to 25.0, "
+ "please try again with only the characters up to — but not including — "
+ "the first null character.");
+ }
}
return UniValue::VNULL;
@@ -175,12 +194,16 @@ RPCHelpMan walletlock()
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
- LOCK(pwallet->cs_wallet);
-
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
}
+ if (pwallet->IsScanningWithPassphrase()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before locking the wallet.");
+ }
+
+ LOCK2(pwallet->m_relock_mutex, pwallet->cs_wallet);
+
pwallet->Lock();
pwallet->nRelockTime = 0;
@@ -219,8 +242,6 @@ RPCHelpMan encryptwallet()
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
- LOCK(pwallet->cs_wallet);
-
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt.");
}
@@ -229,11 +250,15 @@ RPCHelpMan encryptwallet()
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
}
- // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make request.params[0] mlock()'d to begin with.
+ if (pwallet->IsScanningWithPassphrase()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before encrypting the wallet.");
+ }
+
+ LOCK2(pwallet->m_relock_mutex, pwallet->cs_wallet);
+
SecureString strWalletPass;
strWalletPass.reserve(100);
- strWalletPass = request.params[0].get_str().c_str();
+ strWalletPass = std::string_view{request.params[0].get_str()};
if (strWalletPass.empty()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase cannot be empty");
diff --git a/src/wallet/rpc/signmessage.cpp b/src/wallet/rpc/signmessage.cpp
index ae4bd4fbc5..c9fb693482 100644
--- a/src/wallet/rpc/signmessage.cpp
+++ b/src/wallet/rpc/signmessage.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index ebf694157b..88ee6e96b0 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -82,10 +82,10 @@ static UniValue FinishTransaction(const std::shared_ptr<CWallet> pwallet, const
PartiallySignedTransaction psbtx(rawTx);
// First fill transaction with our data without signing,
- // so external signers are not asked sign more than once.
+ // so external signers are not asked to sign more than once.
bool complete;
- pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, false, true);
- const TransactionError err{pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, true, false)};
+ pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true);
+ const TransactionError err{pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/true, /*bip32derivs=*/false)};
if (err != TransactionError::OK) {
throw JSONRPCTransactionError(err);
}
@@ -161,7 +161,7 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, util::ErrorString(res).original);
}
const CTransactionRef& tx = res->tx;
- wallet.CommitTransaction(tx, std::move(map_value), {} /* orderForm */);
+ wallet.CommitTransaction(tx, std::move(map_value), /*orderForm=*/{});
if (verbose) {
UniValue entry(UniValue::VOBJ);
entry.pushKV("txid", tx->GetHash().GetHex());
@@ -217,9 +217,9 @@ RPCHelpMan sendtoaddress()
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to send to."},
{"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
- {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment used to store what the transaction is for.\n"
+ {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A comment used to store what the transaction is for.\n"
"This is not part of the transaction, just kept in your wallet."},
- {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n"
+ {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A comment to store the name of the person or organization\n"
"to which you're sending the transaction. This is not part of the \n"
"transaction, just kept in your wallet."},
{"subtractfeefromamount", RPCArg::Type::BOOL, RPCArg::Default{false}, "The fee will be deducted from the amount being sent.\n"
@@ -314,18 +314,21 @@ RPCHelpMan sendtoaddress()
RPCHelpMan sendmany()
{
return RPCHelpMan{"sendmany",
- "\nSend multiple times. Amounts are double-precision floating point numbers." +
+ "Send multiple times. Amounts are double-precision floating point numbers." +
HELP_REQUIRING_PASSPHRASE,
{
- {"dummy", RPCArg::Type::STR, RPCArg::Optional::NO, "Must be set to \"\" for backwards compatibility.", RPCArgOptions{.oneline_description="\"\""}},
+ {"dummy", RPCArg::Type::STR, RPCArg::Default{"\"\""}, "Must be set to \"\" for backwards compatibility.",
+ RPCArgOptions{
+ .oneline_description = "\"\"",
+ }},
{"amounts", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::NO, "The addresses and amounts",
{
{"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
},
},
- {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "Ignored dummy value"},
- {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment"},
- {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The addresses.\n"
+ {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Ignored dummy value"},
+ {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A comment"},
+ {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The addresses.\n"
"The fee will be equally deducted from the amount of each selected address.\n"
"Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
"If no addresses are specified here, the sender pays the fee.",
@@ -459,7 +462,7 @@ static std::vector<RPCArg> FundTxDoc(bool solving_data = true)
},
};
if (solving_data) {
- args.push_back({"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
+ args.push_back({"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
"Used for fee estimation during coin selection.",
{
{
@@ -528,6 +531,8 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
{"replaceable", UniValueType(UniValue::VBOOL)},
{"conf_target", UniValueType(UniValue::VNUM)},
{"estimate_mode", UniValueType(UniValue::VSTR)},
+ {"minconf", UniValueType(UniValue::VNUM)},
+ {"maxconf", UniValueType(UniValue::VNUM)},
{"input_weights", UniValueType(UniValue::VARR)},
},
true, true);
@@ -593,6 +598,22 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
if (options.exists("replaceable")) {
coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
}
+
+ if (options.exists("minconf")) {
+ coinControl.m_min_depth = options["minconf"].getInt<int>();
+
+ if (coinControl.m_min_depth < 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative minconf");
+ }
+ }
+
+ if (options.exists("maxconf")) {
+ coinControl.m_max_depth = options["maxconf"].getInt<int>();
+
+ if (coinControl.m_max_depth < coinControl.m_min_depth) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("maxconf can't be lower than minconf: %d < %d", coinControl.m_max_depth, coinControl.m_min_depth));
+ }
+ }
SetFeeEstimateMode(wallet, coinControl, options["conf_target"], options["estimate_mode"], options["fee_rate"], override_min_fee);
}
} else {
@@ -737,16 +758,18 @@ RPCHelpMan fundrawtransaction()
"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
+ {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
Cat<std::vector<RPCArg>>(
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
"Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
"If that happens, you will need to fund the transaction with different inputs and republish it."},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."},
+ {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."},
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
- {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
{"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
"e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
@@ -761,20 +784,27 @@ RPCHelpMan fundrawtransaction()
{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
},
},
- {"input_weights", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Inputs and their corresponding weights",
+ {"input_weights", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Inputs and their corresponding weights",
{
- {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
- {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"},
- {"weight", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum weight for this input, "
- "including the weight of the outpoint and sequence number. "
- "Note that serialized signature sizes are not guaranteed to be consistent, "
- "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures."
- "Remember to convert serialized sizes to weight units when necessary."},
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+ {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"},
+ {"weight", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum weight for this input, "
+ "including the weight of the outpoint and sequence number. "
+ "Note that serialized signature sizes are not guaranteed to be consistent, "
+ "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures."
+ "Remember to convert serialized sizes to weight units when necessary."},
+ },
+ },
},
},
},
FundTxDoc()),
- RPCArgOptions{.oneline_description="options"}},
+ RPCArgOptions{
+ .skip_type_check = true,
+ .oneline_description = "options",
+ }},
{"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"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.\n"
"If true, only witness deserialization will be tried.\n"
@@ -806,8 +836,6 @@ RPCHelpMan fundrawtransaction()
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
-
// parse hex string from parameter
CMutableTransaction tx;
bool try_witness = request.params[2].isNull() ? true : request.params[2].get_bool();
@@ -842,7 +870,7 @@ RPCHelpMan signrawtransactionwithwallet()
HELP_REQUIRING_PASSPHRASE,
{
{"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
- {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The previous dependent transaction outputs",
+ {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The previous dependent transaction outputs",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
@@ -896,8 +924,6 @@ RPCHelpMan signrawtransactionwithwallet()
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
-
CMutableTransaction mtx;
if (!DecodeHexTx(mtx, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
@@ -930,6 +956,26 @@ RPCHelpMan signrawtransactionwithwallet()
};
}
+// Definition of allowed formats of specifying transaction outputs in
+// `bumpfee`, `psbtbumpfee`, `send` and `walletcreatefundedpsbt` RPCs.
+static std::vector<RPCArg> OutputsDoc()
+{
+ return
+ {
+ {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "",
+ {
+ {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address,\n"
+ "the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
+ },
+ },
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {
+ {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
+ },
+ },
+ };
+}
+
static RPCHelpMan bumpfee_helper(std::string method_name)
{
const bool want_psbt = method_name == "psbtbumpfee";
@@ -951,7 +997,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
"* WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB. *\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
+ {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks\n"},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"},
@@ -966,7 +1012,12 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
"still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
"are replaceable).\n"},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
- "\"" + FeeModes("\"\n\"") + "\""},
+ "\"" + FeeModes("\"\n\"") + "\""},
+ {"outputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "New outputs (key-value pairs) which will replace\n"
+ "the original ones, if provided. Each address can only appear once and there can\n"
+ "only be one \"data\" object.\n",
+ OutputsDoc(),
+ RPCArgOptions{.skip_type_check = true}},
},
RPCArgOptions{.oneline_description="options"}},
},
@@ -993,17 +1044,17 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
- if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) {
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER) && !want_psbt) {
throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
}
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
uint256 hash(ParseHashV(request.params[0], "txid"));
CCoinControl coin_control;
coin_control.fAllowWatchOnly = pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
// optional parameters
coin_control.m_signal_bip125_rbf = true;
+ std::vector<CTxOut> outputs;
if (!request.params[1].isNull()) {
UniValue options = request.params[1];
@@ -1014,6 +1065,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
{"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
{"replaceable", UniValueType(UniValue::VBOOL)},
{"estimate_mode", UniValueType(UniValue::VSTR)},
+ {"outputs", UniValueType()}, // will be checked by AddOutputs()
},
true, true);
@@ -1027,6 +1079,16 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool();
}
SetFeeEstimateMode(*pwallet, coin_control, conf_target, options["estimate_mode"], options["fee_rate"], /*override_min_fee=*/false);
+
+ // Prepare new outputs by creating a temporary tx and calling AddOutputs().
+ if (!options["outputs"].isNull()) {
+ if (options["outputs"].isArray() && options["outputs"].empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument cannot be an empty array");
+ }
+ CMutableTransaction tempTx;
+ AddOutputs(tempTx, options["outputs"]);
+ outputs = tempTx.vout;
+ }
}
// Make sure the results are valid at least up to the most recent block
@@ -1044,7 +1106,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
CMutableTransaction mtx;
feebumper::Result res;
// Targeting feerate bump.
- res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx, /*require_mine=*/ !want_psbt);
+ res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx, /*require_mine=*/ !want_psbt, outputs);
if (res != feebumper::Result::OK) {
switch(res) {
case feebumper::Result::INVALID_ADDRESS_OR_KEY:
@@ -1071,6 +1133,9 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
// For psbtbumpfee, return the base64-encoded unsigned PSBT of the new transaction.
if (!want_psbt) {
if (!feebumper::SignTransaction(*pwallet, mtx)) {
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Transaction incomplete. Try psbtbumpfee instead.");
+ }
throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
}
@@ -1083,7 +1148,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
} else {
PartiallySignedTransaction psbtx(mtx);
bool complete = false;
- const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, false /* sign */, true /* bip32derivs */);
+ const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true);
CHECK_NONFATAL(err == TransactionError::OK);
CHECK_NONFATAL(!complete);
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
@@ -1116,34 +1181,25 @@ RPCHelpMan send()
{"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n"
"That is, each address can only appear once and there can only be one 'data' object.\n"
"For convenience, a dictionary, which holds the key-value pairs directly, is also accepted.",
- {
- {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "",
- {
- {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
- },
- },
- {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
- {
- {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
- },
- },
- },
- },
+ OutputsDoc(),
+ RPCArgOptions{.skip_type_check = true}},
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
"\"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
+ {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
Cat<std::vector<RPCArg>>(
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"},"Automatically include coins from the wallet to cover the target amount.\n"},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
"Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
"If that happens, you will need to fund the transaction with different inputs and republish it."},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."},
+ {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."},
{"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
{"change_address", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
{"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
- {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\" and \"bech32m\"."},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
@@ -1198,15 +1254,6 @@ RPCHelpMan send()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {
- UniValueType(), // outputs (ARR or OBJ, checked later)
- UniValue::VNUM, // conf_target
- UniValue::VSTR, // estimate_mode
- UniValueType(), // fee_rate, will be checked by AmountFromValue() in SetFeeEstimateMode()
- UniValue::VOBJ, // options
- }, true
- );
-
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
@@ -1255,7 +1302,7 @@ RPCHelpMan sendall()
"\"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{
- "options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
+ "options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
Cat<std::vector<RPCArg>>(
{
{"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns the serialized transaction without broadcasting or adding it to the wallet"},
@@ -1263,7 +1310,7 @@ RPCHelpMan sendall()
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch-only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
"e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
- {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with send_max.",
+ {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with the send_max, minconf, and maxconf options.",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
@@ -1278,6 +1325,8 @@ RPCHelpMan sendall()
{"lock_unspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
{"psbt", RPCArg::Type::BOOL, RPCArg::DefaultHint{"automatic"}, "Always return a PSBT, implies add_to_wallet=false."},
{"send_max", RPCArg::Type::BOOL, RPCArg::Default{false}, "When true, only use UTXOs that can pay for their own fees to maximize the output amount. When 'false' (default), no UTXO is left behind. send_max is incompatible with providing specific inputs."},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "Require inputs with at least this many confirmations."},
+ {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Require inputs with at most this many confirmations."},
},
FundTxDoc()
),
@@ -1307,15 +1356,6 @@ RPCHelpMan sendall()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- RPCTypeCheck(request.params, {
- UniValue::VARR, // recipients
- UniValue::VNUM, // conf_target
- UniValue::VSTR, // estimate_mode
- UniValueType(), // fee_rate, will be checked by AmountFromValue() in SetFeeEstimateMode()
- UniValue::VOBJ, // options
- }, true
- );
-
std::shared_ptr<CWallet> const pwallet{GetWalletForJSONRPCRequest(request)};
if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
@@ -1352,6 +1392,23 @@ RPCHelpMan sendall()
coin_control.fAllowWatchOnly = ParseIncludeWatchonly(options["include_watching"], *pwallet);
+ if (options.exists("minconf")) {
+ if (options["minconf"].getInt<int>() < 0)
+ {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid minconf (minconf cannot be negative): %s", options["minconf"].getInt<int>()));
+ }
+
+ coin_control.m_min_depth = options["minconf"].getInt<int>();
+ }
+
+ if (options.exists("maxconf")) {
+ coin_control.m_max_depth = options["maxconf"].getInt<int>();
+
+ if (coin_control.m_max_depth < coin_control.m_min_depth) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("maxconf can't be lower than minconf: %d < %d", coin_control.m_max_depth, coin_control.m_min_depth));
+ }
+ }
+
const bool rbf{options.exists("replaceable") ? options["replaceable"].get_bool() : pwallet->m_signal_rbf};
FeeCalculation fee_calc_out;
@@ -1373,19 +1430,23 @@ RPCHelpMan sendall()
bool send_max{options.exists("send_max") ? options["send_max"].get_bool() : false};
if (options.exists("inputs") && options.exists("send_max")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot combine send_max with specific inputs.");
+ } else if (options.exists("inputs") && (options.exists("minconf") || options.exists("maxconf"))) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot combine minconf or maxconf with specific inputs.");
} else if (options.exists("inputs")) {
for (const CTxIn& input : rawTx.vin) {
if (pwallet->IsSpent(input.prevout)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not available. UTXO (%s:%d) was already spent.", input.prevout.hash.ToString(), input.prevout.n));
}
const CWalletTx* tx{pwallet->GetWalletTx(input.prevout.hash)};
- if (!tx || pwallet->IsMine(tx->tx->vout[input.prevout.n]) != (coin_control.fAllowWatchOnly ? ISMINE_ALL : ISMINE_SPENDABLE)) {
+ if (!tx || input.prevout.n >= tx->tx->vout.size() || !(pwallet->IsMine(tx->tx->vout[input.prevout.n]) & (coin_control.fAllowWatchOnly ? ISMINE_ALL : ISMINE_SPENDABLE))) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not found. UTXO (%s:%d) is not part of wallet.", input.prevout.hash.ToString(), input.prevout.n));
}
total_input_value += tx->tx->vout[input.prevout.n].nValue;
}
} else {
- for (const COutput& output : AvailableCoins(*pwallet, &coin_control, fee_rate, /*nMinimumAmount=*/0).All()) {
+ CoinFilterParams coins_params;
+ coins_params.min_amount = 0;
+ for (const COutput& output : AvailableCoins(*pwallet, &coin_control, fee_rate, coins_params).All()) {
CHECK_NONFATAL(output.input_bytes > 0);
if (send_max && fee_rate.GetFee(output.input_bytes) > output.txout.nValue) {
continue;
@@ -1509,8 +1570,6 @@ RPCHelpMan walletprocesspsbt()
// the user could have gotten from another RPC command prior to now
wallet.BlockUntilSyncedToCurrentChain();
- RPCTypeCheck(request.params, {UniValue::VSTR});
-
// Unserialize the transaction
PartiallySignedTransaction psbtx;
std::string error;
@@ -1553,7 +1612,7 @@ RPCHelpMan walletcreatefundedpsbt()
"All existing inputs must either have their previous output transaction be in the wallet\n"
"or be in the UTXO set. Solving data must be provided for non-wallet inputs.\n",
{
- {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Leave empty to add inputs automatically. See add_inputs option.",
+ {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Leave empty to add inputs automatically. See add_inputs option.",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
@@ -1573,30 +1632,21 @@ RPCHelpMan walletcreatefundedpsbt()
"That is, each address can only appear once and there can only be one 'data' object.\n"
"For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
"accepted as second parameter.",
- {
- {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "",
- {
- {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
- },
- },
- {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
- {
- {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
- },
- },
- },
- },
+ OutputsDoc(),
+ RPCArgOptions{.skip_type_check = true}},
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
+ {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
Cat<std::vector<RPCArg>>(
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"}, "Automatically include coins from the wallet to cover the target amount.\n"},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
"Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
"If that happens, you will need to fund the transaction with different inputs and republish it."},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."},
+ {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."},
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
- {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
{"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only"},
{"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
@@ -1636,24 +1686,12 @@ RPCHelpMan walletcreatefundedpsbt()
// the user could have gotten from another RPC command prior to now
wallet.BlockUntilSyncedToCurrentChain();
- RPCTypeCheck(request.params, {
- UniValue::VARR,
- UniValueType(), // ARR or OBJ, checked later
- UniValue::VNUM,
- UniValue::VOBJ,
- UniValue::VBOOL
- }, true
- );
-
UniValue options{request.params[3].isNull() ? UniValue::VOBJ : request.params[3]};
CAmount fee;
int change_position;
- bool rbf{wallet.m_signal_rbf};
const UniValue &replaceable_arg = options["replaceable"];
- if (!replaceable_arg.isNull()) {
- rbf = replaceable_arg.isTrue();
- }
+ const bool rbf{replaceable_arg.isNull() ? wallet.m_signal_rbf : replaceable_arg.get_bool()};
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
CCoinControl coin_control;
// Automatically select coins, unless at least one is manually selected. Can
@@ -1668,7 +1706,7 @@ RPCHelpMan walletcreatefundedpsbt()
// Fill transaction with out data but don't sign
bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool();
bool complete = true;
- const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, false, bip32derivs)};
+ const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, /*sign=*/false, /*bip32derivs=*/bip32derivs)};
if (err != TransactionError::OK) {
throw JSONRPCTransactionError(err);
}
diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp
index 0e13e4756b..3bfe296d90 100644
--- a/src/wallet/rpc/transactions.cpp
+++ b/src/wallet/rpc/transactions.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -206,7 +206,7 @@ RPCHelpMan listreceivedbyaddress()
{"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
{"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include addresses that haven't received any payments."},
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"},
- {"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present and non-empty, only return information on this address."},
+ {"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If present and non-empty, only return information on this address."},
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
},
RPCResult{
@@ -316,7 +316,7 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
*/
template <class Vec>
static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong,
- Vec& ret, const isminefilter& filter_ismine, const std::string* filter_label,
+ Vec& ret, const isminefilter& filter_ismine, const std::optional<std::string>& filter_label,
bool include_change = false)
EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
@@ -329,7 +329,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
bool involvesWatchonly = CachedTxIsFromMe(wallet, wtx, ISMINE_WATCH_ONLY);
// Sent
- if (!filter_label)
+ if (!filter_label.has_value())
{
for (const COutputEntry& s : listSent)
{
@@ -362,7 +362,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
if (address_book_entry) {
label = address_book_entry->GetLabel();
}
- if (filter_label && label != *filter_label) {
+ if (filter_label.has_value() && label != filter_label.value()) {
continue;
}
UniValue entry(UniValue::VOBJ);
@@ -397,7 +397,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
}
-static const std::vector<RPCResult> TransactionDescriptionString()
+static std::vector<RPCResult> TransactionDescriptionString()
{
return{{RPCResult::Type::NUM, "confirmations", "The number of confirmations for the transaction. Negative confirmations means the\n"
"transaction conflicted that many blocks ago."},
@@ -416,7 +416,6 @@ static const std::vector<RPCResult> TransactionDescriptionString()
}},
{RPCResult::Type::STR_HEX, "replaced_by_txid", /*optional=*/true, "The txid if this tx was replaced."},
{RPCResult::Type::STR_HEX, "replaces_txid", /*optional=*/true, "The txid if the tx replaces one."},
- {RPCResult::Type::STR, "comment", /*optional=*/true, ""},
{RPCResult::Type::STR, "to", /*optional=*/true, "If a comment to is associated with the transaction."},
{RPCResult::Type::NUM_TIME, "time", "The transaction time expressed in " + UNIX_EPOCH_TIME + "."},
{RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."},
@@ -435,7 +434,7 @@ RPCHelpMan listtransactions()
"\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
{
- {"label|dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, should be a valid label name to return only incoming transactions\n"
+ {"label|dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If set, should be a valid label name to return only incoming transactions\n"
"with the specified label, or \"*\" to disable filtering and return all transactions."},
{"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"},
{"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"},
@@ -447,7 +446,7 @@ RPCHelpMan listtransactions()
{RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
{
{RPCResult::Type::BOOL, "involvesWatchonly", /*optional=*/true, "Only returns true if imported addresses were involved in transaction."},
- {RPCResult::Type::STR, "address", "The bitcoin address of the transaction."},
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
{RPCResult::Type::STR, "category", "The transaction category.\n"
"\"send\" Transactions sent.\n"
"\"receive\" Non-coinbase transactions received.\n"
@@ -485,10 +484,10 @@ RPCHelpMan listtransactions()
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- const std::string* filter_label = nullptr;
+ std::optional<std::string> filter_label;
if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
- filter_label = &request.params[0].get_str();
- if (filter_label->empty()) {
+ filter_label.emplace(LabelFromValue(request.params[0]));
+ if (filter_label.value().empty()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
}
}
@@ -546,12 +545,13 @@ RPCHelpMan listsinceblock()
"If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
"Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
{
- {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."},
+ {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If set, the block hash to list transactions since, otherwise list all transactions."},
{"target_confirmations", RPCArg::Type::NUM, RPCArg::Default{1}, "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"},
{"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n"
"(not guaranteed to work on pruned nodes)"},
{"include_change", RPCArg::Type::BOOL, RPCArg::Default{false}, "Also add entries for change outputs.\n"},
+ {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Return only incoming transactions paying to addresses with the specified label.\n"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -561,7 +561,7 @@ RPCHelpMan listsinceblock()
{RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
{
{RPCResult::Type::BOOL, "involvesWatchonly", /*optional=*/true, "Only returns true if imported addresses were involved in transaction."},
- {RPCResult::Type::STR, "address", "The bitcoin address of the transaction."},
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
{RPCResult::Type::STR, "category", "The transaction category.\n"
"\"send\" Transactions sent.\n"
"\"receive\" Non-coinbase transactions received.\n"
@@ -614,7 +614,7 @@ RPCHelpMan listsinceblock()
blockId = ParseHashV(request.params[0], "blockhash");
height = int{};
altheight = int{};
- if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /* ancestor out */ FoundBlock().height(*height), /* blockId out */ FoundBlock().height(*altheight))) {
+ if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /*ancestor_out=*/FoundBlock().height(*height), /*block1_out=*/FoundBlock().height(*altheight))) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
}
@@ -634,6 +634,10 @@ RPCHelpMan listsinceblock()
bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
bool include_change = (!request.params[4].isNull() && request.params[4].get_bool());
+ // Only set it if 'label' was provided.
+ std::optional<std::string> filter_label;
+ if (!request.params[5].isNull()) filter_label.emplace(LabelFromValue(request.params[5]));
+
int depth = height ? wallet.GetLastBlockHeight() + 1 - *height : -1;
UniValue transactions(UniValue::VARR);
@@ -642,7 +646,7 @@ RPCHelpMan listsinceblock()
const CWalletTx& tx = pairWtx.second;
if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) {
- ListTransactions(wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */, /*include_change=*/include_change);
+ ListTransactions(wallet, tx, 0, true, transactions, filter, filter_label, include_change);
}
}
@@ -659,7 +663,7 @@ RPCHelpMan listsinceblock()
if (it != wallet.mapWallet.end()) {
// We want all transactions regardless of confirmation count to appear here,
// even negative confirmation ones, hence the big negative.
- ListTransactions(wallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */, /*include_change=*/include_change);
+ ListTransactions(wallet, it->second, -100000000, true, removed, filter, filter_label, include_change);
}
}
blockId = block.hashPrevBlock;
@@ -777,7 +781,7 @@ RPCHelpMan gettransaction()
WalletTxToJSON(*pwallet, wtx, entry);
UniValue details(UniValue::VARR);
- ListTransactions(*pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
+ ListTransactions(*pwallet, wtx, 0, false, details, filter, /*filter_label=*/std::nullopt);
entry.pushKV("details", details);
std::string strHex = EncodeHexTx(*wtx.tx, pwallet->chain().rpcSerializationFlags());
@@ -839,10 +843,12 @@ RPCHelpMan rescanblockchain()
{
return RPCHelpMan{"rescanblockchain",
"\nRescan the local blockchain for wallet related transactions.\n"
- "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
+ "The rescan is significantly faster when used on a descriptor wallet\n"
+ "and block filters are available (using startup option \"-blockfilterindex=1\").\n",
{
{"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "block height where the rescan should start"},
- {"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "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."},
+ {"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "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{
RPCResult::Type::OBJ, "", "",
@@ -866,15 +872,18 @@ RPCHelpMan rescanblockchain()
wallet.BlockUntilSyncedToCurrentChain();
WalletRescanReserver reserver(*pwallet);
- if (!reserver.reserve()) {
+ if (!reserver.reserve(/*with_passphrase=*/true)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
}
int start_height = 0;
std::optional<int> stop_height;
uint256 start_block;
+
+ LOCK(pwallet->m_relock_mutex);
{
LOCK(pwallet->cs_wallet);
+ EnsureWalletIsUnlocked(*pwallet);
int tip_height = pwallet->GetLastBlockHeight();
if (!request.params[0].isNull()) {
diff --git a/src/wallet/rpc/util.cpp b/src/wallet/rpc/util.cpp
index 1aa2a87e99..4d82e0a41f 100644
--- a/src/wallet/rpc/util.cpp
+++ b/src/wallet/rpc/util.cpp
@@ -1,12 +1,13 @@
-// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Copyright (c) 2011-2022 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 <wallet/rpc/util.h>
+#include <common/url.h>
#include <rpc/util.h>
+#include <util/system.h>
#include <util/translation.h>
-#include <util/url.h>
#include <wallet/context.h>
#include <wallet/wallet.h>
@@ -75,7 +76,7 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
- const std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
+ std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}
@@ -132,7 +133,10 @@ const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wal
std::string LabelFromValue(const UniValue& value)
{
- std::string label = value.get_str();
+ static const std::string empty_string;
+ if (value.isNull()) return empty_string;
+
+ const std::string& label{value.get_str()};
if (label == "*")
throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
return label;
diff --git a/src/wallet/rpc/util.h b/src/wallet/rpc/util.h
index 87d34f7c11..d5d6ac0dfa 100644
--- a/src/wallet/rpc/util.h
+++ b/src/wallet/rpc/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 675c4a759d..16595267b4 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -201,7 +201,7 @@ static RPCHelpMan loadwallet()
"\napplied to the new wallet.\n",
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
- {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
+ {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -226,6 +226,14 @@ static RPCHelpMan loadwallet()
bilingual_str error;
std::vector<bilingual_str> warnings;
std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
+
+ {
+ LOCK(context.wallets_mutex);
+ if (std::any_of(context.wallets.begin(), context.wallets.end(), [&name](const auto& wallet) { return wallet->GetName() == name; })) {
+ throw JSONRPCError(RPC_WALLET_ALREADY_LOADED, "Wallet \"" + name + "\" is already loaded.");
+ }
+ }
+
std::shared_ptr<CWallet> const wallet = LoadWallet(context, name, load_on_start, options, status, error, warnings);
HandleWalletError(wallet, status, error);
@@ -315,12 +323,12 @@ static RPCHelpMan createwallet()
{"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "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, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
{"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
- {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Encrypt the wallet with this passphrase."},
+ {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
{"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
{"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation."
" Setting to \"false\" will create a legacy wallet; however, the legacy wallet type is being deprecated and"
" support for creating and opening legacy wallets will be removed in the future."},
- {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
+ {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
{"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
},
RPCResult{
@@ -351,7 +359,7 @@ static RPCHelpMan createwallet()
passphrase.reserve(100);
std::vector<bilingual_str> warnings;
if (!request.params[3].isNull()) {
- passphrase = request.params[3].get_str().c_str();
+ passphrase = std::string_view{request.params[3].get_str()};
if (passphrase.empty()) {
// Empty string means unencrypted
warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
@@ -411,7 +419,7 @@ static RPCHelpMan unloadwallet()
"Specifying the wallet name on a wallet endpoint is invalid.",
{
{"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
- {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
+ {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
},
RPCResult{RPCResult::Type::OBJ, "", "", {
{RPCResult::Type::STR, "warning", "Warning message if wallet was not unloaded cleanly."},
@@ -437,13 +445,20 @@ static RPCHelpMan unloadwallet()
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
}
- // Release the "main" shared pointer and prevent further notifications.
- // Note that any attempt to load the same wallet would fail until the wallet
- // is destroyed (see CheckUniqueFileid).
std::vector<bilingual_str> warnings;
- std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
- if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
- throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
+ {
+ WalletRescanReserver reserver(*wallet);
+ if (!reserver.reserve()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
+ }
+
+ // Release the "main" shared pointer and prevent further notifications.
+ // Note that any attempt to load the same wallet would fail until the wallet
+ // is destroyed (see CheckUniqueFileid).
+ std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
+ if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
+ }
}
UnloadWallet(std::move(wallet));
@@ -553,8 +568,6 @@ static RPCHelpMan upgradewallet()
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
- RPCTypeCheck(request.params, {UniValue::VNUM}, true);
-
EnsureWalletIsUnlocked(*pwallet);
int version = 0;
@@ -595,12 +608,12 @@ RPCHelpMan simulaterawtransaction()
return RPCHelpMan{"simulaterawtransaction",
"\nCalculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
{
- {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "An array of hex strings of raw transactions.\n",
+ {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of hex strings of raw transactions.\n",
{
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
},
},
- {"options", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED_NAMED_ARG, "Options",
+ {"options", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "Options",
{
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
},
@@ -622,8 +635,6 @@ RPCHelpMan simulaterawtransaction()
if (!rpc_wallet) return UniValue::VNULL;
const CWallet& wallet = *rpc_wallet;
- RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ}, true);
-
LOCK(wallet.cs_wallet);
UniValue include_watchonly(UniValue::VNULL);
@@ -709,9 +720,12 @@ static RPCHelpMan migratewallet()
"A new wallet backup will need to be made.\n"
"\nThe migration process will create a backup of the wallet before migrating. This backup\n"
"file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"
- "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet." +
- HELP_REQUIRING_PASSPHRASE,
- {},
+ "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet."
+ "\nEncrypted wallets must have the passphrase provided as an argument to this call.",
+ {
+ {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to migrate. If provided both here and in the RPC endpoint, the two must be identical."},
+ {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
+ },
RPCResult{
RPCResult::Type::OBJ, "", "",
{
@@ -727,14 +741,26 @@ static RPCHelpMan migratewallet()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- std::shared_ptr<CWallet> wallet = GetWalletForJSONRPCRequest(request);
- if (!wallet) return NullUniValue;
+ std::string wallet_name;
+ if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
+ if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
+ }
+ } else {
+ if (request.params[0].isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Either RPC endpoint wallet or wallet_name parameter must be provided");
+ }
+ wallet_name = request.params[0].get_str();
+ }
- EnsureWalletIsUnlocked(*wallet);
+ SecureString wallet_pass;
+ wallet_pass.reserve(100);
+ if (!request.params[1].isNull()) {
+ wallet_pass = std::string_view{request.params[1].get_str()};
+ }
WalletContext& context = EnsureWalletContext(request.context);
-
- util::Result<MigrationResult> res = MigrateLegacyToDescriptor(std::move(wallet), context);
+ util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
if (!res) {
throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
}
diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp
index 9ba3c7fd2c..e2b4dbf4c2 100644
--- a/src/wallet/salvage.cpp
+++ b/src/wallet/salvage.cpp
@@ -135,11 +135,11 @@ bool RecoverDatabaseFile(const ArgsManager& args, const fs::path& file_path, bil
}
DbTxn* ptxn = env->TxnBegin();
- CWallet dummyWallet(nullptr, "", gArgs, CreateDummyWalletDatabase());
+ CWallet dummyWallet(nullptr, "", CreateDummyWalletDatabase());
for (KeyValPair& row : salvagedData)
{
/* Filter for only private key type KV pairs to be added to the salvaged wallet */
- CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
+ DataStream ssKey{row.first};
CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
std::string strType, strErr;
bool fReadOK;
diff --git a/src/wallet/salvage.h b/src/wallet/salvage.h
index e4822c3c75..ce918aec2d 100644
--- a/src/wallet/salvage.h
+++ b/src/wallet/salvage.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 41654579c6..1589e52deb 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -1,7 +1,8 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 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 <hash.h>
#include <key_io.h>
#include <logging.h>
#include <outputtype.h>
@@ -10,7 +11,6 @@
#include <util/bip32.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>
#include <wallet/scriptpubkeyman.h>
@@ -28,6 +28,9 @@ util::Result<CTxDestination> LegacyScriptPubKeyMan::GetNewDestination(const Outp
}
assert(type != OutputType::BECH32M);
+ // Fill-up keypool if needed
+ TopUp();
+
LOCK(cs_KeyStore);
// Generate a new key that is added to wallet
@@ -163,9 +166,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s
if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
break;
}
- uint160 hash;
- CRIPEMD160().Write(vSolutions[0].data(), vSolutions[0].size()).Finalize(hash.begin());
- CScriptID scriptID = CScriptID(hash);
+ CScriptID scriptID{RIPEMD160(vSolutions[0])};
CScript subscript;
if (keystore.GetCScript(scriptID, subscript)) {
ret = std::max(ret, recurse_scripthash ? IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0) : IsMineResult::SPENDABLE);
@@ -304,6 +305,9 @@ util::Result<CTxDestination> LegacyScriptPubKeyMan::GetReservedDestination(const
return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
+ // Fill-up keypool if needed
+ TopUp();
+
if (!ReserveKeyFromKeyPool(index, keypool, internal)) {
return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
@@ -586,7 +590,7 @@ bool LegacyScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sig
// or solving information, even if not able to sign fully.
return true;
} else {
- // If, given the stuff in sigdata, we could make a valid sigature, then we can provide for this script
+ // If, given the stuff in sigdata, we could make a valid signature, then we can provide for this script
ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, script, sigdata);
if (!sigdata.signatures.empty()) {
// If we could make signatures, make sure we have a private key to actually make a signature
@@ -1289,7 +1293,7 @@ bool LegacyScriptPubKeyMan::TopUpChain(CHDChain& chain, unsigned int kpSize)
if (kpSize > 0) {
nTargetSize = kpSize;
} else {
- nTargetSize = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{0});
+ nTargetSize = m_keypool_size;
}
int64_t target = std::max((int64_t) nTargetSize, int64_t{1});
@@ -1659,7 +1663,7 @@ std::set<CKeyID> LegacyScriptPubKeyMan::GetKeys() const
return set_address;
}
-const std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetScriptPubKeys() const
+std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetScriptPubKeys() const
{
LOCK(cs_KeyStore);
std::unordered_set<CScript, SaltedSipHasher> spks;
@@ -1779,7 +1783,7 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor()
WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
- auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc));
+ auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc, m_keypool_size));
desc_spk_man->AddDescriptorKey(key, key.GetPubKey());
desc_spk_man->TopUp();
auto desc_spks = desc_spk_man->GetScriptPubKeys();
@@ -1824,7 +1828,7 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor()
WalletDescriptor w_desc(std::move(desc), 0, 0, chain_counter, 0);
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
- auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc));
+ auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc, m_keypool_size));
desc_spk_man->AddDescriptorKey(master_key.key, master_key.key.GetPubKey());
desc_spk_man->TopUp();
auto desc_spks = desc_spk_man->GetScriptPubKeys();
@@ -1886,7 +1890,7 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor()
} else {
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
- auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc));
+ auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc, m_keypool_size));
for (const auto& keyid : privkeyids) {
CKey key;
if (!GetKey(keyid, key)) {
@@ -1983,7 +1987,7 @@ util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const
std::optional<OutputType> desc_addr_type = m_wallet_descriptor.descriptor->GetOutputType();
assert(desc_addr_type);
if (type != *desc_addr_type) {
- throw std::runtime_error(std::string(__func__) + ": Types are inconsistent");
+ throw std::runtime_error(std::string(__func__) + ": Types are inconsistent. Stored type does not match type of newly generated address");
}
TopUp();
@@ -2001,11 +2005,8 @@ util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const
}
CTxDestination dest;
- std::optional<OutputType> out_script_type = m_wallet_descriptor.descriptor->GetOutputType();
- if (out_script_type && out_script_type == type) {
- ExtractDestination(scripts_temp[0], dest);
- } else {
- throw std::runtime_error(std::string(__func__) + ": Types are inconsistent. Stored type does not match type of newly generated address");
+ if (!ExtractDestination(scripts_temp[0], dest)) {
+ return util::Error{_("Error: Cannot extract destination from the generated scriptpubkey")}; // shouldn't happen
}
m_wallet_descriptor.next_index++;
WalletBatch(m_storage.GetDatabase()).WriteDescriptor(GetID(), m_wallet_descriptor);
@@ -2120,7 +2121,7 @@ bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
if (size > 0) {
target_size = size;
} else {
- target_size = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 1);
+ target_size = m_keypool_size;
}
// Calculate the new range_end
@@ -2494,19 +2495,28 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
input.FillSignatureData(sigdata);
std::unique_ptr<FlatSigningProvider> keys = std::make_unique<FlatSigningProvider>();
- std::unique_ptr<FlatSigningProvider> script_keys = GetSigningProvider(script, sign);
+ std::unique_ptr<FlatSigningProvider> script_keys = GetSigningProvider(script, /*include_private=*/sign);
if (script_keys) {
keys->Merge(std::move(*script_keys));
} else {
// Maybe there are pubkeys listed that we can sign for
- script_keys = std::make_unique<FlatSigningProvider>();
- for (const auto& pk_pair : input.hd_keypaths) {
- const CPubKey& pubkey = pk_pair.first;
- std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(pubkey);
- if (pk_keys) {
- keys->Merge(std::move(*pk_keys));
- }
+ std::vector<CPubKey> pubkeys;
+
+ // ECDSA Pubkeys
+ for (const auto& [pk, _] : input.hd_keypaths) {
+ pubkeys.push_back(pk);
+ }
+
+ // Taproot output pubkey
+ std::vector<std::vector<unsigned char>> sols;
+ if (Solver(script, sols) == TxoutType::WITNESS_V1_TAPROOT) {
+ sols[0].insert(sols[0].begin(), 0x02);
+ pubkeys.emplace_back(sols[0]);
+ sols[0][0] = 0x03;
+ pubkeys.emplace_back(sols[0]);
}
+
+ // Taproot pubkeys
for (const auto& pk_pair : input.m_tap_bip32_paths) {
const XOnlyPubKey& pubkey = pk_pair.first;
for (unsigned char prefix : {0x02, 0x03}) {
@@ -2514,15 +2524,19 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
std::copy(pubkey.begin(), pubkey.end(), b + 1);
CPubKey fullpubkey;
fullpubkey.Set(b, b + 33);
- std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(fullpubkey);
- if (pk_keys) {
- keys->Merge(std::move(*pk_keys));
- }
+ pubkeys.push_back(fullpubkey);
+ }
+ }
+
+ for (const auto& pubkey : pubkeys) {
+ std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(pubkey);
+ if (pk_keys) {
+ keys->Merge(std::move(*pk_keys));
}
}
}
- SignPSBTInput(HidingSigningProvider(keys.get(), !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
+ SignPSBTInput(HidingSigningProvider(keys.get(), /*hide_secret=*/!sign, /*hide_origin=*/!bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
bool signed_one = PSBTInputSigned(input);
if (n_signed && (signed_one || !sign)) {
@@ -2539,7 +2553,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
if (!keys) {
continue;
}
- UpdatePSBTOutput(HidingSigningProvider(keys.get(), true, !bip32derivs), psbtx, i);
+ UpdatePSBTOutput(HidingSigningProvider(keys.get(), /*hide_secret=*/true, /*hide_origin=*/!bip32derivs), psbtx, i);
}
return TransactionError::OK;
@@ -2635,23 +2649,33 @@ void DescriptorScriptPubKeyMan::WriteDescriptor()
}
}
-const WalletDescriptor DescriptorScriptPubKeyMan::GetWalletDescriptor() const
+WalletDescriptor DescriptorScriptPubKeyMan::GetWalletDescriptor() const
{
return m_wallet_descriptor;
}
-const std::unordered_set<CScript, SaltedSipHasher> DescriptorScriptPubKeyMan::GetScriptPubKeys() const
+std::unordered_set<CScript, SaltedSipHasher> DescriptorScriptPubKeyMan::GetScriptPubKeys() const
+{
+ return GetScriptPubKeys(0);
+}
+
+std::unordered_set<CScript, SaltedSipHasher> DescriptorScriptPubKeyMan::GetScriptPubKeys(int32_t minimum_index) const
{
LOCK(cs_desc_man);
std::unordered_set<CScript, SaltedSipHasher> script_pub_keys;
script_pub_keys.reserve(m_map_script_pub_keys.size());
- for (auto const& script_pub_key: m_map_script_pub_keys) {
- script_pub_keys.insert(script_pub_key.first);
+ for (auto const& [script_pub_key, index] : m_map_script_pub_keys) {
+ if (index >= minimum_index) script_pub_keys.insert(script_pub_key);
}
return script_pub_keys;
}
+int32_t DescriptorScriptPubKeyMan::GetEndRange() const
+{
+ return m_max_cached_index + 1;
+}
+
bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, const bool priv) const
{
LOCK(cs_desc_man);
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index 3ab489c374..4d14325241 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -36,7 +36,7 @@ class WalletStorage
{
public:
virtual ~WalletStorage() = default;
- virtual const std::string GetDisplayName() const = 0;
+ virtual std::string GetDisplayName() const = 0;
virtual WalletDatabase& GetDatabase() const = 0;
virtual bool IsWalletFlagSet(uint64_t) const = 0;
virtual void UnsetBlankWalletFlag(WalletBatch&) = 0;
@@ -243,7 +243,7 @@ public:
virtual uint256 GetID() const { return uint256(); }
/** Returns a set of all the scriptPubKeys that this ScriptPubKeyMan watches */
- virtual const std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const { return {}; };
+ virtual std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const { return {}; };
/** Prepends the wallet name in logging output to ease debugging in multi-wallet use cases */
template<typename... Params>
@@ -286,6 +286,9 @@ private:
int64_t nTimeFirstKey GUARDED_BY(cs_KeyStore) = 0;
+ //! Number of pre-generated keys/scripts (part of the look-ahead process, used to detect payments)
+ int64_t m_keypool_size GUARDED_BY(cs_KeyStore){DEFAULT_KEYPOOL_SIZE};
+
bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey);
bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
@@ -363,7 +366,7 @@ private:
bool TopUpChain(CHDChain& chain, unsigned int size);
public:
- using ScriptPubKeyMan::ScriptPubKeyMan;
+ LegacyScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size) : ScriptPubKeyMan(storage), m_keypool_size(keypool_size) {}
util::Result<CTxDestination> GetNewDestination(const OutputType type) override;
isminetype IsMine(const CScript& script) const override;
@@ -512,7 +515,7 @@ public:
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
std::set<CKeyID> GetKeys() const override;
- const std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;
+ std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;
/** Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this LegacyScriptPubKeyMan.
* Does not modify this ScriptPubKeyMan. */
@@ -555,6 +558,9 @@ private:
//! keeps track of whether Unlock has run a thorough check before
bool m_decryption_thoroughly_checked = false;
+ //! Number of pre-generated keys/scripts (part of the look-ahead process, used to detect payments)
+ int64_t m_keypool_size GUARDED_BY(cs_desc_man){DEFAULT_KEYPOOL_SIZE};
+
bool AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
KeyMap GetKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
@@ -572,12 +578,14 @@ protected:
WalletDescriptor m_wallet_descriptor GUARDED_BY(cs_desc_man);
public:
- DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor)
+ DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size)
: ScriptPubKeyMan(storage),
+ m_keypool_size(keypool_size),
m_wallet_descriptor(descriptor)
{}
- DescriptorScriptPubKeyMan(WalletStorage& storage)
- : ScriptPubKeyMan(storage)
+ DescriptorScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size)
+ : ScriptPubKeyMan(storage),
+ m_keypool_size(keypool_size)
{}
mutable RecursiveMutex cs_desc_man;
@@ -641,8 +649,10 @@ public:
void AddDescriptorKey(const CKey& key, const CPubKey &pubkey);
void WriteDescriptor();
- const WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
- const std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;
+ WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
+ std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;
+ std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys(int32_t minimum_index) const;
+ int32_t GetEndRange() const;
bool GetDescriptorString(std::string& out, const bool priv) const;
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 36c1a65ea2..409b43670a 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -1,11 +1,14 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 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 <algorithm>
#include <consensus/amount.h>
#include <consensus/validation.h>
#include <interfaces/chain.h>
+#include <numeric>
#include <policy/policy.h>
+#include <primitives/transaction.h>
#include <script/signingprovider.h>
#include <util/check.h>
#include <util/fees.h>
@@ -27,11 +30,11 @@ using interfaces::FoundBlock;
namespace wallet {
static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100};
-int CalculateMaximumSignedInputSize(const CTxOut& txout, const COutPoint outpoint, const SigningProvider* provider, const CCoinControl* coin_control)
+int CalculateMaximumSignedInputSize(const CTxOut& txout, const COutPoint outpoint, const SigningProvider* provider, bool can_grind_r, const CCoinControl* coin_control)
{
CMutableTransaction txn;
txn.vin.push_back(CTxIn(outpoint));
- if (!provider || !DummySignInput(*provider, txn.vin[0], txout, coin_control)) {
+ if (!provider || !DummySignInput(*provider, txn.vin[0], txout, can_grind_r, coin_control)) {
return -1;
}
return GetVirtualTransactionInputSize(txn.vin[0]);
@@ -40,7 +43,7 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const COutPoint outpoin
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, const CCoinControl* coin_control)
{
const std::unique_ptr<SigningProvider> provider = wallet->GetSolvingProvider(txout.scriptPubKey);
- return CalculateMaximumSignedInputSize(txout, COutPoint(), provider.get(), coin_control);
+ return CalculateMaximumSignedInputSize(txout, COutPoint(), provider.get(), wallet->CanGrindR(), coin_control);
}
// txouts needs to be in the order of tx.vin
@@ -102,15 +105,19 @@ void CoinsResult::Clear() {
coins.clear();
}
-void CoinsResult::Erase(std::set<COutPoint>& preset_coins)
+void CoinsResult::Erase(const std::unordered_set<COutPoint, SaltedOutpointHasher>& coins_to_remove)
{
- for (auto& it : coins) {
- auto& vec = it.second;
- auto i = std::find_if(vec.begin(), vec.end(), [&](const COutput &c) { return preset_coins.count(c.outpoint);});
- if (i != vec.end()) {
- vec.erase(i);
- break;
- }
+ for (auto& [type, vec] : coins) {
+ auto remove_it = std::remove_if(vec.begin(), vec.end(), [&](const COutput& coin) {
+ // remove it if it's on the set
+ if (coins_to_remove.count(coin.outpoint) == 0) return false;
+
+ // update cached amounts
+ total_amount -= coin.txout.nValue;
+ if (coin.HasEffectiveValue()) total_effective_amount = *total_effective_amount - coin.GetEffectiveValue();
+ return true;
+ });
+ vec.erase(remove_it, vec.end());
}
}
@@ -124,6 +131,11 @@ void CoinsResult::Shuffle(FastRandomContext& rng_fast)
void CoinsResult::Add(OutputType type, const COutput& out)
{
coins[type].emplace_back(out);
+ total_amount += out.txout.nValue;
+ if (out.HasEffectiveValue()) {
+ total_effective_amount = total_effective_amount.has_value() ?
+ *total_effective_amount + out.GetEffectiveValue() : out.GetEffectiveValue();
+ }
}
static OutputType GetOutputType(TxoutType type, bool is_from_p2sh)
@@ -143,14 +155,56 @@ static OutputType GetOutputType(TxoutType type, bool is_from_p2sh)
}
}
+// Fetch and validate the coin control selected inputs.
+// Coins could be internal (from the wallet) or external.
+util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const CCoinControl& coin_control,
+ const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
+{
+ PreSelectedInputs result;
+ std::vector<COutPoint> vPresetInputs;
+ coin_control.ListSelected(vPresetInputs);
+ const bool can_grind_r = wallet.CanGrindR();
+ for (const COutPoint& outpoint : vPresetInputs) {
+ int input_bytes = -1;
+ CTxOut txout;
+ if (auto ptr_wtx = wallet.GetWalletTx(outpoint.hash)) {
+ // Clearly invalid input, fail
+ if (ptr_wtx->tx->vout.size() <= outpoint.n) {
+ return util::Error{strprintf(_("Invalid pre-selected input %s"), outpoint.ToString())};
+ }
+ txout = ptr_wtx->tx->vout.at(outpoint.n);
+ input_bytes = CalculateMaximumSignedInputSize(txout, &wallet, &coin_control);
+ } else {
+ // The input is external. We did not find the tx in mapWallet.
+ if (!coin_control.GetExternalOutput(outpoint, txout)) {
+ return util::Error{strprintf(_("Not found pre-selected input %s"), outpoint.ToString())};
+ }
+ }
+
+ if (input_bytes == -1) {
+ input_bytes = CalculateMaximumSignedInputSize(txout, outpoint, &coin_control.m_external_provider, can_grind_r, &coin_control);
+ }
+
+ // If available, override calculated size with coin control specified size
+ if (coin_control.HasInputWeight(outpoint)) {
+ input_bytes = GetVirtualTransactionSize(coin_control.GetInputWeight(outpoint), 0, 0);
+ }
+
+ if (input_bytes == -1) {
+ return util::Error{strprintf(_("Not solvable pre-selected input %s"), outpoint.ToString())}; // Not solvable, can't estimate size for fee
+ }
+
+ /* Set some defaults for depth, spendable, solvable, safe, time, and from_me as these don't matter for preset inputs since no selection is being done. */
+ COutput output(outpoint, txout, /*depth=*/ 0, input_bytes, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, coin_selection_params.m_effective_feerate);
+ result.Insert(output, coin_selection_params.m_subtract_fee_outputs);
+ }
+ return result;
+}
+
CoinsResult AvailableCoins(const CWallet& wallet,
const CCoinControl* coinControl,
std::optional<CFeeRate> feerate,
- const CAmount& nMinimumAmount,
- const CAmount& nMaximumAmount,
- const CAmount& nMinimumSumAmount,
- const uint64_t nMaximumCount,
- bool only_spendable)
+ const CoinFilterParams& params)
{
AssertLockHeld(wallet.cs_wallet);
@@ -161,6 +215,7 @@ CoinsResult AvailableCoins(const CWallet& wallet,
const int min_depth = {coinControl ? coinControl->m_min_depth : DEFAULT_MIN_DEPTH};
const int max_depth = {coinControl ? coinControl->m_max_depth : DEFAULT_MAX_DEPTH};
const bool only_safe = {coinControl ? !coinControl->m_include_unsafe_inputs : true};
+ const bool can_grind_r = wallet.CanGrindR();
std::set<uint256> trusted_parents;
for (const auto& entry : wallet.mapWallet)
@@ -168,7 +223,7 @@ CoinsResult AvailableCoins(const CWallet& wallet,
const uint256& wtxid = entry.first;
const CWalletTx& wtx = entry.second;
- if (wallet.IsTxImmatureCoinBase(wtx))
+ if (wallet.IsTxImmatureCoinBase(wtx) && !params.include_immature_coinbase)
continue;
int nDepth = wallet.GetTxDepthInMainChain(wtx);
@@ -227,13 +282,14 @@ CoinsResult AvailableCoins(const CWallet& wallet,
const CTxOut& output = wtx.tx->vout[i];
const COutPoint outpoint(wtxid, i);
- if (output.nValue < nMinimumAmount || output.nValue > nMaximumAmount)
+ if (output.nValue < params.min_amount || output.nValue > params.max_amount)
continue;
- if (coinControl && coinControl->HasSelected() && !coinControl->m_allow_other_inputs && !coinControl->IsSelected(outpoint))
+ // Skip manually selected coins (the caller can fetch them directly)
+ if (coinControl && coinControl->HasSelected() && coinControl->IsSelected(outpoint))
continue;
- if (wallet.IsLockedCoin(outpoint))
+ if (wallet.IsLockedCoin(outpoint) && params.skip_locked)
continue;
if (wallet.IsSpent(outpoint))
@@ -251,14 +307,12 @@ CoinsResult AvailableCoins(const CWallet& wallet,
std::unique_ptr<SigningProvider> provider = wallet.GetSolvingProvider(output.scriptPubKey);
- int input_bytes = CalculateMaximumSignedInputSize(output, COutPoint(), provider.get(), coinControl);
- // Because CalculateMaximumSignedInputSize just uses ProduceSignature and makes a dummy signature,
- // it is safe to assume that this input is solvable if input_bytes is greater -1.
- bool solvable = input_bytes > -1;
+ int input_bytes = CalculateMaximumSignedInputSize(output, COutPoint(), provider.get(), can_grind_r, coinControl);
+ bool solvable = provider ? InferDescriptor(output.scriptPubKey, *provider)->IsSolvable() : false;
bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
// Filter by spendable outputs only
- if (!spendable && only_spendable) continue;
+ if (!spendable && params.only_spendable) continue;
// Obtain script type
std::vector<std::vector<uint8_t>> script_solutions;
@@ -279,17 +333,15 @@ CoinsResult AvailableCoins(const CWallet& wallet,
result.Add(GetOutputType(type, is_from_p2sh),
COutput(outpoint, output, nDepth, input_bytes, spendable, solvable, safeTx, wtx.GetTxTime(), tx_from_me, feerate));
- // Cache total amount as we go
- result.total_amount += output.nValue;
// Checks the sum amount of all UTXO's.
- if (nMinimumSumAmount != MAX_MONEY) {
- if (result.total_amount >= nMinimumSumAmount) {
+ if (params.min_sum_amount != MAX_MONEY) {
+ if (result.GetTotalAmount() >= params.min_sum_amount) {
return result;
}
}
// Checks the maximum number of UTXO's.
- if (nMaximumCount > 0 && result.Size() >= nMaximumCount) {
+ if (params.max_count > 0 && result.Size() >= params.max_count) {
return result;
}
}
@@ -298,109 +350,88 @@ CoinsResult AvailableCoins(const CWallet& wallet,
return result;
}
-CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl, const CAmount& nMinimumAmount, const CAmount& nMaximumAmount, const CAmount& nMinimumSumAmount, const uint64_t nMaximumCount)
+CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl, CoinFilterParams params)
{
- return AvailableCoins(wallet, coinControl, /*feerate=*/ std::nullopt, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, /*only_spendable=*/false);
+ params.only_spendable = false;
+ return AvailableCoins(wallet, coinControl, /*feerate=*/ std::nullopt, params);
}
CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl)
{
LOCK(wallet.cs_wallet);
- return AvailableCoins(wallet, coinControl,
- /*feerate=*/ std::nullopt,
- /*nMinimumAmount=*/ 1,
- /*nMaximumAmount=*/ MAX_MONEY,
- /*nMinimumSumAmount=*/ MAX_MONEY,
- /*nMaximumCount=*/ 0
- ).total_amount;
+ return AvailableCoins(wallet, coinControl).GetTotalAmount();
}
-const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const CTransaction& tx, int output)
+const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint)
{
AssertLockHeld(wallet.cs_wallet);
- const CTransaction* ptx = &tx;
- int n = output;
+ const CWalletTx* wtx{Assert(wallet.GetWalletTx(outpoint.hash))};
+
+ const CTransaction* ptx = wtx->tx.get();
+ int n = outpoint.n;
while (OutputIsChange(wallet, ptx->vout[n]) && ptx->vin.size() > 0) {
const COutPoint& prevout = ptx->vin[0].prevout;
- auto it = wallet.mapWallet.find(prevout.hash);
- if (it == wallet.mapWallet.end() || it->second.tx->vout.size() <= prevout.n ||
- !wallet.IsMine(it->second.tx->vout[prevout.n])) {
+ const CWalletTx* it = wallet.GetWalletTx(prevout.hash);
+ if (!it || it->tx->vout.size() <= prevout.n ||
+ !wallet.IsMine(it->tx->vout[prevout.n])) {
break;
}
- ptx = it->second.tx.get();
+ ptx = it->tx.get();
n = prevout.n;
}
return ptx->vout[n];
}
-const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint)
-{
- AssertLockHeld(wallet.cs_wallet);
- return FindNonChangeParentOutput(wallet, *wallet.GetWalletTx(outpoint.hash)->tx, outpoint.n);
-}
-
std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet)
{
AssertLockHeld(wallet.cs_wallet);
std::map<CTxDestination, std::vector<COutput>> result;
- for (COutput& coin : AvailableCoinsListUnspent(wallet).All()) {
+ CCoinControl coin_control;
+ // Include watch-only for LegacyScriptPubKeyMan wallets without private keys
+ coin_control.fAllowWatchOnly = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
+ CoinFilterParams coins_params;
+ coins_params.only_spendable = false;
+ coins_params.skip_locked = false;
+ for (const COutput& coin : AvailableCoins(wallet, &coin_control, /*feerate=*/std::nullopt, coins_params).All()) {
CTxDestination address;
if ((coin.spendable || (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && coin.solvable)) &&
ExtractDestination(FindNonChangeParentOutput(wallet, coin.outpoint).scriptPubKey, address)) {
- result[address].emplace_back(std::move(coin));
+ result[address].emplace_back(coin);
}
}
-
- std::vector<COutPoint> lockedCoins;
- wallet.ListLockedCoins(lockedCoins);
- // Include watch-only for LegacyScriptPubKeyMan wallets without private keys
- const bool include_watch_only = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
- const isminetype is_mine_filter = include_watch_only ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
- for (const COutPoint& output : lockedCoins) {
- auto it = wallet.mapWallet.find(output.hash);
- if (it != wallet.mapWallet.end()) {
- const auto& wtx = it->second;
- int depth = wallet.GetTxDepthInMainChain(wtx);
- if (depth >= 0 && output.n < wtx.tx->vout.size() &&
- wallet.IsMine(wtx.tx->vout[output.n]) == is_mine_filter
- ) {
- CTxDestination address;
- if (ExtractDestination(FindNonChangeParentOutput(wallet, *wtx.tx, output.n).scriptPubKey, address)) {
- const auto out = wtx.tx->vout.at(output.n);
- result[address].emplace_back(
- COutPoint(wtx.GetHash(), output.n), out, depth, CalculateMaximumSignedInputSize(out, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ false, wtx.GetTxTime(), CachedTxIsFromMe(wallet, wtx, ISMINE_ALL));
- }
- }
- }
- }
-
return result;
}
-std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<COutput>& outputs, const CoinSelectionParams& coin_sel_params, const CoinEligibilityFilter& filter, bool positive_only)
+FilteredOutputGroups GroupOutputs(const CWallet& wallet,
+ const CoinsResult& coins,
+ const CoinSelectionParams& coin_sel_params,
+ const std::vector<SelectionFilter>& filters)
{
- std::vector<OutputGroup> groups_out;
+ FilteredOutputGroups filtered_groups;
if (!coin_sel_params.m_avoid_partial_spends) {
- // Allowing partial spends means no grouping. Each COutput gets its own OutputGroup.
- for (const COutput& output : outputs) {
- // Skip outputs we cannot spend
- if (!output.spendable) continue;
-
- size_t ancestors, descendants;
- wallet.chain().getTransactionAncestry(output.outpoint.hash, ancestors, descendants);
-
- // Make an OutputGroup containing just this output
- OutputGroup group{coin_sel_params};
- group.Insert(output, ancestors, descendants, positive_only);
-
- // Check the OutputGroup's eligibility. Only add the eligible ones.
- if (positive_only && group.GetSelectionAmount() <= 0) continue;
- if (group.m_outputs.size() > 0 && group.EligibleForSpending(filter)) groups_out.push_back(group);
+ // Allowing partial spends means no grouping. Each COutput gets its own OutputGroup
+ for (const auto& [type, outputs] : coins.coins) {
+ for (const COutput& output : outputs) {
+ // Get mempool info
+ size_t ancestors, descendants;
+ wallet.chain().getTransactionAncestry(output.outpoint.hash, ancestors, descendants);
+
+ // Create a new group per output and add it to the all groups vector
+ OutputGroup group(coin_sel_params);
+ group.Insert(std::make_shared<COutput>(output), ancestors, descendants);
+
+ // Each filter maps to a different set of groups
+ for (const auto& sel_filter : filters) {
+ const auto& filter = sel_filter.filter;
+ if (!group.EligibleForSpending(filter)) continue;
+ filtered_groups[filter].Push(group, type, /*insert_positive=*/true, /*insert_mixed=*/true);
+ }
+ }
}
- return groups_out;
+ return filtered_groups;
}
// We want to combine COutputs that have the same scriptPubKey into single OutputGroups
@@ -409,16 +440,11 @@ std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<C
// For each COutput, we check if the scriptPubKey is in the map, and if it is, the COutput is added
// to the last OutputGroup in the vector for the scriptPubKey. When the last OutputGroup has
// OUTPUT_GROUP_MAX_ENTRIES COutputs, a new OutputGroup is added to the end of the vector.
- std::map<CScript, std::vector<OutputGroup>> spk_to_groups_map;
- for (const auto& output : outputs) {
- // Skip outputs we cannot spend
- if (!output.spendable) continue;
-
- size_t ancestors, descendants;
- wallet.chain().getTransactionAncestry(output.outpoint.hash, ancestors, descendants);
- CScript spk = output.txout.scriptPubKey;
-
- std::vector<OutputGroup>& groups = spk_to_groups_map[spk];
+ typedef std::map<std::pair<CScript, OutputType>, std::vector<OutputGroup>> ScriptPubKeyToOutgroup;
+ const auto& insert_output = [&](
+ const std::shared_ptr<COutput>& output, OutputType type, size_t ancestors, size_t descendants,
+ ScriptPubKeyToOutgroup& groups_map) {
+ std::vector<OutputGroup>& groups = groups_map[std::make_pair(output->txout.scriptPubKey,type)];
if (groups.size() == 0) {
// No OutputGroups for this scriptPubKey yet, add one
@@ -437,167 +463,177 @@ std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<C
group = &groups.back();
}
- // Add the output to group
- group->Insert(output, ancestors, descendants, positive_only);
- }
-
- // Now we go through the entire map and pull out the OutputGroups
- for (const auto& spk_and_groups_pair: spk_to_groups_map) {
- const std::vector<OutputGroup>& groups_per_spk= spk_and_groups_pair.second;
+ group->Insert(output, ancestors, descendants);
+ };
- // Go through the vector backwards. This allows for the first item we deal with being the partial group.
- for (auto group_it = groups_per_spk.rbegin(); group_it != groups_per_spk.rend(); group_it++) {
- const OutputGroup& group = *group_it;
+ ScriptPubKeyToOutgroup spk_to_groups_map;
+ ScriptPubKeyToOutgroup spk_to_positive_groups_map;
+ for (const auto& [type, outs] : coins.coins) {
+ for (const COutput& output : outs) {
+ size_t ancestors, descendants;
+ wallet.chain().getTransactionAncestry(output.outpoint.hash, ancestors, descendants);
- // Don't include partial groups if there are full groups too and we don't want partial groups
- if (group_it == groups_per_spk.rbegin() && groups_per_spk.size() > 1 && !filter.m_include_partial_groups) {
- continue;
+ const auto& shared_output = std::make_shared<COutput>(output);
+ // Filter for positive only before adding the output
+ if (output.GetEffectiveValue() > 0) {
+ insert_output(shared_output, type, ancestors, descendants, spk_to_positive_groups_map);
}
- // Check the OutputGroup's eligibility. Only add the eligible ones.
- if (positive_only && group.GetSelectionAmount() <= 0) continue;
- if (group.m_outputs.size() > 0 && group.EligibleForSpending(filter)) groups_out.push_back(group);
+ // 'All' groups
+ insert_output(shared_output, type, ancestors, descendants, spk_to_groups_map);
}
}
- return groups_out;
+ // Now we go through the entire maps and pull out the OutputGroups
+ const auto& push_output_groups = [&](const ScriptPubKeyToOutgroup& groups_map, bool positive_only) {
+ for (const auto& [script, groups] : groups_map) {
+ // Go through the vector backwards. This allows for the first item we deal with being the partial group.
+ for (auto group_it = groups.rbegin(); group_it != groups.rend(); group_it++) {
+ const OutputGroup& group = *group_it;
+
+ // Each filter maps to a different set of groups
+ for (const auto& sel_filter : filters) {
+ const auto& filter = sel_filter.filter;
+ if (!group.EligibleForSpending(filter)) continue;
+
+ // Don't include partial groups if there are full groups too and we don't want partial groups
+ if (group_it == groups.rbegin() && groups.size() > 1 && !filter.m_include_partial_groups) {
+ continue;
+ }
+
+ OutputType type = script.second;
+ // Either insert the group into the positive-only groups or the mixed ones.
+ filtered_groups[filter].Push(group, type, positive_only, /*insert_mixed=*/!positive_only);
+ }
+ }
+ }
+ };
+
+ push_output_groups(spk_to_groups_map, /*positive_only=*/ false);
+ push_output_groups(spk_to_positive_groups_map, /*positive_only=*/ true);
+
+ return filtered_groups;
}
-std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins,
+// Returns true if the result contains an error and the message is not empty
+static bool HasErrorMsg(const util::Result<SelectionResult>& res) { return !util::ErrorString(res).empty(); }
+
+util::Result<SelectionResult> AttemptSelection(const CAmount& nTargetValue, OutputGroupTypeMap& groups,
const CoinSelectionParams& coin_selection_params, bool allow_mixed_output_types)
{
// Run coin selection on each OutputType and compute the Waste Metric
std::vector<SelectionResult> results;
- for (const auto& it : available_coins.coins) {
- if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, it.second, coin_selection_params)}) {
- results.push_back(*result);
- }
+ for (auto& [type, group] : groups.groups_by_type) {
+ auto result{ChooseSelectionResult(nTargetValue, group, coin_selection_params)};
+ // If any specific error message appears here, then something particularly wrong happened.
+ if (HasErrorMsg(result)) return result; // So let's return the specific error.
+ // Append the favorable result.
+ if (result) results.push_back(*result);
}
// If we have at least one solution for funding the transaction without mixing, choose the minimum one according to waste metric
// and return the result
if (results.size() > 0) return *std::min_element(results.begin(), results.end());
// If we can't fund the transaction from any individual OutputType, run coin selection one last time
- // over all available coins, which would allow mixing
- if (allow_mixed_output_types) {
- if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.All(), coin_selection_params)}) {
- return result;
- }
+ // over all available coins, which would allow mixing.
+ // If TypesCount() <= 1, there is nothing to mix.
+ if (allow_mixed_output_types && groups.TypesCount() > 1) {
+ return ChooseSelectionResult(nTargetValue, groups.all_groups, coin_selection_params);
}
// Either mixing is not allowed and we couldn't find a solution from any single OutputType, or mixing was allowed and we still couldn't
// find a solution using all available coins
- return std::nullopt;
+ return util::Error();
};
-std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins, const CoinSelectionParams& coin_selection_params)
+util::Result<SelectionResult> ChooseSelectionResult(const CAmount& nTargetValue, Groups& groups, const CoinSelectionParams& coin_selection_params)
{
// Vector of results. We will choose the best one based on waste.
std::vector<SelectionResult> results;
- std::vector<OutputGroup> positive_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, /*positive_only=*/true);
- if (auto bnb_result{SelectCoinsBnB(positive_groups, nTargetValue, coin_selection_params.m_cost_of_change)}) {
+ if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change)}) {
results.push_back(*bnb_result);
}
// The knapsack solver has some legacy behavior where it will spend dust outputs. We retain this behavior, so don't filter for positive only here.
- std::vector<OutputGroup> all_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, /*positive_only=*/false);
- if (auto knapsack_result{KnapsackSolver(all_groups, nTargetValue, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast)}) {
+ if (auto knapsack_result{KnapsackSolver(groups.mixed_group, nTargetValue, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast)}) {
knapsack_result->ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee);
results.push_back(*knapsack_result);
}
- if (auto srd_result{SelectCoinsSRD(positive_groups, nTargetValue, coin_selection_params.rng_fast)}) {
+ if (auto srd_result{SelectCoinsSRD(groups.positive_group, nTargetValue, coin_selection_params.rng_fast)}) {
srd_result->ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee);
results.push_back(*srd_result);
}
- if (results.size() == 0) {
+ if (results.empty()) {
// No solution found
- return std::nullopt;
+ return util::Error();
+ }
+
+ std::vector<SelectionResult> eligible_results;
+ std::copy_if(results.begin(), results.end(), std::back_inserter(eligible_results), [coin_selection_params](const SelectionResult& result) {
+ const auto initWeight{coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR};
+ return initWeight + result.GetWeight() <= static_cast<int>(MAX_STANDARD_TX_WEIGHT);
+ });
+
+ if (eligible_results.empty()) {
+ return util::Error{_("The inputs size exceeds the maximum weight. "
+ "Please try sending a smaller amount or manually consolidating your wallet's UTXOs")};
}
// Choose the result with the least waste
// If the waste is the same, choose the one which spends more inputs.
- auto& best_result = *std::min_element(results.begin(), results.end());
+ auto& best_result = *std::min_element(eligible_results.begin(), eligible_results.end());
return best_result;
}
-std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params)
+util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const PreSelectedInputs& pre_set_inputs,
+ const CAmount& nTargetValue, const CCoinControl& coin_control,
+ const CoinSelectionParams& coin_selection_params)
{
- CAmount value_to_select = nTargetValue;
-
- OutputGroup preset_inputs(coin_selection_params);
-
- // calculate value from preset inputs and store them
- std::set<COutPoint> preset_coins;
-
- std::vector<COutPoint> vPresetInputs;
- coin_control.ListSelected(vPresetInputs);
- for (const COutPoint& outpoint : vPresetInputs) {
- int input_bytes = -1;
- CTxOut txout;
- auto ptr_wtx = wallet.GetWalletTx(outpoint.hash);
- if (ptr_wtx) {
- // Clearly invalid input, fail
- if (ptr_wtx->tx->vout.size() <= outpoint.n) {
- return std::nullopt;
- }
- txout = ptr_wtx->tx->vout.at(outpoint.n);
- input_bytes = CalculateMaximumSignedInputSize(txout, &wallet, &coin_control);
- } else {
- // The input is external. We did not find the tx in mapWallet.
- if (!coin_control.GetExternalOutput(outpoint, txout)) {
- return std::nullopt;
- }
- }
-
- if (input_bytes == -1) {
- input_bytes = CalculateMaximumSignedInputSize(txout, outpoint, &coin_control.m_external_provider, &coin_control);
- }
+ // Deduct preset inputs amount from the search target
+ CAmount selection_target = nTargetValue - pre_set_inputs.total_amount;
- // If available, override calculated size with coin control specified size
- if (coin_control.HasInputWeight(outpoint)) {
- input_bytes = GetVirtualTransactionSize(coin_control.GetInputWeight(outpoint), 0, 0);
- }
-
- if (input_bytes == -1) {
- return std::nullopt; // Not solvable, can't estimate size for fee
- }
-
- /* Set some defaults for depth, spendable, solvable, safe, time, and from_me as these don't matter for preset inputs since no selection is being done. */
- COutput output(outpoint, txout, /*depth=*/ 0, input_bytes, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, coin_selection_params.m_effective_feerate);
- if (coin_selection_params.m_subtract_fee_outputs) {
- value_to_select -= output.txout.nValue;
- } else {
- value_to_select -= output.GetEffectiveValue();
- }
- preset_coins.insert(outpoint);
- /* Set ancestors and descendants to 0 as they don't matter for preset inputs since no actual selection is being done.
- * positive_only is set to false because we want to include all preset inputs, even if they are dust.
- */
- preset_inputs.Insert(output, /*ancestors=*/ 0, /*descendants=*/ 0, /*positive_only=*/ false);
+ // Return if automatic coin selection is disabled, and we don't cover the selection target
+ if (!coin_control.m_allow_other_inputs && selection_target > 0) {
+ return util::Error{_("The preselected coins total amount does not cover the transaction target. "
+ "Please allow other inputs to be automatically selected or include more coins manually")};
}
- // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
- if (coin_control.HasSelected() && !coin_control.m_allow_other_inputs) {
+ // Return if we can cover the target only with the preset inputs
+ if (selection_target <= 0) {
SelectionResult result(nTargetValue, SelectionAlgorithm::MANUAL);
- result.AddInput(preset_inputs);
-
- if (!coin_selection_params.m_subtract_fee_outputs && result.GetSelectedEffectiveValue() < nTargetValue) {
- return std::nullopt;
- } else if (result.GetSelectedValue() < nTargetValue) {
- return std::nullopt;
- }
-
+ result.AddInputs(pre_set_inputs.coins, coin_selection_params.m_subtract_fee_outputs);
result.ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee);
return result;
}
- // remove preset inputs from coins so that Coin Selection doesn't pick them.
- if (coin_control.HasSelected()) {
- available_coins.Erase(preset_coins);
+ // Return early if we cannot cover the target with the wallet's UTXO.
+ // We use the total effective value if we are not subtracting fee from outputs and 'available_coins' contains the data.
+ CAmount available_coins_total_amount = coin_selection_params.m_subtract_fee_outputs ? available_coins.GetTotalAmount() :
+ (available_coins.GetEffectiveTotalAmount().has_value() ? *available_coins.GetEffectiveTotalAmount() : 0);
+ if (selection_target > available_coins_total_amount) {
+ return util::Error(); // Insufficient funds
+ }
+
+ // Start wallet Coin Selection procedure
+ auto op_selection_result = AutomaticCoinSelection(wallet, available_coins, selection_target, coin_selection_params);
+ if (!op_selection_result) return op_selection_result;
+
+ // If needed, add preset inputs to the automatic coin selection result
+ if (!pre_set_inputs.coins.empty()) {
+ SelectionResult preselected(pre_set_inputs.total_amount, SelectionAlgorithm::MANUAL);
+ preselected.AddInputs(pre_set_inputs.coins, coin_selection_params.m_subtract_fee_outputs);
+ op_selection_result->Merge(preselected);
+ op_selection_result->ComputeAndSetWaste(coin_selection_params.min_viable_change,
+ coin_selection_params.m_cost_of_change,
+ coin_selection_params.m_change_fee);
}
+ return op_selection_result;
+}
+util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& value_to_select, const CoinSelectionParams& coin_selection_params)
+{
unsigned int limit_ancestor_count = 0;
unsigned int limit_descendant_count = 0;
wallet.chain().getPackageLimits(limit_ancestor_count, limit_descendant_count);
@@ -605,82 +641,73 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a
const size_t max_descendants = (size_t)std::max<int64_t>(1, limit_descendant_count);
const bool fRejectLongChains = gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
- // form groups from remaining coins; note that preset coins will not
- // automatically have their associated (same address) coins included
- if (coin_control.m_avoid_partial_spends && available_coins.Size() > OUTPUT_GROUP_MAX_ENTRIES) {
- // Cases where we have 101+ outputs all pointing to the same destination may result in
- // privacy leaks as they will potentially be deterministically sorted. We solve that by
- // explicitly shuffling the outputs before processing
+ // Cases where we have 101+ outputs all pointing to the same destination may result in
+ // privacy leaks as they will potentially be deterministically sorted. We solve that by
+ // explicitly shuffling the outputs before processing
+ if (coin_selection_params.m_avoid_partial_spends && available_coins.Size() > OUTPUT_GROUP_MAX_ENTRIES) {
available_coins.Shuffle(coin_selection_params.rng_fast);
}
- SelectionResult preselected(preset_inputs.GetSelectionAmount(), SelectionAlgorithm::MANUAL);
- preselected.AddInput(preset_inputs);
-
// Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the
// transaction at a target feerate. If an attempt fails, more attempts may be made using a more
// permissive CoinEligibilityFilter.
- std::optional<SelectionResult> res = [&] {
- // Pre-selected inputs already cover the target amount.
- if (value_to_select <= 0) return std::make_optional(SelectionResult(value_to_select, SelectionAlgorithm::MANUAL));
-
- // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
- // confirmations on outputs received from other wallets and only spend confirmed change.
- if (auto r1{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 6, 0), available_coins, coin_selection_params, /*allow_mixed_output_types=*/false)}) return r1;
- // Allow mixing only if no solution from any single output type can be found
- if (auto r2{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 1, 0), available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) return r2;
-
+ util::Result<SelectionResult> res = [&] {
+ // Place coins eligibility filters on a scope increasing order.
+ std::vector<SelectionFilter> ordered_filters{
+ // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
+ // confirmations on outputs received from other wallets and only spend confirmed change.
+ {CoinEligibilityFilter(1, 6, 0), /*allow_mixed_output_types=*/false},
+ {CoinEligibilityFilter(1, 1, 0)},
+ };
// Fall back to using zero confirmation change (but with as few ancestors in the mempool as
// possible) if we cannot fund the transaction otherwise.
if (wallet.m_spend_zero_conf_change) {
- if (auto r3{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, 2), available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) return r3;
- if (auto r4{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)),
- available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
- return r4;
- }
- if (auto r5{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2),
- available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
- return r5;
- }
+ ordered_filters.push_back({CoinEligibilityFilter(0, 1, 2)});
+ ordered_filters.push_back({CoinEligibilityFilter(0, 1, std::min(size_t{4}, max_ancestors/3), std::min(size_t{4}, max_descendants/3))});
+ ordered_filters.push_back({CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2)});
// If partial groups are allowed, relax the requirement of spending OutputGroups (groups
// of UTXOs sent to the same address, which are obviously controlled by a single wallet)
// in their entirety.
- if (auto r6{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
- available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
- return r6;
- }
+ ordered_filters.push_back({CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, /*include_partial=*/true)});
// Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
// received from other wallets.
- if (coin_control.m_include_unsafe_inputs) {
- if (auto r7{AttemptSelection(wallet, value_to_select,
- CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
- available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
- return r7;
- }
+ if (coin_selection_params.m_include_unsafe_inputs) {
+ ordered_filters.push_back({CoinEligibilityFilter(/*conf_mine=*/0, /*conf_theirs*/0, max_ancestors-1, max_descendants-1, /*include_partial=*/true)});
}
// Try with unlimited ancestors/descendants. The transaction will still need to meet
// mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but
// OutputGroups use heuristics that may overestimate ancestor/descendant counts.
if (!fRejectLongChains) {
- if (auto r8{AttemptSelection(wallet, value_to_select,
- CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(), true /* include_partial_groups */),
- available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
- return r8;
- }
+ ordered_filters.push_back({CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(),
+ std::numeric_limits<uint64_t>::max(),
+ /*include_partial=*/true)});
+ }
+ }
+
+ // Group outputs and map them by coin eligibility filter
+ FilteredOutputGroups filtered_groups = GroupOutputs(wallet, available_coins, coin_selection_params, ordered_filters);
+
+ // Walk-through the filters until the solution gets found.
+ // If no solution is found, return the first detailed error (if any).
+ // future: add "error level" so the worst one can be picked instead.
+ std::vector<util::Result<SelectionResult>> res_detailed_errors;
+ for (const auto& select_filter : ordered_filters) {
+ auto it = filtered_groups.find(select_filter.filter);
+ if (it == filtered_groups.end()) continue;
+ if (auto res{AttemptSelection(value_to_select, it->second,
+ coin_selection_params, select_filter.allow_mixed_output_types)}) {
+ return res; // result found
+ } else {
+ // If any specific error message appears here, then something particularly wrong might have happened.
+ // Save the error and continue the selection process. So if no solutions gets found, we can return
+ // the detailed error to the upper layers.
+ if (HasErrorMsg(res)) res_detailed_errors.emplace_back(res);
}
}
// Coin Selection failed.
- return std::optional<SelectionResult>();
+ return res_detailed_errors.empty() ? util::Result<SelectionResult>(util::Error()) : res_detailed_errors.front();
}();
- if (!res) return std::nullopt;
-
- // Add preset inputs to result
- res->Merge(preselected);
- if (res->GetAlgo() == SelectionAlgorithm::MANUAL) {
- res->ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee);
- }
-
return res;
}
@@ -768,7 +795,6 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
AssertLockHeld(wallet.cs_wallet);
// out variables, to be packed into returned result structure
- CAmount nFeeRet;
int nChangePosInOut = change_pos;
FastRandomContext rng_fast;
@@ -776,6 +802,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
CoinSelectionParams coin_selection_params{rng_fast}; // Parameters for coin selection, init with dummy
coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends;
+ coin_selection_params.m_include_unsafe_inputs = coin_control.m_include_unsafe_inputs;
// Set the long term feerate estimate to the wallet's consolidate feerate
coin_selection_params.m_long_term_feerate = wallet.m_consolidate_feerate;
@@ -827,7 +854,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout);
// Get size of spending the change output
- int change_spend_size = CalculateMaximumSignedInputSize(change_prototype_txout, &wallet);
+ int change_spend_size = CalculateMaximumSignedInputSize(change_prototype_txout, &wallet, /*coin_control=*/nullptr);
// If the wallet doesn't know how to sign change output, assume p2sh-p2wpkh
// as lower-bound to allow BnB to do it's thing
if (change_spend_size == -1) {
@@ -869,19 +896,16 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
const auto change_spend_fee = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size);
coin_selection_params.min_viable_change = std::max(change_spend_fee + 1, dust);
+ // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 witness overhead (dummy, flag, stack size)
+ coin_selection_params.tx_noinputs_size = 10 + GetSizeOfCompactSize(vecSend.size()); // bytes for output count
+
// vouts to the payees
- if (!coin_selection_params.m_subtract_fee_outputs) {
- coin_selection_params.tx_noinputs_size = 10; // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 witness overhead (dummy, flag, stack size)
- coin_selection_params.tx_noinputs_size += GetSizeOfCompactSize(vecSend.size()); // bytes for output count
- }
for (const auto& recipient : vecSend)
{
CTxOut txout(recipient.nAmount, recipient.scriptPubKey);
// Include the fee cost for outputs.
- if (!coin_selection_params.m_subtract_fee_outputs) {
- coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION);
- }
+ coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION);
if (IsDust(txout, wallet.chain().relayDustFee())) {
return util::Error{_("Transaction amount too small")};
@@ -890,26 +914,35 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
}
// Include the fees for things that aren't inputs, excluding the change output
- const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.tx_noinputs_size);
+ const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.m_subtract_fee_outputs ? 0 : coin_selection_params.tx_noinputs_size);
CAmount selection_target = recipients_sum + not_input_fees;
- // Get available coins
- auto available_coins = AvailableCoins(wallet,
- &coin_control,
- coin_selection_params.m_effective_feerate,
- 1, /*nMinimumAmount*/
- MAX_MONEY, /*nMaximumAmount*/
- MAX_MONEY, /*nMinimumSumAmount*/
- 0); /*nMaximumCount*/
+ // Fetch manually selected coins
+ PreSelectedInputs preset_inputs;
+ if (coin_control.HasSelected()) {
+ auto res_fetch_inputs = FetchSelectedInputs(wallet, coin_control, coin_selection_params);
+ if (!res_fetch_inputs) return util::Error{util::ErrorString(res_fetch_inputs)};
+ preset_inputs = *res_fetch_inputs;
+ }
+
+ // Fetch wallet available coins if "other inputs" are
+ // allowed (coins automatically selected by the wallet)
+ CoinsResult available_coins;
+ if (coin_control.m_allow_other_inputs) {
+ available_coins = AvailableCoins(wallet, &coin_control, coin_selection_params.m_effective_feerate);
+ }
// Choose coins to use
- std::optional<SelectionResult> result = SelectCoins(wallet, available_coins, /*nTargetValue=*/selection_target, coin_control, coin_selection_params);
- if (!result) {
- return util::Error{_("Insufficient funds")};
+ auto select_coins_res = SelectCoins(wallet, available_coins, preset_inputs, /*nTargetValue=*/selection_target, coin_control, coin_selection_params);
+ if (!select_coins_res) {
+ // 'SelectCoins' either returns a specific error message or, if empty, means a general "Insufficient funds".
+ const bilingual_str& err = util::ErrorString(select_coins_res);
+ return util::Error{err.empty() ?_("Insufficient funds") : err};
}
- TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result->GetAlgo()).c_str(), result->GetTarget(), result->GetWaste(), result->GetSelectedValue());
+ const SelectionResult& result = *select_coins_res;
+ TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result.GetAlgo()).c_str(), result.GetTarget(), result.GetWaste(), result.GetSelectedValue());
- const CAmount change_amount = result->GetChange(coin_selection_params.min_viable_change, coin_selection_params.m_change_fee);
+ const CAmount change_amount = result.GetChange(coin_selection_params.min_viable_change, coin_selection_params.m_change_fee);
if (change_amount > 0) {
CTxOut newTxOut(change_amount, scriptChange);
if (nChangePosInOut == -1) {
@@ -924,7 +957,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
}
// Shuffle selected coins and fill in final vin
- std::vector<COutput> selected_coins = result->GetShuffledInputVector();
+ std::vector<std::shared_ptr<COutput>> selected_coins = result.GetShuffledInputVector();
// The sequence number is set to non-maxint so that DiscourageFeeSniping
// works.
@@ -936,7 +969,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
// behavior."
const uint32_t nSequence{coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : CTxIn::MAX_SEQUENCE_NONFINAL};
for (const auto& coin : selected_coins) {
- txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence));
+ txNew.vin.push_back(CTxIn(coin->outpoint, CScript(), nSequence));
}
DiscourageFeeSniping(txNew, rng_fast, wallet.chain(), wallet.GetLastBlockHash(), wallet.GetLastBlockHeight());
@@ -947,22 +980,28 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
return util::Error{_("Missing solving data for estimating transaction size")};
}
CAmount fee_needed = coin_selection_params.m_effective_feerate.GetFee(nBytes);
- nFeeRet = result->GetSelectedValue() - recipients_sum - change_amount;
+ const CAmount output_value = CalculateOutputValue(txNew);
+ Assume(recipients_sum + change_amount == output_value);
+ CAmount current_fee = result.GetSelectedValue() - output_value;
- // The only time that fee_needed should be less than the amount available for fees is when
- // we are subtracting the fee from the outputs. If this occurs at any other time, it is a bug.
- assert(coin_selection_params.m_subtract_fee_outputs || fee_needed <= nFeeRet);
+ // Sanity check that the fee cannot be negative as that means we have more output value than input value
+ if (current_fee < 0) {
+ return util::Error{Untranslated(STR_INTERNAL_BUG("Fee paid < 0"))};
+ }
// If there is a change output and we overpay the fees then increase the change to match the fee needed
- if (nChangePosInOut != -1 && fee_needed < nFeeRet) {
+ if (nChangePosInOut != -1 && fee_needed < current_fee) {
auto& change = txNew.vout.at(nChangePosInOut);
- change.nValue += nFeeRet - fee_needed;
- nFeeRet = fee_needed;
+ change.nValue += current_fee - fee_needed;
+ current_fee = result.GetSelectedValue() - CalculateOutputValue(txNew);
+ if (fee_needed != current_fee) {
+ return util::Error{Untranslated(STR_INTERNAL_BUG("Change adjustment: Fee needed != fee paid"))};
+ }
}
// Reduce output values for subtractFeeFromAmount
if (coin_selection_params.m_subtract_fee_outputs) {
- CAmount to_reduce = fee_needed - nFeeRet;
+ CAmount to_reduce = fee_needed - current_fee;
int i = 0;
bool fFirst = true;
for (const auto& recipient : vecSend)
@@ -993,7 +1032,16 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
}
++i;
}
- nFeeRet = fee_needed;
+ current_fee = result.GetSelectedValue() - CalculateOutputValue(txNew);
+ if (fee_needed != current_fee) {
+ return util::Error{Untranslated(STR_INTERNAL_BUG("SFFO: Fee needed != fee paid"))};
+ }
+ }
+
+ // fee_needed should now always be less than or equal to the current fees that we pay.
+ // If it is not, it is a bug.
+ if (fee_needed > current_fee) {
+ return util::Error{Untranslated(STR_INTERNAL_BUG("Fee needed > fee paid"))};
}
// Give up if change keypool ran out and change is required
@@ -1015,7 +1063,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
return util::Error{_("Transaction too large")};
}
- if (nFeeRet > wallet.m_default_max_tx_fee) {
+ if (current_fee > wallet.m_default_max_tx_fee) {
return util::Error{TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED)};
}
@@ -1031,14 +1079,14 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
reservedest.KeepDestination();
wallet.WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
- nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
+ current_fee, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
feeCalc.est.pass.start, feeCalc.est.pass.end,
(feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) > 0.0 ? 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) : 0.0,
feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool,
feeCalc.est.fail.start, feeCalc.est.fail.end,
(feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) > 0.0 ? 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) : 0.0,
feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool);
- return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut, feeCalc);
+ return CreatedTransactionResult(tx, current_fee, nChangePosInOut, feeCalc);
}
util::Result<CreatedTransactionResult> CreateTransaction(
@@ -1068,6 +1116,13 @@ util::Result<CreatedTransactionResult> CreateTransaction(
TRACE1(coin_selection, attempting_aps_create_tx, wallet.GetName().c_str());
CCoinControl tmp_cc = coin_control;
tmp_cc.m_avoid_partial_spends = true;
+
+ // Re-use the change destination from the first creation attempt to avoid skipping BIP44 indexes
+ const int ungrouped_change_pos = txr_ungrouped.change_pos;
+ if (ungrouped_change_pos != -1) {
+ ExtractDestination(txr_ungrouped.tx->vout[ungrouped_change_pos].scriptPubKey, tmp_cc.destChange);
+ }
+
auto txr_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
// if fee of this alternative one is within the range of the max fee, we use this one
const bool use_aps{txr_grouped.has_value() ? (txr_grouped->fee <= txr_ungrouped.fee + wallet.m_max_aps_fee) : false};
diff --git a/src/wallet/spend.h b/src/wallet/spend.h
index c29e5be5c7..78c2c5f22b 100644
--- a/src/wallet/spend.h
+++ b/src/wallet/spend.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,8 +17,8 @@
namespace wallet {
/** Get the marginal bytes if spending the specified output from this transaction.
* Use CoinControl to determine whether to expect signature grinding when calculating the size of the input spend. */
-int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet, const CCoinControl* coin_control = nullptr);
-int CalculateMaximumSignedInputSize(const CTxOut& txout, const COutPoint outpoint, const SigningProvider* pwallet, const CCoinControl* coin_control = nullptr);
+int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet, const CCoinControl* coin_control);
+int CalculateMaximumSignedInputSize(const CTxOut& txout, const COutPoint outpoint, const SigningProvider* pwallet, bool can_grind_r, const CCoinControl* coin_control);
struct TxSize {
int64_t vsize{-1};
int64_t weight{-1};
@@ -46,13 +46,38 @@ struct CoinsResult {
/** The following methods are provided so that CoinsResult can mimic a vector,
* i.e., methods can work with individual OutputType vectors or on the entire object */
size_t Size() const;
+ /** Return how many different output types this struct stores */
+ size_t TypesCount() const { return coins.size(); }
void Clear();
- void Erase(std::set<COutPoint>& preset_coins);
+ void Erase(const std::unordered_set<COutPoint, SaltedOutpointHasher>& coins_to_remove);
void Shuffle(FastRandomContext& rng_fast);
void Add(OutputType type, const COutput& out);
- /** Sum of all available coins */
+ CAmount GetTotalAmount() { return total_amount; }
+ std::optional<CAmount> GetEffectiveTotalAmount() {return total_effective_amount; }
+
+private:
+ /** Sum of all available coins raw value */
CAmount total_amount{0};
+ /** Sum of all available coins effective value (each output value minus fees required to spend it) */
+ std::optional<CAmount> total_effective_amount{0};
+};
+
+struct CoinFilterParams {
+ // Outputs below the minimum amount will not get selected
+ CAmount min_amount{1};
+ // Outputs above the maximum amount will not get selected
+ CAmount max_amount{MAX_MONEY};
+ // Return outputs until the minimum sum amount is covered
+ CAmount min_sum_amount{MAX_MONEY};
+ // Maximum number of outputs that can be returned
+ uint64_t max_count{0};
+ // By default, return only spendable outputs
+ bool only_spendable{true};
+ // By default, do not include immature coinbase outputs
+ bool include_immature_coinbase{false};
+ // By default, skip locked UTXOs
+ bool skip_locked{true};
};
/**
@@ -61,24 +86,19 @@ struct CoinsResult {
CoinsResult AvailableCoins(const CWallet& wallet,
const CCoinControl* coinControl = nullptr,
std::optional<CFeeRate> feerate = std::nullopt,
- const CAmount& nMinimumAmount = 1,
- const CAmount& nMaximumAmount = MAX_MONEY,
- const CAmount& nMinimumSumAmount = MAX_MONEY,
- const uint64_t nMaximumCount = 0,
- bool only_spendable = true) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
+ const CoinFilterParams& params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
/**
- * Wrapper function for AvailableCoins which skips the `feerate` parameter. Use this function
+ * Wrapper function for AvailableCoins which skips the `feerate` and `CoinFilterParams::only_spendable` parameters. Use this function
* to list all available coins (e.g. listunspent RPC) while not intending to fund a transaction.
*/
-CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
+CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl = nullptr, CoinFilterParams params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl = nullptr);
/**
* Find non-change parent output.
*/
-const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const CTransaction& tx, int output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
/**
@@ -86,23 +106,35 @@ const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint&
*/
std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
-std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<COutput>& outputs, const CoinSelectionParams& coin_sel_params, const CoinEligibilityFilter& filter, bool positive_only);
+struct SelectionFilter {
+ CoinEligibilityFilter filter;
+ bool allow_mixed_output_types{true};
+};
+
+/**
+* Group coins by the provided filters.
+*/
+FilteredOutputGroups GroupOutputs(const CWallet& wallet,
+ const CoinsResult& coins,
+ const CoinSelectionParams& coin_sel_params,
+ const std::vector<SelectionFilter>& filters);
+
/**
* Attempt to find a valid input set that preserves privacy by not mixing OutputTypes.
* `ChooseSelectionResult()` will be called on each OutputType individually and the best
* the solution (according to the waste metric) will be chosen. If a valid input cannot be found from any
* single OutputType, fallback to running `ChooseSelectionResult()` over all available coins.
*
- * param@[in] wallet The wallet which provides solving data for the coins
* param@[in] nTargetValue The target value
- * param@[in] eligilibity_filter A filter containing rules for which coins are allowed to be included in this selection
- * param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
+ * param@[in] groups The grouped outputs mapped by coin eligibility filters
* param@[in] coin_selection_params Parameters for the coin selection
* param@[in] allow_mixed_output_types Relax restriction that SelectionResults must be of the same OutputType
* returns If successful, a SelectionResult containing the input set
- * If failed, a nullopt
+ * If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds")
+ * or (2) an specific error message if there was something particularly wrong (e.g. a selection
+ * result that surpassed the tx max weight size).
*/
-std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins,
+util::Result<SelectionResult> AttemptSelection(const CAmount& nTargetValue, OutputGroupTypeMap& groups,
const CoinSelectionParams& coin_selection_params, bool allow_mixed_output_types);
/**
@@ -110,31 +142,66 @@ std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAm
* Multiple coin selection algorithms will be run and the input set that produces the least waste
* (according to the waste metric) will be chosen.
*
- * param@[in] wallet The wallet which provides solving data for the coins
* param@[in] nTargetValue The target value
- * param@[in] eligilibity_filter A filter containing rules for which coins are allowed to be included in this selection
- * param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
+ * param@[in] groups The struct containing the outputs grouped by script and divided by (1) positive only outputs and (2) all outputs (positive + negative).
* param@[in] coin_selection_params Parameters for the coin selection
* returns If successful, a SelectionResult containing the input set
- * If failed, a nullopt
+ * If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds")
+ * or (2) an specific error message if there was something particularly wrong (e.g. a selection
+ * result that surpassed the tx max weight size).
*/
-std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins,
- const CoinSelectionParams& coin_selection_params);
+util::Result<SelectionResult> ChooseSelectionResult(const CAmount& nTargetValue, Groups& groups, const CoinSelectionParams& coin_selection_params);
+
+// User manually selected inputs that must be part of the transaction
+struct PreSelectedInputs
+{
+ std::set<std::shared_ptr<COutput>> coins;
+ // If subtract fee from outputs is disabled, the 'total_amount'
+ // will be the sum of each output effective value
+ // instead of the sum of the outputs amount
+ CAmount total_amount{0};
+
+ void Insert(const COutput& output, bool subtract_fee_outputs)
+ {
+ if (subtract_fee_outputs) {
+ total_amount += output.txout.nValue;
+ } else {
+ total_amount += output.GetEffectiveValue();
+ }
+ coins.insert(std::make_shared<COutput>(output));
+ }
+};
+
+/**
+ * Fetch and validate coin control selected inputs.
+ * Coins could be internal (from the wallet) or external.
+*/
+util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const CCoinControl& coin_control,
+ const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
/**
- * Select a set of coins such that nTargetValue is met and at least
- * all coins from coin_control are selected; never select unconfirmed coins if they are not ours
+ * Select a set of coins such that nTargetValue is met; never select unconfirmed coins if they are not ours
* param@[in] wallet The wallet which provides data necessary to spend the selected coins
* param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
* param@[in] nTargetValue The target value
* param@[in] coin_selection_params Parameters for this coin selection such as feerates, whether to avoid partial spends,
* and whether to subtract the fee from the outputs.
* returns If successful, a SelectionResult containing the selected coins
- * If failed, a nullopt.
+ * If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds")
+ * or (2) an specific error message if there was something particularly wrong (e.g. a selection
+ * result that surpassed the tx max weight size).
*/
-std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control,
+util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue,
const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
+/**
+ * Select all coins from coin_control, and if coin_control 'm_allow_other_inputs=true', call 'AutomaticCoinSelection' to
+ * select a set of coins such that nTargetValue - pre_set_inputs.total_amount is met.
+ */
+util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const PreSelectedInputs& pre_set_inputs,
+ const CAmount& nTargetValue, const CCoinControl& coin_control,
+ const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
+
struct CreatedTransactionResult
{
CTransactionRef tx;
diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp
index 053fb8f983..8d8a7ab2a2 100644
--- a/src/wallet/sqlite.cpp
+++ b/src/wallet/sqlite.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Copyright (c) 2020-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -23,9 +23,6 @@
namespace wallet {
static constexpr int32_t WALLET_SCHEMA_VERSION = 0;
-static GlobalMutex g_sqlite_mutex;
-static int g_sqlite_count GUARDED_BY(g_sqlite_mutex) = 0;
-
static void ErrorLogCallback(void* arg, int code, const char* msg)
{
// From sqlite3_config() documentation for the SQLITE_CONFIG_LOG option:
@@ -83,6 +80,9 @@ static void SetPragma(sqlite3* db, const std::string& key, const std::string& va
}
}
+Mutex SQLiteDatabase::g_sqlite_mutex;
+int SQLiteDatabase::g_sqlite_count = 0;
+
SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options, bool mock)
: WalletDatabase(), m_mock(mock), m_dir_path(fs::PathToString(dir_path)), m_file_path(fs::PathToString(file_path)), m_use_unsafe_sync(options.use_unsafe_sync)
{
@@ -125,7 +125,6 @@ void SQLiteBatch::SetupSQLStatements()
{&m_insert_stmt, "INSERT INTO main VALUES(?, ?)"},
{&m_overwrite_stmt, "INSERT or REPLACE into main values(?, ?)"},
{&m_delete_stmt, "DELETE FROM main WHERE key = ?"},
- {&m_cursor_stmt, "SELECT key, value FROM main"},
};
for (const auto& [stmt_prepared, stmt_text] : statements) {
@@ -146,6 +145,8 @@ SQLiteDatabase::~SQLiteDatabase()
void SQLiteDatabase::Cleanup() noexcept
{
+ AssertLockNotHeld(g_sqlite_mutex);
+
Close();
LOCK(g_sqlite_mutex);
@@ -374,7 +375,6 @@ void SQLiteBatch::Close()
{&m_insert_stmt, "insert"},
{&m_overwrite_stmt, "overwrite"},
{&m_delete_stmt, "delete"},
- {&m_cursor_stmt, "cursor"},
};
for (const auto& [stmt_prepared, stmt_description] : statements) {
@@ -387,7 +387,7 @@ void SQLiteBatch::Close()
}
}
-bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value)
+bool SQLiteBatch::ReadKey(DataStream&& key, DataStream& value)
{
if (!m_database.m_db) return false;
assert(m_read_stmt);
@@ -414,7 +414,7 @@ bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value)
return true;
}
-bool SQLiteBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite)
+bool SQLiteBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite)
{
if (!m_database.m_db) return false;
assert(m_insert_stmt && m_overwrite_stmt);
@@ -441,7 +441,7 @@ bool SQLiteBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwrit
return res == SQLITE_DONE;
}
-bool SQLiteBatch::EraseKey(CDataStream&& key)
+bool SQLiteBatch::EraseKey(DataStream&& key)
{
if (!m_database.m_db) return false;
assert(m_delete_stmt);
@@ -459,7 +459,7 @@ bool SQLiteBatch::EraseKey(CDataStream&& key)
return res == SQLITE_DONE;
}
-bool SQLiteBatch::HasKey(CDataStream&& key)
+bool SQLiteBatch::HasKey(DataStream&& key)
{
if (!m_database.m_db) return false;
assert(m_read_stmt);
@@ -472,28 +472,15 @@ bool SQLiteBatch::HasKey(CDataStream&& key)
return res == SQLITE_ROW;
}
-bool SQLiteBatch::StartCursor()
+DatabaseCursor::Status SQLiteCursor::Next(DataStream& key, DataStream& value)
{
- assert(!m_cursor_init);
- if (!m_database.m_db) return false;
- m_cursor_init = true;
- return true;
-}
-
-bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& complete)
-{
- complete = false;
-
- if (!m_cursor_init) return false;
-
int res = sqlite3_step(m_cursor_stmt);
if (res == SQLITE_DONE) {
- complete = true;
- return true;
+ return Status::DONE;
}
if (res != SQLITE_ROW) {
- LogPrintf("SQLiteBatch::ReadAtCursor: Unable to execute cursor step: %s\n", sqlite3_errstr(res));
- return false;
+ LogPrintf("%s: Unable to execute cursor step: %s\n", __func__, sqlite3_errstr(res));
+ return Status::FAIL;
}
// Leftmost column in result is index 0
@@ -503,13 +490,32 @@ bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& compl
const std::byte* value_data{AsBytePtr(sqlite3_column_blob(m_cursor_stmt, 1))};
size_t value_data_size(sqlite3_column_bytes(m_cursor_stmt, 1));
value.write({value_data, value_data_size});
- return true;
+ return Status::MORE;
}
-void SQLiteBatch::CloseCursor()
+SQLiteCursor::~SQLiteCursor()
{
sqlite3_reset(m_cursor_stmt);
- m_cursor_init = false;
+ int res = sqlite3_finalize(m_cursor_stmt);
+ if (res != SQLITE_OK) {
+ LogPrintf("%s: cursor closed but could not finalize cursor statement: %s\n",
+ __func__, sqlite3_errstr(res));
+ }
+}
+
+std::unique_ptr<DatabaseCursor> SQLiteBatch::GetNewCursor()
+{
+ if (!m_database.m_db) return nullptr;
+ auto cursor = std::make_unique<SQLiteCursor>();
+
+ const char* stmt_text = "SELECT key, value FROM main";
+ int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, &cursor->m_cursor_stmt, nullptr);
+ if (res != SQLITE_OK) {
+ throw std::runtime_error(strprintf(
+ "%s: Failed to setup cursor SQL statement: %s\n", __func__, sqlite3_errstr(res)));
+ }
+
+ return cursor;
}
bool SQLiteBatch::TxnBegin()
diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h
index 47b7ebb0ec..5745a1d4cf 100644
--- a/src/wallet/sqlite.h
+++ b/src/wallet/sqlite.h
@@ -1,10 +1,11 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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_SQLITE_H
#define BITCOIN_WALLET_SQLITE_H
+#include <sync.h>
#include <wallet/db.h>
#include <sqlite3.h>
@@ -14,26 +15,34 @@ struct bilingual_str;
namespace wallet {
class SQLiteDatabase;
+class SQLiteCursor : public DatabaseCursor
+{
+public:
+ sqlite3_stmt* m_cursor_stmt{nullptr};
+
+ explicit SQLiteCursor() {}
+ ~SQLiteCursor() override;
+
+ Status Next(DataStream& key, DataStream& value) override;
+};
+
/** RAII class that provides access to a WalletDatabase */
class SQLiteBatch : public DatabaseBatch
{
private:
SQLiteDatabase& m_database;
- bool m_cursor_init = false;
-
sqlite3_stmt* m_read_stmt{nullptr};
sqlite3_stmt* m_insert_stmt{nullptr};
sqlite3_stmt* m_overwrite_stmt{nullptr};
sqlite3_stmt* m_delete_stmt{nullptr};
- sqlite3_stmt* m_cursor_stmt{nullptr};
void SetupSQLStatements();
- bool ReadKey(CDataStream&& key, CDataStream& value) override;
- bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite = true) override;
- bool EraseKey(CDataStream&& key) override;
- bool HasKey(CDataStream&& key) override;
+ bool ReadKey(DataStream&& key, DataStream& value) override;
+ bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override;
+ bool EraseKey(DataStream&& key) override;
+ bool HasKey(DataStream&& key) override;
public:
explicit SQLiteBatch(SQLiteDatabase& database);
@@ -44,9 +53,7 @@ public:
void Close() override;
- bool StartCursor() override;
- bool ReadAtCursor(CDataStream& key, CDataStream& value, bool& complete) override;
- void CloseCursor() override;
+ std::unique_ptr<DatabaseCursor> GetNewCursor() override;
bool TxnBegin() override;
bool TxnCommit() override;
bool TxnAbort() override;
@@ -63,7 +70,16 @@ private:
const std::string m_file_path;
- void Cleanup() noexcept;
+ /**
+ * This mutex protects SQLite initialization and shutdown.
+ * sqlite3_config() and sqlite3_shutdown() are not thread-safe (sqlite3_initialize() is).
+ * Concurrent threads that execute SQLiteDatabase::SQLiteDatabase() should have just one
+ * of them do the init and the rest wait for it to complete before all can proceed.
+ */
+ static Mutex g_sqlite_mutex;
+ static int g_sqlite_count GUARDED_BY(g_sqlite_mutex);
+
+ void Cleanup() noexcept EXCLUSIVE_LOCKS_REQUIRED(!g_sqlite_mutex);
public:
SQLiteDatabase() = delete;
diff --git a/src/wallet/test/availablecoins_tests.cpp b/src/wallet/test/availablecoins_tests.cpp
deleted file mode 100644
index 2427a343d5..0000000000
--- a/src/wallet/test/availablecoins_tests.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2022 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or https://www.opensource.org/licenses/mit-license.php.
-
-#include <validation.h>
-#include <wallet/coincontrol.h>
-#include <wallet/spend.h>
-#include <wallet/test/util.h>
-#include <wallet/test/wallet_test_fixture.h>
-
-#include <boost/test/unit_test.hpp>
-
-namespace wallet {
-BOOST_FIXTURE_TEST_SUITE(availablecoins_tests, WalletTestingSetup)
-class AvailableCoinsTestingSetup : public TestChain100Setup
-{
-public:
- AvailableCoinsTestingSetup()
- {
- CreateAndProcessBlock({}, {});
- wallet = CreateSyncedWallet(*m_node.chain, m_node.chainman->ActiveChain(), m_args, coinbaseKey);
- }
-
- ~AvailableCoinsTestingSetup()
- {
- wallet.reset();
- }
- CWalletTx& AddTx(CRecipient recipient)
- {
- CTransactionRef tx;
- CCoinControl dummy;
- {
- constexpr int RANDOM_CHANGE_POSITION = -1;
- auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, dummy);
- BOOST_CHECK(res);
- tx = res->tx;
- }
- wallet->CommitTransaction(tx, {}, {});
- CMutableTransaction blocktx;
- {
- LOCK(wallet->cs_wallet);
- blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx);
- }
- CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
-
- LOCK(wallet->cs_wallet);
- LOCK(m_node.chainman->GetMutex());
- wallet->SetLastBlockProcessed(wallet->GetLastBlockHeight() + 1, m_node.chainman->ActiveChain().Tip()->GetBlockHash());
- auto it = wallet->mapWallet.find(tx->GetHash());
- BOOST_CHECK(it != wallet->mapWallet.end());
- it->second.m_state = TxStateConfirmed{m_node.chainman->ActiveChain().Tip()->GetBlockHash(), m_node.chainman->ActiveChain().Height(), /*index=*/1};
- return it->second;
- }
-
- std::unique_ptr<CWallet> wallet;
-};
-
-BOOST_FIXTURE_TEST_CASE(BasicOutputTypesTest, AvailableCoinsTestingSetup)
-{
- CoinsResult available_coins;
- util::Result<CTxDestination> dest{util::Error{}};
- LOCK(wallet->cs_wallet);
-
- // Verify our wallet has one usable coinbase UTXO before starting
- // This UTXO is a P2PK, so it should show up in the Other bucket
- available_coins = AvailableCoins(*wallet);
- BOOST_CHECK_EQUAL(available_coins.Size(), 1U);
- BOOST_CHECK_EQUAL(available_coins.coins[OutputType::UNKNOWN].size(), 1U);
-
- // We will create a self transfer for each of the OutputTypes and
- // verify it is put in the correct bucket after running GetAvailablecoins
- //
- // For each OutputType, We expect 2 UTXOs in our wallet following the self transfer:
- // 1. One UTXO as the recipient
- // 2. One UTXO from the change, due to payment address matching logic
-
- // Bech32m
- dest = wallet->GetNewDestination(OutputType::BECH32M, "");
- BOOST_ASSERT(dest);
- AddTx(CRecipient{{GetScriptForDestination(*dest)}, 1 * COIN, /*fSubtractFeeFromAmount=*/true});
- available_coins = AvailableCoins(*wallet);
- BOOST_CHECK_EQUAL(available_coins.coins[OutputType::BECH32M].size(), 2U);
-
- // Bech32
- dest = wallet->GetNewDestination(OutputType::BECH32, "");
- BOOST_ASSERT(dest);
- AddTx(CRecipient{{GetScriptForDestination(*dest)}, 2 * COIN, /*fSubtractFeeFromAmount=*/true});
- available_coins = AvailableCoins(*wallet);
- BOOST_CHECK_EQUAL(available_coins.coins[OutputType::BECH32].size(), 2U);
-
- // P2SH-SEGWIT
- dest = wallet->GetNewDestination(OutputType::P2SH_SEGWIT, "");
- BOOST_ASSERT(dest);
- AddTx(CRecipient{{GetScriptForDestination(*dest)}, 3 * COIN, /*fSubtractFeeFromAmount=*/true});
- available_coins = AvailableCoins(*wallet);
- BOOST_CHECK_EQUAL(available_coins.coins[OutputType::P2SH_SEGWIT].size(), 2U);
-
- // Legacy (P2PKH)
- dest = wallet->GetNewDestination(OutputType::LEGACY, "");
- BOOST_ASSERT(dest);
- AddTx(CRecipient{{GetScriptForDestination(*dest)}, 4 * COIN, /*fSubtractFeeFromAmount=*/true});
- available_coins = AvailableCoins(*wallet);
- BOOST_CHECK_EQUAL(available_coins.coins[OutputType::LEGACY].size(), 2U);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-} // namespace wallet
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 23f024247d..8f626addde 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 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 <consensus/amount.h>
#include <node/context.h>
+#include <policy/policy.h>
#include <primitives/transaction.h>
#include <random.h>
#include <test/util/setup_common.h>
@@ -28,7 +29,7 @@ BOOST_FIXTURE_TEST_SUITE(coinselector_tests, WalletTestingSetup)
// we repeat those tests this many times and only complain if all iterations of the test fail
#define RANDOM_REPEATS 5
-typedef std::set<COutput> CoinSet;
+typedef std::set<std::shared_ptr<COutput>> CoinSet;
static const CoinEligibilityFilter filter_standard(1, 6, 0);
static const CoinEligibilityFilter filter_confirmed(1, 1, 0);
@@ -52,7 +53,7 @@ static void add_coin(const CAmount& nValue, int nInput, SelectionResult& result)
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
COutput output(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 1, /*input_bytes=*/ -1, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, /*fees=*/ 0);
OutputGroup group;
- group.Insert(output, /*ancestors=*/ 0, /*descendants=*/ 0, /*positive_only=*/ true);
+ group.Insert(std::make_shared<COutput>(output), /*ancestors=*/ 0, /*descendants=*/ 0);
result.AddInput(group);
}
@@ -64,7 +65,7 @@ static void add_coin(const CAmount& nValue, int nInput, CoinSet& set, CAmount fe
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
COutput coin(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 1, /*input_bytes=*/ 148, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, fee);
coin.long_term_fee = long_term_fee;
- set.insert(coin);
+ set.insert(std::make_shared<COutput>(coin));
}
static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmount& nValue, CFeeRate feerate = CFeeRate(0), int nAge = 6*24, bool fIsFromMe = false, int nInput =0, bool spendable = false)
@@ -83,7 +84,7 @@ static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmoun
assert(ret.second);
CWalletTx& wtx = (*ret.first).second;
const auto& txout = wtx.tx->vout.at(nInput);
- available_coins.coins[OutputType::BECH32].emplace_back(COutPoint(wtx.GetHash(), nInput), txout, nAge, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, wtx.GetTxTime(), fIsFromMe, feerate);
+ available_coins.Add(OutputType::BECH32, {COutPoint(wtx.GetHash(), nInput), txout, nAge, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, wtx.GetTxTime(), fIsFromMe, feerate});
}
/** Check if SelectionResult a is equivalent to SelectionResult b.
@@ -93,10 +94,10 @@ static bool EquivalentResult(const SelectionResult& a, const SelectionResult& b)
std::vector<CAmount> a_amts;
std::vector<CAmount> b_amts;
for (const auto& coin : a.GetInputSet()) {
- a_amts.push_back(coin.txout.nValue);
+ a_amts.push_back(coin->txout.nValue);
}
for (const auto& coin : b.GetInputSet()) {
- b_amts.push_back(coin.txout.nValue);
+ b_amts.push_back(coin->txout.nValue);
}
std::sort(a_amts.begin(), a_amts.end());
std::sort(b_amts.begin(), b_amts.end());
@@ -109,8 +110,8 @@ static bool EquivalentResult(const SelectionResult& a, const SelectionResult& b)
static bool EqualResult(const SelectionResult& a, const SelectionResult& b)
{
std::pair<CoinSet::iterator, CoinSet::iterator> ret = std::mismatch(a.GetInputSet().begin(), a.GetInputSet().end(), b.GetInputSet().begin(),
- [](const COutput& a, const COutput& b) {
- return a.outpoint == b.outpoint;
+ [](const std::shared_ptr<COutput>& a, const std::shared_ptr<COutput>& b) {
+ return a->outpoint == b->outpoint;
});
return ret.first == a.GetInputSet().end() && ret.second == b.GetInputSet().end();
}
@@ -120,9 +121,9 @@ static CAmount make_hard_case(int utxos, std::vector<COutput>& utxo_pool)
utxo_pool.clear();
CAmount target = 0;
for (int i = 0; i < utxos; ++i) {
- target += (CAmount)1 << (utxos+i);
- add_coin((CAmount)1 << (utxos+i), 2*i, utxo_pool);
- add_coin(((CAmount)1 << (utxos+i)) + ((CAmount)1 << (utxos-1-i)), 2*i + 1, utxo_pool);
+ target += CAmount{1} << (utxos+i);
+ add_coin(CAmount{1} << (utxos+i), 2*i, utxo_pool);
+ add_coin((CAmount{1} << (utxos+i)) + (CAmount{1} << (utxos-1-i)), 2*i + 1, utxo_pool);
}
return target;
}
@@ -133,12 +134,12 @@ inline std::vector<OutputGroup>& GroupCoins(const std::vector<COutput>& availabl
static_groups.clear();
for (auto& coin : available_coins) {
static_groups.emplace_back();
- static_groups.back().Insert(coin, /*ancestors=*/ 0, /*descendants=*/ 0, /*positive_only=*/ false);
+ static_groups.back().Insert(std::make_shared<COutput>(coin), /*ancestors=*/ 0, /*descendants=*/ 0);
}
return static_groups;
}
-inline std::vector<OutputGroup>& KnapsackGroupOutputs(const std::vector<COutput>& available_coins, CWallet& wallet, const CoinEligibilityFilter& filter)
+inline std::vector<OutputGroup>& KnapsackGroupOutputs(const CoinsResult& available_coins, CWallet& wallet, const CoinEligibilityFilter& filter)
{
FastRandomContext rand{};
CoinSelectionParams coin_selection_params{
@@ -152,9 +153,9 @@ inline std::vector<OutputGroup>& KnapsackGroupOutputs(const std::vector<COutput>
/*tx_noinputs_size=*/ 0,
/*avoid_partial=*/ false,
};
- static std::vector<OutputGroup> static_groups;
- static_groups = GroupOutputs(wallet, available_coins, coin_selection_params, filter, /*positive_only=*/false);
- return static_groups;
+ static OutputGroupTypeMap static_groups;
+ static_groups = GroupOutputs(wallet, available_coins, coin_selection_params, {{filter}})[filter];
+ return static_groups.all_groups.mixed_group;
}
// Branch and bound coin selection tests
@@ -231,17 +232,6 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
BOOST_CHECK_EQUAL(result5->GetSelectedValue(), 10 * CENT);
expected_result.Clear();
- // Negative effective value
- // Select 10 Cent but have 1 Cent not be possible because too small
- add_coin(5 * CENT, 5, expected_result);
- add_coin(3 * CENT, 3, expected_result);
- add_coin(2 * CENT, 2, expected_result);
- const auto result6 = SelectCoinsBnB(GroupCoins(utxo_pool), 10 * CENT, 5000);
- BOOST_CHECK(result6);
- BOOST_CHECK_EQUAL(result6->GetSelectedValue(), 10 * CENT);
- // FIXME: this test is redundant with the above, because 1 Cent is selected, not "too small"
- // BOOST_CHECK(EquivalentResult(expected_result, *result));
-
// Select 0.25 Cent, not possible
BOOST_CHECK(!SelectCoinsBnB(GroupCoins(utxo_pool), 0.25 * CENT, 0.5 * CENT));
expected_result.Clear();
@@ -301,8 +291,10 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_change_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_output_size);
coin_selection_params_bnb.m_cost_of_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size) + coin_selection_params_bnb.m_change_fee;
coin_selection_params_bnb.min_viable_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size);
+ coin_selection_params_bnb.m_subtract_fee_outputs = true;
+
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -318,14 +310,13 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
available_coins.Clear();
add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate);
available_coins.All().at(0).input_bytes = 40;
- coin_selection_params_bnb.m_subtract_fee_outputs = true;
const auto result9 = SelectCoinsBnB(GroupCoins(available_coins.All()), 1 * CENT, coin_selection_params_bnb.m_cost_of_change);
BOOST_CHECK(result9);
BOOST_CHECK_EQUAL(result9->GetSelectedValue(), 1 * CENT);
}
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -338,13 +329,17 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(available_coins, *wallet, 2 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
CCoinControl coin_control;
coin_control.m_allow_other_inputs = true;
- coin_control.Select(available_coins.All().at(0).outpoint);
+ COutput select_coin = available_coins.All().at(0);
+ coin_control.Select(select_coin.outpoint);
+ PreSelectedInputs selected_input;
+ selected_input.Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs);
+ available_coins.Erase({available_coins.coins[OutputType::BECH32].begin()->outpoint});
coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
- const auto result10 = SelectCoins(*wallet, available_coins, 10 * CENT, coin_control, coin_selection_params_bnb);
+ const auto result10 = SelectCoins(*wallet, available_coins, selected_input, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(result10);
}
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -363,7 +358,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
expected_result.Clear();
add_coin(10 * CENT, 2, expected_result);
CCoinControl coin_control;
- const auto result11 = SelectCoins(*wallet, available_coins, 10 * CENT, coin_control, coin_selection_params_bnb);
+ const auto result11 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result11));
available_coins.Clear();
@@ -378,7 +373,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
expected_result.Clear();
add_coin(9 * CENT, 2, expected_result);
add_coin(1 * CENT, 2, expected_result);
- const auto result12 = SelectCoins(*wallet, available_coins, 10 * CENT, coin_control, coin_selection_params_bnb);
+ const auto result12 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result12));
available_coins.Clear();
@@ -394,8 +389,12 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(9 * CENT, 2, expected_result);
add_coin(1 * CENT, 2, expected_result);
coin_control.m_allow_other_inputs = true;
- coin_control.Select(available_coins.All().at(1).outpoint); // pre select 9 coin
- const auto result13 = SelectCoins(*wallet, available_coins, 10 * CENT, coin_control, coin_selection_params_bnb);
+ COutput select_coin = available_coins.All().at(1); // pre select 9 coin
+ coin_control.Select(select_coin.outpoint);
+ PreSelectedInputs selected_input;
+ selected_input.Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs);
+ available_coins.Erase({(++available_coins.coins[OutputType::BECH32].begin())->outpoint});
+ const auto result13 = SelectCoins(*wallet, available_coins, selected_input, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result13));
}
}
@@ -405,7 +404,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
FastRandomContext rand{};
const auto temp1{[&rand](std::vector<OutputGroup>& g, const CAmount& v, CAmount c) { return KnapsackSolver(g, v, c, rand); }};
const auto KnapsackSolver{temp1};
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -419,25 +418,25 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
available_coins.Clear();
// with an empty wallet we can't even pay one cent
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_standard), 1 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_standard), 1 * CENT, CENT));
add_coin(available_coins, *wallet, 1*CENT, CFeeRate(0), 4); // add a new 1 cent coin
// with a new 1 cent coin, we still can't find a mature 1 cent
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_standard), 1 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_standard), 1 * CENT, CENT));
// but we can find a new 1 cent
- const auto result1 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 1 * CENT, CENT);
+ const auto result1 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 1 * CENT, CENT);
BOOST_CHECK(result1);
BOOST_CHECK_EQUAL(result1->GetSelectedValue(), 1 * CENT);
add_coin(available_coins, *wallet, 2*CENT); // add a mature 2 cent coin
// we can't make 3 cents of mature coins
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_standard), 3 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_standard), 3 * CENT, CENT));
// we can make 3 cents of new coins
- const auto result2 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 3 * CENT, CENT);
+ const auto result2 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 3 * CENT, CENT);
BOOST_CHECK(result2);
BOOST_CHECK_EQUAL(result2->GetSelectedValue(), 3 * CENT);
@@ -448,38 +447,38 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
// we can't make 38 cents only if we disallow new coins:
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_standard), 38 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_standard), 38 * CENT, CENT));
// we can't even make 37 cents if we don't allow new coins even if they're from us
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_standard_extra), 38 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_standard_extra), 38 * CENT, CENT));
// but we can make 37 cents if we accept new coins from ourself
- const auto result3 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_standard), 37 * CENT, CENT);
+ const auto result3 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_standard), 37 * CENT, CENT);
BOOST_CHECK(result3);
BOOST_CHECK_EQUAL(result3->GetSelectedValue(), 37 * CENT);
// and we can make 38 cents if we accept all new coins
- const auto result4 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 38 * CENT, CENT);
+ const auto result4 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 38 * CENT, CENT);
BOOST_CHECK(result4);
BOOST_CHECK_EQUAL(result4->GetSelectedValue(), 38 * CENT);
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
- const auto result5 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 34 * CENT, CENT);
+ const auto result5 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 34 * CENT, CENT);
BOOST_CHECK(result5);
BOOST_CHECK_EQUAL(result5->GetSelectedValue(), 35 * CENT); // but 35 cents is closest
BOOST_CHECK_EQUAL(result5->GetInputSet().size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
- const auto result6 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 7 * CENT, CENT);
+ const auto result6 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 7 * CENT, CENT);
BOOST_CHECK(result6);
BOOST_CHECK_EQUAL(result6->GetSelectedValue(), 7 * CENT);
BOOST_CHECK_EQUAL(result6->GetInputSet().size(), 2U);
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
- const auto result7 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 8 * CENT, CENT);
+ const auto result7 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 8 * CENT, CENT);
BOOST_CHECK(result7);
BOOST_CHECK(result7->GetSelectedValue() == 8 * CENT);
BOOST_CHECK_EQUAL(result7->GetInputSet().size(), 3U);
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
- const auto result8 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 9 * CENT, CENT);
+ const auto result8 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 9 * CENT, CENT);
BOOST_CHECK(result8);
BOOST_CHECK_EQUAL(result8->GetSelectedValue(), 10 * CENT);
BOOST_CHECK_EQUAL(result8->GetInputSet().size(), 1U);
@@ -494,12 +493,12 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(available_coins, *wallet, 30*CENT); // now we have 6+7+8+20+30 = 71 cents total
// check that we have 71 and not 72
- const auto result9 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 71 * CENT, CENT);
+ const auto result9 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 71 * CENT, CENT);
BOOST_CHECK(result9);
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 72 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 72 * CENT, CENT));
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
- const auto result10 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 16 * CENT, CENT);
+ const auto result10 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 16 * CENT, CENT);
BOOST_CHECK(result10);
BOOST_CHECK_EQUAL(result10->GetSelectedValue(), 20 * CENT); // we should get 20 in one coin
BOOST_CHECK_EQUAL(result10->GetInputSet().size(), 1U);
@@ -507,7 +506,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(available_coins, *wallet, 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
- const auto result11 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 16 * CENT, CENT);
+ const auto result11 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 16 * CENT, CENT);
BOOST_CHECK(result11);
BOOST_CHECK_EQUAL(result11->GetSelectedValue(), 18 * CENT); // we should get 18 in 3 coins
BOOST_CHECK_EQUAL(result11->GetInputSet().size(), 3U);
@@ -515,13 +514,13 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(available_coins, *wallet, 18*CENT); // now we have 5+6+7+8+18+20+30
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
- const auto result12 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 16 * CENT, CENT);
+ const auto result12 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 16 * CENT, CENT);
BOOST_CHECK(result12);
BOOST_CHECK_EQUAL(result12->GetSelectedValue(), 18 * CENT); // we should get 18 in 1 coin
BOOST_CHECK_EQUAL(result12->GetInputSet().size(), 1U); // because in the event of a tie, the biggest coin wins
// now try making 11 cents. we should get 5+6
- const auto result13 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 11 * CENT, CENT);
+ const auto result13 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 11 * CENT, CENT);
BOOST_CHECK(result13);
BOOST_CHECK_EQUAL(result13->GetSelectedValue(), 11 * CENT);
BOOST_CHECK_EQUAL(result13->GetInputSet().size(), 2U);
@@ -531,12 +530,12 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(available_coins, *wallet, 2*COIN);
add_coin(available_coins, *wallet, 3*COIN);
add_coin(available_coins, *wallet, 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
- const auto result14 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 95 * CENT, CENT);
+ const auto result14 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 95 * CENT, CENT);
BOOST_CHECK(result14);
BOOST_CHECK_EQUAL(result14->GetSelectedValue(), 1 * COIN); // we should get 1 BTC in 1 coin
BOOST_CHECK_EQUAL(result14->GetInputSet().size(), 1U);
- const auto result15 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 195 * CENT, CENT);
+ const auto result15 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 195 * CENT, CENT);
BOOST_CHECK(result15);
BOOST_CHECK_EQUAL(result15->GetSelectedValue(), 2 * COIN); // we should get 2 BTC in 1 coin
BOOST_CHECK_EQUAL(result15->GetInputSet().size(), 1U);
@@ -552,7 +551,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// try making 1 * CENT from the 1.5 * CENT
// we'll get change smaller than CENT whatever happens, so can expect CENT exactly
- const auto result16 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), CENT, CENT);
+ const auto result16 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), CENT, CENT);
BOOST_CHECK(result16);
BOOST_CHECK_EQUAL(result16->GetSelectedValue(), CENT);
@@ -560,7 +559,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(available_coins, *wallet, 1111*CENT);
// try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
- const auto result17 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 1 * CENT, CENT);
+ const auto result17 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 1 * CENT, CENT);
BOOST_CHECK(result17);
BOOST_CHECK_EQUAL(result17->GetSelectedValue(), 1 * CENT); // we should get the exact amount
@@ -569,7 +568,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(available_coins, *wallet, CENT * 7 / 10);
// and try again to make 1.0 * CENT
- const auto result18 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 1 * CENT, CENT);
+ const auto result18 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 1 * CENT, CENT);
BOOST_CHECK(result18);
BOOST_CHECK_EQUAL(result18->GetSelectedValue(), 1 * CENT); // we should get the exact amount
@@ -579,7 +578,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
for (int j = 0; j < 20; j++)
add_coin(available_coins, *wallet, 50000 * COIN);
- const auto result19 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 500000 * COIN, CENT);
+ const auto result19 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 500000 * COIN, CENT);
BOOST_CHECK(result19);
BOOST_CHECK_EQUAL(result19->GetSelectedValue(), 500000 * COIN); // we should get the exact amount
BOOST_CHECK_EQUAL(result19->GetInputSet().size(), 10U); // in ten coins
@@ -593,7 +592,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(available_coins, *wallet, CENT * 6 / 10);
add_coin(available_coins, *wallet, CENT * 7 / 10);
add_coin(available_coins, *wallet, 1111 * CENT);
- const auto result20 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 1 * CENT, CENT);
+ const auto result20 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 1 * CENT, CENT);
BOOST_CHECK(result20);
BOOST_CHECK_EQUAL(result20->GetSelectedValue(), 1111 * CENT); // we get the bigger coin
BOOST_CHECK_EQUAL(result20->GetInputSet().size(), 1U);
@@ -604,7 +603,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(available_coins, *wallet, CENT * 6 / 10);
add_coin(available_coins, *wallet, CENT * 8 / 10);
add_coin(available_coins, *wallet, 1111 * CENT);
- const auto result21 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), CENT, CENT);
+ const auto result21 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), CENT, CENT);
BOOST_CHECK(result21);
BOOST_CHECK_EQUAL(result21->GetSelectedValue(), CENT); // we should get the exact amount
BOOST_CHECK_EQUAL(result21->GetInputSet().size(), 2U); // in two coins 0.4+0.6
@@ -616,13 +615,13 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(available_coins, *wallet, CENT * 100);
// trying to make 100.01 from these three coins
- const auto result22 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), CENT * 10001 / 100, CENT);
+ const auto result22 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), CENT * 10001 / 100, CENT);
BOOST_CHECK(result22);
BOOST_CHECK_EQUAL(result22->GetSelectedValue(), CENT * 10105 / 100); // we should get all coins
BOOST_CHECK_EQUAL(result22->GetInputSet().size(), 3U);
// but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change
- const auto result23 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), CENT * 9990 / 100, CENT);
+ const auto result23 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), CENT * 9990 / 100, CENT);
BOOST_CHECK(result23);
BOOST_CHECK_EQUAL(result23->GetSelectedValue(), 101 * CENT);
BOOST_CHECK_EQUAL(result23->GetInputSet().size(), 2U);
@@ -637,7 +636,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// We only create the wallet once to save time, but we still run the coin selection RUN_TESTS times.
for (int i = 0; i < RUN_TESTS; i++) {
- const auto result24 = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_confirmed), 2000, CENT);
+ const auto result24 = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_confirmed), 2000, CENT);
BOOST_CHECK(result24);
if (amt - 2000 < CENT) {
@@ -715,7 +714,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
{
FastRandomContext rand{};
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -728,7 +727,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
add_coin(available_coins, *wallet, 1000 * COIN);
add_coin(available_coins, *wallet, 3 * COIN);
- const auto result = KnapsackSolver(KnapsackGroupOutputs(available_coins.All(), *wallet, filter_standard), 1003 * COIN, CENT, rand);
+ const auto result = KnapsackSolver(KnapsackGroupOutputs(available_coins, *wallet, filter_standard), 1003 * COIN, CENT, rand);
BOOST_CHECK(result);
BOOST_CHECK_EQUAL(result->GetSelectedValue(), 1003 * COIN);
BOOST_CHECK_EQUAL(result->GetInputSet().size(), 2U);
@@ -737,7 +736,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
// Tests that with the ideal conditions, the coin selector will always be able to find a solution that can pay the target value
BOOST_AUTO_TEST_CASE(SelectCoins_test)
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -783,7 +782,7 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
cs_params.m_cost_of_change = 1;
cs_params.min_viable_change = 1;
CCoinControl cc;
- const auto result = SelectCoins(*wallet, available_coins, target, cc, cs_params);
+ const auto result = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, target, cc, cs_params);
BOOST_CHECK(result);
BOOST_CHECK_GE(result->GetSelectedValue(), target);
}
@@ -922,13 +921,131 @@ BOOST_AUTO_TEST_CASE(effective_value_test)
BOOST_CHECK_EQUAL(output5.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1
}
+static util::Result<SelectionResult> select_coins(const CAmount& target, const CoinSelectionParams& cs_params, const CCoinControl& cc, std::function<CoinsResult(CWallet&)> coin_setup, interfaces::Chain* chain)
+{
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(chain, "", CreateMockWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
+ auto available_coins = coin_setup(*wallet);
+
+ auto result = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/ {}, target, cc, cs_params);
+ if (result) {
+ const auto signedTxSize = 10 + 34 + 68 * result->GetInputSet().size(); // static header size + output size + inputs size (P2WPKH)
+ BOOST_CHECK_LE(signedTxSize * WITNESS_SCALE_FACTOR, MAX_STANDARD_TX_WEIGHT);
+
+ BOOST_CHECK_GE(result->GetSelectedValue(), target);
+ }
+ return result;
+}
+
+static bool has_coin(const CoinSet& set, CAmount amount)
+{
+ return std::any_of(set.begin(), set.end(), [&](const auto& coin) { return coin->GetEffectiveValue() == amount; });
+}
+
+BOOST_AUTO_TEST_CASE(check_max_weight)
+{
+ const CAmount target = 49.5L * COIN;
+ CCoinControl cc;
+
+ FastRandomContext rand;
+ CoinSelectionParams cs_params{
+ rand,
+ /*change_output_size=*/34,
+ /*change_spend_size=*/68,
+ /*min_change_target=*/CENT,
+ /*effective_feerate=*/CFeeRate(0),
+ /*long_term_feerate=*/CFeeRate(0),
+ /*discard_feerate=*/CFeeRate(0),
+ /*tx_noinputs_size=*/10 + 34, // static header size + output size
+ /*avoid_partial=*/false,
+ };
+
+ auto chain{m_node.chain.get()};
+
+ {
+ // Scenario 1:
+ // The actor starts with 1x 50.0 BTC and 1515x 0.033 BTC (~100.0 BTC total) unspent outputs
+ // Then tries to spend 49.5 BTC
+ // The 50.0 BTC output should be selected, because the transaction would otherwise be too large
+
+ // Perform selection
+
+ const auto result = select_coins(
+ target, cs_params, cc, [&](CWallet& wallet) {
+ CoinsResult available_coins;
+ for (int j = 0; j < 1515; ++j) {
+ add_coin(available_coins, wallet, CAmount(0.033 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+
+ add_coin(available_coins, wallet, CAmount(50 * COIN), CFeeRate(0), 144, false, 0, true);
+ return available_coins;
+ },
+ chain);
+
+ BOOST_CHECK(result);
+ BOOST_CHECK(has_coin(result->GetInputSet(), CAmount(50 * COIN)));
+ }
+
+ {
+ // Scenario 2:
+
+ // The actor starts with 400x 0.0625 BTC and 2000x 0.025 BTC (75.0 BTC total) unspent outputs
+ // Then tries to spend 49.5 BTC
+ // A combination of coins should be selected, such that the created transaction is not too large
+
+ // Perform selection
+ const auto result = select_coins(
+ target, cs_params, cc, [&](CWallet& wallet) {
+ CoinsResult available_coins;
+ for (int j = 0; j < 400; ++j) {
+ add_coin(available_coins, wallet, CAmount(0.0625 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+ for (int j = 0; j < 2000; ++j) {
+ add_coin(available_coins, wallet, CAmount(0.025 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+ return available_coins;
+ },
+ chain);
+
+ BOOST_CHECK(has_coin(result->GetInputSet(), CAmount(0.0625 * COIN)));
+ BOOST_CHECK(has_coin(result->GetInputSet(), CAmount(0.025 * COIN)));
+ }
+
+ {
+ // Scenario 3:
+
+ // The actor starts with 1515x 0.033 BTC (49.995 BTC total) unspent outputs
+ // No results should be returned, because the transaction would be too large
+
+ // Perform selection
+ const auto result = select_coins(
+ target, cs_params, cc, [&](CWallet& wallet) {
+ CoinsResult available_coins;
+ for (int j = 0; j < 1515; ++j) {
+ add_coin(available_coins, wallet, CAmount(0.033 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+ return available_coins;
+ },
+ chain);
+
+ // No results
+ // 1515 inputs * 68 bytes = 103,020 bytes
+ // 103,020 bytes * 4 = 412,080 weight, which is above the MAX_STANDARD_TX_WEIGHT of 400,000
+ BOOST_CHECK(!result);
+ }
+}
+
BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
{
// Test that the effective value is used to check whether preset inputs provide sufficient funds when subtract_fee_outputs is not used.
// This test creates a coin whose value is higher than the target but whose effective value is lower than the target.
// The coin is selected using coin control, with m_allow_other_inputs = false. SelectCoins should fail due to insufficient funds.
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -936,7 +1053,7 @@ BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
CoinsResult available_coins;
{
- std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", m_args, CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", CreateMockWalletDatabase());
dummyWallet->LoadWallet();
LOCK(dummyWallet->cs_wallet);
dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -965,9 +1082,52 @@ BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
cc.SetInputWeight(output.outpoint, 148);
cc.SelectExternal(output.outpoint, output.txout);
- const auto result = SelectCoins(*wallet, available_coins, target, cc, cs_params);
+ const auto preset_inputs = *Assert(FetchSelectedInputs(*wallet, cc, cs_params));
+ available_coins.Erase({available_coins.coins[OutputType::BECH32].begin()->outpoint});
+
+ const auto result = SelectCoins(*wallet, available_coins, preset_inputs, target, cc, cs_params);
BOOST_CHECK(!result);
}
+BOOST_FIXTURE_TEST_CASE(wallet_coinsresult_test, BasicTestingSetup)
+{
+ // Test case to verify CoinsResult object sanity.
+ CoinsResult available_coins;
+ {
+ std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", CreateMockWalletDatabase());
+ BOOST_CHECK_EQUAL(dummyWallet->LoadWallet(), DBErrors::LOAD_OK);
+ LOCK(dummyWallet->cs_wallet);
+ dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ dummyWallet->SetupDescriptorScriptPubKeyMans();
+
+ // Add some coins to 'available_coins'
+ for (int i=0; i<10; i++) {
+ add_coin(available_coins, *dummyWallet, 1 * COIN);
+ }
+ }
+
+ {
+ // First test case, check that 'CoinsResult::Erase' function works as expected.
+ // By trying to erase two elements from the 'available_coins' object.
+ std::unordered_set<COutPoint, SaltedOutpointHasher> outs_to_remove;
+ const auto& coins = available_coins.All();
+ for (int i = 0; i < 2; i++) {
+ outs_to_remove.emplace(coins[i].outpoint);
+ }
+ available_coins.Erase(outs_to_remove);
+
+ // Check that the elements were actually removed.
+ const auto& updated_coins = available_coins.All();
+ for (const auto& out: outs_to_remove) {
+ auto it = std::find_if(updated_coins.begin(), updated_coins.end(), [&out](const COutput &coin) {
+ return coin.outpoint == out;
+ });
+ BOOST_CHECK(it == updated_coins.end());
+ }
+ // And verify that no extra element were removed
+ BOOST_CHECK_EQUAL(available_coins.Size(), 8);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index f61808c549..7e26656b86 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/feebumper_tests.cpp b/src/wallet/test/feebumper_tests.cpp
index 6add86dc3d..2480a9b4e1 100644
--- a/src/wallet/test/feebumper_tests.cpp
+++ b/src/wallet/test/feebumper_tests.cpp
@@ -2,6 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php.
+#include <consensus/validation.h>
+#include <policy/policy.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <util/strencodings.h>
diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp
index 1a0708c43a..304190eec1 100644
--- a/src/wallet/test/fuzz/coinselection.cpp
+++ b/src/wallet/test/fuzz/coinselection.cpp
@@ -29,8 +29,10 @@ static void GroupCoins(FuzzedDataProvider& fuzzed_data_provider, const std::vect
auto output_group = OutputGroup(coin_params);
bool valid_outputgroup{false};
for (auto& coin : coins) {
- output_group.Insert(coin, /*ancestors=*/0, /*descendants=*/0, positive_only);
- // If positive_only was specified, nothing may have been inserted, leading to an empty output group
+ if (!positive_only || (positive_only && coin.GetEffectiveValue() > 0)) {
+ output_group.Insert(std::make_shared<COutput>(coin), /*ancestors=*/0, /*descendants=*/0);
+ }
+ // If positive_only was specified, nothing was inserted, leading to an empty output group
// that would be invalid for the BnB algorithm
valid_outputgroup = !positive_only || output_group.GetSelectionAmount() > 0;
if (valid_outputgroup && fuzzed_data_provider.ConsumeBool()) {
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index 5e9cd4001b..de381a5ec9 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/fuzz/parse_iso8601.cpp b/src/wallet/test/fuzz/parse_iso8601.cpp
index 5be248c2fb..c1bafc1073 100644
--- a/src/wallet/test/fuzz/parse_iso8601.cpp
+++ b/src/wallet/test/fuzz/parse_iso8601.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2021 The Bitcoin Core developers
+// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/group_outputs_tests.cpp b/src/wallet/test/group_outputs_tests.cpp
new file mode 100644
index 0000000000..283e87989c
--- /dev/null
+++ b/src/wallet/test/group_outputs_tests.cpp
@@ -0,0 +1,234 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or https://www.opensource.org/licenses/mit-license.php.
+
+#include <test/util/setup_common.h>
+
+#include <wallet/coinselection.h>
+#include <wallet/spend.h>
+#include <wallet/wallet.h>
+
+#include <boost/test/unit_test.hpp>
+
+namespace wallet {
+BOOST_FIXTURE_TEST_SUITE(group_outputs_tests, TestingSetup)
+
+static int nextLockTime = 0;
+
+static std::shared_ptr<CWallet> NewWallet(const node::NodeContext& m_node)
+{
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+ return wallet;
+}
+
+static void addCoin(CoinsResult& coins,
+ CWallet& wallet,
+ const CTxDestination& dest,
+ const CAmount& nValue,
+ bool is_from_me,
+ CFeeRate fee_rate = CFeeRate(0),
+ int depth = 6)
+{
+ CMutableTransaction tx;
+ tx.nLockTime = nextLockTime++; // so all transactions get different hashes
+ tx.vout.resize(1);
+ tx.vout[0].nValue = nValue;
+ tx.vout[0].scriptPubKey = GetScriptForDestination(dest);
+
+ const uint256& txid = tx.GetHash();
+ LOCK(wallet.cs_wallet);
+ auto ret = wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid), std::forward_as_tuple(MakeTransactionRef(std::move(tx)), TxStateInactive{}));
+ assert(ret.second);
+ CWalletTx& wtx = (*ret.first).second;
+ const auto& txout = wtx.tx->vout.at(0);
+ coins.Add(*Assert(OutputTypeFromDestination(dest)),
+ {COutPoint(wtx.GetHash(), 0),
+ txout,
+ depth,
+ CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr),
+ /*spendable=*/ true,
+ /*solvable=*/ true,
+ /*safe=*/ true,
+ wtx.GetTxTime(),
+ is_from_me,
+ fee_rate});
+}
+
+ CoinSelectionParams makeSelectionParams(FastRandomContext& rand, bool avoid_partial_spends)
+{
+ return CoinSelectionParams{
+ rand,
+ /*change_output_size=*/ 0,
+ /*change_spend_size=*/ 0,
+ /*min_change_target=*/ CENT,
+ /*effective_feerate=*/ CFeeRate(0),
+ /*long_term_feerate=*/ CFeeRate(0),
+ /*discard_feerate=*/ CFeeRate(0),
+ /*tx_noinputs_size=*/ 0,
+ /*avoid_partial=*/ avoid_partial_spends,
+ };
+}
+
+class GroupVerifier
+{
+public:
+ std::shared_ptr<CWallet> wallet{nullptr};
+ CoinsResult coins_pool;
+ FastRandomContext rand;
+
+ void GroupVerify(const OutputType type,
+ const CoinEligibilityFilter& filter,
+ bool avoid_partial_spends,
+ bool positive_only,
+ int expected_size)
+ {
+ OutputGroupTypeMap groups = GroupOutputs(*wallet, coins_pool, makeSelectionParams(rand, avoid_partial_spends), {{filter}})[filter];
+ std::vector<OutputGroup>& groups_out = positive_only ? groups.groups_by_type[type].positive_group :
+ groups.groups_by_type[type].mixed_group;
+ BOOST_CHECK_EQUAL(groups_out.size(), expected_size);
+ }
+
+ void GroupAndVerify(const OutputType type,
+ const CoinEligibilityFilter& filter,
+ int expected_with_partial_spends_size,
+ int expected_without_partial_spends_size,
+ bool positive_only)
+ {
+ // First avoid partial spends
+ GroupVerify(type, filter, /*avoid_partial_spends=*/false, positive_only, expected_with_partial_spends_size);
+ // Second don't avoid partial spends
+ GroupVerify(type, filter, /*avoid_partial_spends=*/true, positive_only, expected_without_partial_spends_size);
+ }
+};
+
+BOOST_AUTO_TEST_CASE(outputs_grouping_tests)
+{
+ const auto& wallet = NewWallet(m_node);
+ GroupVerifier group_verifier;
+ group_verifier.wallet = wallet;
+
+ const CoinEligibilityFilter& BASIC_FILTER{1, 6, 0};
+
+ // #################################################################################
+ // 10 outputs from different txs going to the same script
+ // 1) if partial spends is enabled --> must not be grouped
+ // 2) if partial spends is not enabled --> must be grouped into a single OutputGroup
+ // #################################################################################
+
+ unsigned long GROUP_SIZE = 10;
+ const CTxDestination dest = *Assert(wallet->GetNewDestination(OutputType::BECH32, ""));
+ for (unsigned long i = 0; i < GROUP_SIZE; i++) {
+ addCoin(group_verifier.coins_pool, *wallet, dest, 10 * COIN, /*is_from_me=*/true);
+ }
+
+ group_verifier.GroupAndVerify(OutputType::BECH32,
+ BASIC_FILTER,
+ /*expected_with_partial_spends_size=*/ GROUP_SIZE,
+ /*expected_without_partial_spends_size=*/ 1,
+ /*positive_only=*/ true);
+
+ // ####################################################################################
+ // 3) 10 more UTXO are added with a different script --> must be grouped into a single
+ // group for avoid partial spends and 10 different output groups for partial spends
+ // ####################################################################################
+
+ const CTxDestination dest2 = *Assert(wallet->GetNewDestination(OutputType::BECH32, ""));
+ for (unsigned long i = 0; i < GROUP_SIZE; i++) {
+ addCoin(group_verifier.coins_pool, *wallet, dest2, 5 * COIN, /*is_from_me=*/true);
+ }
+
+ group_verifier.GroupAndVerify(OutputType::BECH32,
+ BASIC_FILTER,
+ /*expected_with_partial_spends_size=*/ GROUP_SIZE * 2,
+ /*expected_without_partial_spends_size=*/ 2,
+ /*positive_only=*/ true);
+
+ // ################################################################################
+ // 4) Now add a negative output --> which will be skipped if "positive_only" is set
+ // ################################################################################
+
+ const CTxDestination dest3 = *Assert(wallet->GetNewDestination(OutputType::BECH32, ""));
+ addCoin(group_verifier.coins_pool, *wallet, dest3, 1, true, CFeeRate(100));
+ BOOST_CHECK(group_verifier.coins_pool.coins[OutputType::BECH32].back().GetEffectiveValue() <= 0);
+
+ // First expect no changes with "positive_only" enabled
+ group_verifier.GroupAndVerify(OutputType::BECH32,
+ BASIC_FILTER,
+ /*expected_with_partial_spends_size=*/ GROUP_SIZE * 2,
+ /*expected_without_partial_spends_size=*/ 2,
+ /*positive_only=*/ true);
+
+ // Then expect changes with "positive_only" disabled
+ group_verifier.GroupAndVerify(OutputType::BECH32,
+ BASIC_FILTER,
+ /*expected_with_partial_spends_size=*/ GROUP_SIZE * 2 + 1,
+ /*expected_without_partial_spends_size=*/ 3,
+ /*positive_only=*/ false);
+
+
+ // ##############################################################################
+ // 5) Try to add a non-eligible UTXO (due not fulfilling the min depth target for
+ // "not mine" UTXOs) --> it must not be added to any group
+ // ##############################################################################
+
+ const CTxDestination dest4 = *Assert(wallet->GetNewDestination(OutputType::BECH32, ""));
+ addCoin(group_verifier.coins_pool, *wallet, dest4, 6 * COIN,
+ /*is_from_me=*/false, CFeeRate(0), /*depth=*/5);
+
+ // Expect no changes from this round and the previous one (point 4)
+ group_verifier.GroupAndVerify(OutputType::BECH32,
+ BASIC_FILTER,
+ /*expected_with_partial_spends_size=*/ GROUP_SIZE * 2 + 1,
+ /*expected_without_partial_spends_size=*/ 3,
+ /*positive_only=*/ false);
+
+
+ // ##############################################################################
+ // 6) Try to add a non-eligible UTXO (due not fulfilling the min depth target for
+ // "mine" UTXOs) --> it must not be added to any group
+ // ##############################################################################
+
+ const CTxDestination dest5 = *Assert(wallet->GetNewDestination(OutputType::BECH32, ""));
+ addCoin(group_verifier.coins_pool, *wallet, dest5, 6 * COIN,
+ /*is_from_me=*/true, CFeeRate(0), /*depth=*/0);
+
+ // Expect no changes from this round and the previous one (point 5)
+ group_verifier.GroupAndVerify(OutputType::BECH32,
+ BASIC_FILTER,
+ /*expected_with_partial_spends_size=*/ GROUP_SIZE * 2 + 1,
+ /*expected_without_partial_spends_size=*/ 3,
+ /*positive_only=*/ false);
+
+ // ###########################################################################################
+ // 7) Surpass the OUTPUT_GROUP_MAX_ENTRIES and verify that a second partial group gets created
+ // ###########################################################################################
+
+ const CTxDestination dest7 = *Assert(wallet->GetNewDestination(OutputType::BECH32, ""));
+ uint16_t NUM_SINGLE_ENTRIES = 101;
+ for (unsigned long i = 0; i < NUM_SINGLE_ENTRIES; i++) { // OUTPUT_GROUP_MAX_ENTRIES{100}
+ addCoin(group_verifier.coins_pool, *wallet, dest7, 9 * COIN, /*is_from_me=*/true);
+ }
+
+ // Exclude partial groups only adds one more group to the previous test case (point 6)
+ int PREVIOUS_ROUND_COUNT = GROUP_SIZE * 2 + 1;
+ group_verifier.GroupAndVerify(OutputType::BECH32,
+ BASIC_FILTER,
+ /*expected_with_partial_spends_size=*/ PREVIOUS_ROUND_COUNT + NUM_SINGLE_ENTRIES,
+ /*expected_without_partial_spends_size=*/ 4,
+ /*positive_only=*/ false);
+
+ // Include partial groups should add one more group inside the "avoid partial spends" count
+ const CoinEligibilityFilter& avoid_partial_groups_filter{1, 6, 0, 0, /*include_partial=*/ true};
+ group_verifier.GroupAndVerify(OutputType::BECH32,
+ avoid_partial_groups_filter,
+ /*expected_with_partial_spends_size=*/ PREVIOUS_ROUND_COUNT + NUM_SINGLE_ENTRIES,
+ /*expected_without_partial_spends_size=*/ 5,
+ /*positive_only=*/ false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+} // end namespace wallet
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index 8eb7689c94..60b1bab8ac 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index fb0a07e181..3dbc91fc68 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
index 68146eb079..90f369b22a 100644
--- a/src/wallet/test/ismine_tests.cpp
+++ b/src/wallet/test/ismine_tests.cpp
@@ -1,8 +1,9 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 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 <key.h>
+#include <key_io.h>
#include <node/context.h>
#include <script/script.h>
#include <script/standard.h>
@@ -16,6 +17,25 @@
namespace wallet {
BOOST_FIXTURE_TEST_SUITE(ismine_tests, BasicTestingSetup)
+wallet::ScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& desc_str, const bool success)
+{
+ keystore.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+
+ FlatSigningProvider keys;
+ std::string error;
+ std::unique_ptr<Descriptor> parsed_desc = Parse(desc_str, keys, error, false);
+ BOOST_CHECK(success == (parsed_desc != nullptr));
+ if (!success) return nullptr;
+
+ const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1;
+
+ WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
+
+ LOCK(keystore.cs_wallet);
+
+ return Assert(keystore.AddWalletDescriptor(w_desc, keys,/*label=*/"", /*internal=*/false));
+};
+
BOOST_AUTO_TEST_CASE(ismine_standard)
{
CKey keys[2];
@@ -33,9 +53,9 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
CScript scriptPubKey;
isminetype result;
- // P2PK compressed
+ // P2PK compressed - Legacy
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
@@ -52,9 +72,21 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
- // P2PK uncompressed
+ // P2PK compressed - Descriptor
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "pk(" + EncodeSecret(keys[0]) + ")";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2PK uncompressed - Legacy
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
@@ -71,9 +103,21 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
- // P2PKH compressed
+ // P2PK uncompressed - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "pk(" + EncodeSecret(uncompressedKey) + ")";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2PKH compressed - Legacy
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
@@ -90,9 +134,21 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
- // P2PKH uncompressed
+ // P2PKH compressed - Descriptor
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "pkh(" + EncodeSecret(keys[0]) + ")";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2PKH uncompressed - Legacy
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
@@ -109,9 +165,21 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
- // P2SH
+ // P2PKH uncompressed - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "pkh(" + EncodeSecret(uncompressedKey) + ")";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2SH - Legacy
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -136,9 +204,22 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
- // (P2PKH inside) P2SH inside P2SH (invalid)
+ // P2SH - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "sh(pkh(" + EncodeSecret(keys[0]) + "))";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // (P2PKH inside) P2SH inside P2SH (invalid) - Legacy
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -155,9 +236,18 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
- // (P2PKH inside) P2SH inside P2WSH (invalid)
+ // (P2PKH inside) P2SH inside P2SH (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "sh(sh(" + EncodeSecret(keys[0]) + "))";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, false);
+ BOOST_CHECK_EQUAL(spk_manager, nullptr);
+ }
+
+ // (P2PKH inside) P2SH inside P2WSH (invalid) - Legacy
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -174,9 +264,18 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
- // P2WPKH inside P2WSH (invalid)
+ // (P2PKH inside) P2SH inside P2WSH (invalid) - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "wsh(sh(" + EncodeSecret(keys[0]) + "))";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, false);
+ BOOST_CHECK_EQUAL(spk_manager, nullptr);
+ }
+
+ // P2WPKH inside P2WSH (invalid) - Legacy
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -191,9 +290,18 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
- // (P2PKH inside) P2WSH inside P2WSH (invalid)
+ // P2WPKH inside P2WSH (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "wsh(wpkh(" + EncodeSecret(keys[0]) + "))";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, false);
+ BOOST_CHECK_EQUAL(spk_manager, nullptr);
+ }
+
+ // (P2PKH inside) P2WSH inside P2WSH (invalid) - Legacy
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -210,9 +318,18 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
- // P2WPKH compressed
+ // (P2PKH inside) P2WSH inside P2WSH (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "wsh(wsh(" + EncodeSecret(keys[0]) + "))";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, false);
+ BOOST_CHECK_EQUAL(spk_manager, nullptr);
+ }
+
+ // P2WPKH compressed - Legacy
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -226,9 +343,21 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
- // P2WPKH uncompressed
+ // P2WPKH compressed - Descriptor
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "wpkh(" + EncodeSecret(keys[0]) + ")";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2WPKH uncompressed - Legacy
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -247,9 +376,18 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
- // scriptPubKey multisig
+ // P2WPKH uncompressed (invalid) - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "wpkh(" + EncodeSecret(uncompressedKey) + ")";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, false);
+ BOOST_CHECK_EQUAL(spk_manager, nullptr);
+ }
+
+ // scriptPubKey multisig - Legacy
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -282,9 +420,21 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
- // P2SH multisig
+ // scriptPubKey multisig - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ std::string desc_str = "multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + ")";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2SH multisig - Legacy
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -305,9 +455,23 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
- // P2WSH multisig with compressed keys
+ // P2SH multisig - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+
+ std::string desc_str = "sh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2WSH multisig with compressed keys - Legacy
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -334,9 +498,23 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
- // P2WSH multisig with uncompressed key
+ // P2WSH multisig with compressed keys - Descriptor
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+
+ std::string desc_str = "wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + "))";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ CScript redeemScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(redeemScript));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2WSH multisig with uncompressed key - Legacy
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -363,9 +541,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
}
- // P2WSH multisig wrapped in P2SH
+ // P2WSH multisig with uncompressed key (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+
+ std::string desc_str = "wsh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, false);
+ BOOST_CHECK_EQUAL(spk_manager, nullptr);
+ }
+
+ // P2WSH multisig wrapped in P2SH - Legacy
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -393,9 +581,86 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
}
+ // P2WSH multisig wrapped in P2SH - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+
+ std::string desc_str = "sh(wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + ")))";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
+ CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // Combo - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+
+ std::string desc_str = "combo(" + EncodeSecret(keys[0]) + ")";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ // Test P2PK
+ result = spk_manager->IsMine(GetScriptForRawPubKey(pubkeys[0]));
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+
+ // Test P2PKH
+ result = spk_manager->IsMine(GetScriptForDestination(PKHash(pubkeys[0])));
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+
+ // Test P2SH (combo descriptor does not describe P2SH)
+ CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Test P2WPKH
+ scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+
+ // P2SH-P2WPKH output
+ redeemScript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+
+ // Test P2TR (combo descriptor does not describe P2TR)
+ XOnlyPubKey xpk(pubkeys[0]);
+ Assert(xpk.IsFullyValid());
+ TaprootBuilder builder;
+ builder.Finalize(xpk);
+ WitnessV1Taproot output = builder.GetOutput();
+ scriptPubKey = GetScriptForDestination(output);
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // Taproot - Descriptor
+ {
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+
+ std::string desc_str = "tr(" + EncodeSecret(keys[0]) + ")";
+
+ auto spk_manager = CreateDescriptor(keystore, desc_str, true);
+
+ XOnlyPubKey xpk(pubkeys[0]);
+ Assert(xpk.IsFullyValid());
+ TaprootBuilder builder;
+ builder.Finalize(xpk);
+ WitnessV1Taproot output = builder.GetOutput();
+ scriptPubKey = GetScriptForDestination(output);
+ result = spk_manager->IsMine(scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
// OP_RETURN
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -410,7 +675,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unspendable
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -425,7 +690,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unknown
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -440,7 +705,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Nonstandard
{
- CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 62053ae8d2..9510f28282 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/scriptpubkeyman_tests.cpp b/src/wallet/test/scriptpubkeyman_tests.cpp
index a524b85ccb..90042f5252 100644
--- a/src/wallet/test/scriptpubkeyman_tests.cpp
+++ b/src/wallet/test/scriptpubkeyman_tests.cpp
@@ -18,7 +18,7 @@ BOOST_FIXTURE_TEST_SUITE(scriptpubkeyman_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(CanProvide)
{
// Set up wallet and keyman variables.
- CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
LegacyScriptPubKeyMan& keyman = *wallet.GetOrCreateLegacyScriptPubKeyMan();
// Make a 1 of 2 multisig script
diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp
index a75b014870..6e87d1cb49 100644
--- a/src/wallet/test/spend_tests.cpp
+++ b/src/wallet/test/spend_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,7 +18,7 @@ BOOST_FIXTURE_TEST_SUITE(spend_tests, WalletTestingSetup)
BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- auto wallet = CreateSyncedWallet(*m_node.chain, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), m_args, coinbaseKey);
+ auto wallet = CreateSyncedWallet(*m_node.chain, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), coinbaseKey);
// Check that a subtract-from-recipient transaction slightly less than the
// coinbase input amount does not create a change output (because it would
@@ -26,7 +26,7 @@ BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
// leftover input amount which would have been change to the recipient
// instead of the miner.
auto check_tx = [&wallet](CAmount leftover_input_amount) {
- CRecipient recipient{GetScriptForRawPubKey({}), 50 * COIN - leftover_input_amount, true /* subtract fee */};
+ CRecipient recipient{GetScriptForRawPubKey({}), 50 * COIN - leftover_input_amount, /*subtract_fee=*/true};
constexpr int RANDOM_CHANGE_POSITION = -1;
CCoinControl coin_control;
coin_control.m_feerate.emplace(10000);
@@ -112,5 +112,50 @@ BOOST_FIXTURE_TEST_CASE(FillInputToWeightTest, BasicTestingSetup)
// Note: We don't test the next boundary because of memory allocation constraints.
}
+BOOST_FIXTURE_TEST_CASE(wallet_duplicated_preset_inputs_test, TestChain100Setup)
+{
+ // Verify that the wallet's Coin Selection process does not include pre-selected inputs twice in a transaction.
+
+ // Add 4 spendable UTXO, 50 BTC each, to the wallet (total balance 200 BTC)
+ for (int i = 0; i < 4; i++) CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+ auto wallet = CreateSyncedWallet(*m_node.chain, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), coinbaseKey);
+
+ LOCK(wallet->cs_wallet);
+ auto available_coins = AvailableCoins(*wallet);
+ std::vector<COutput> coins = available_coins.All();
+ // Preselect the first 3 UTXO (150 BTC total)
+ std::set<COutPoint> preset_inputs = {coins[0].outpoint, coins[1].outpoint, coins[2].outpoint};
+
+ // Try to create a tx that spends more than what preset inputs + wallet selected inputs are covering for.
+ // The wallet can cover up to 200 BTC, and the tx target is 299 BTC.
+ std::vector<CRecipient> recipients = {{GetScriptForDestination(*Assert(wallet->GetNewDestination(OutputType::BECH32, "dummy"))),
+ /*nAmount=*/299 * COIN, /*fSubtractFeeFromAmount=*/true}};
+ CCoinControl coin_control;
+ coin_control.m_allow_other_inputs = true;
+ for (const auto& outpoint : preset_inputs) {
+ coin_control.Select(outpoint);
+ }
+
+ // Attempt to send 299 BTC from a wallet that only has 200 BTC. The wallet should exclude
+ // the preset inputs from the pool of available coins, realize that there is not enough
+ // money to fund the 299 BTC payment, and fail with "Insufficient funds".
+ //
+ // Even with SFFO, the wallet can only afford to send 200 BTC.
+ // If the wallet does not properly exclude preset inputs from the pool of available coins
+ // prior to coin selection, it may create a transaction that does not fund the full payment
+ // amount or, through SFFO, incorrectly reduce the recipient's amount by the difference
+ // between the original target and the wrongly counted inputs (in this case 99 BTC)
+ // so that the recipient's amount is no longer equal to the user's selected target of 299 BTC.
+
+ // First case, use 'subtract_fee_from_outputs=true'
+ util::Result<CreatedTransactionResult> res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control);
+ BOOST_CHECK(!res_tx.has_value());
+
+ // Second case, don't use 'subtract_fee_from_outputs'.
+ recipients[0].fSubtractFeeFromAmount = false;
+ res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control);
+ BOOST_CHECK(!res_tx.has_value());
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp
index ab72721f9d..b7bf312edf 100644
--- a/src/wallet/test/util.cpp
+++ b/src/wallet/test/util.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,14 +11,12 @@
#include <wallet/wallet.h>
#include <wallet/walletdb.h>
-#include <boost/test/unit_test.hpp>
-
#include <memory>
namespace wallet {
-std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, ArgsManager& args, const CKey& key)
+std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key)
{
- auto wallet = std::make_unique<CWallet>(&chain, "", args, CreateMockWalletDatabase());
+ auto wallet = std::make_unique<CWallet>(&chain, "", CreateMockWalletDatabase());
{
LOCK2(wallet->cs_wallet, ::cs_main);
wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash());
@@ -39,10 +37,46 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc
WalletRescanReserver reserver(*wallet);
reserver.reserve();
CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
- BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
- BOOST_CHECK_EQUAL(result.last_scanned_block, cchain.Tip()->GetBlockHash());
- BOOST_CHECK_EQUAL(*result.last_scanned_height, cchain.Height());
- BOOST_CHECK(result.last_failed_block.IsNull());
+ assert(result.status == CWallet::ScanResult::SUCCESS);
+ assert(result.last_scanned_block == cchain.Tip()->GetBlockHash());
+ assert(*result.last_scanned_height == cchain.Height());
+ assert(result.last_failed_block.IsNull());
return wallet;
}
+
+std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database, DatabaseOptions& options)
+{
+ auto new_database = CreateMockWalletDatabase(options);
+
+ // Get a cursor to the original database
+ auto batch = database.MakeBatch();
+ std::unique_ptr<wallet::DatabaseCursor> cursor = batch->GetNewCursor();
+
+ // Get a batch for the new database
+ auto new_batch = new_database->MakeBatch();
+
+ // Read all records from the original database and write them to the new one
+ while (true) {
+ DataStream key{};
+ DataStream value{};
+ DatabaseCursor::Status status = cursor->Next(key, value);
+ assert(status != DatabaseCursor::Status::FAIL);
+ if (status == DatabaseCursor::Status::DONE) break;
+ new_batch->Write(key, value);
+ }
+
+ return new_database;
+}
+
+std::string getnewaddress(CWallet& w)
+{
+ constexpr auto output_type = OutputType::BECH32;
+ return EncodeDestination(getNewDestination(w, output_type));
+}
+
+CTxDestination getNewDestination(CWallet& w, OutputType output_type)
+{
+ return *Assert(w.GetNewDestination(output_type, ""));
+}
+
} // namespace wallet
diff --git a/src/wallet/test/util.h b/src/wallet/test/util.h
index 712d0251cd..d726517e21 100644
--- a/src/wallet/test/util.h
+++ b/src/wallet/test/util.h
@@ -1,23 +1,36 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 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_TEST_UTIL_H
#define BITCOIN_WALLET_TEST_UTIL_H
+#include <script/standard.h>
#include <memory>
class ArgsManager;
class CChain;
class CKey;
+enum class OutputType;
namespace interfaces {
class Chain;
} // namespace interfaces
namespace wallet {
class CWallet;
+struct DatabaseOptions;
+class WalletDatabase;
+
+std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key);
+
+// Creates a copy of the provided database
+std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database, DatabaseOptions& options);
+
+/** Returns a new encoded destination from the wallet (hardcoded to BECH32) */
+std::string getnewaddress(CWallet& w);
+/** Returns a new destination, of an specific type, from the wallet */
+CTxDestination getNewDestination(CWallet& w, OutputType output_type);
-std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, ArgsManager& args, const CKey& key);
} // namespace wallet
#endif // BITCOIN_WALLET_TEST_UTIL_H
diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp
index 327c28412a..d5e75bb892 100644
--- a/src/wallet/test/wallet_crypto_tests.cpp
+++ b/src/wallet/test/wallet_crypto_tests.cpp
@@ -1,7 +1,8 @@
-// Copyright (c) 2014-2020 The Bitcoin Core developers
+// Copyright (c) 2014-2022 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/util/random.h>
#include <test/util/setup_common.h>
#include <util/strencodings.h>
#include <wallet/crypter.h>
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 38d23b6f91..2dd8f9ad33 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,7 +10,7 @@ namespace wallet {
WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
: TestingSetup(chainName),
m_wallet_loader{interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args))},
- m_wallet(m_node.chain.get(), "", m_args, CreateMockWalletDatabase())
+ m_wallet(m_node.chain.get(), "", CreateMockWalletDatabase())
{
m_wallet.LoadWallet();
m_chain_notifications_handler = m_node.chain->handleNotifications({ &m_wallet, [](CWallet*) {} });
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index e0b38a40e7..f1ef15a282 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 60fdbde71b..2e95a14807 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2021 The Bitcoin Core developers
+// Copyright (c) 2012-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -43,7 +43,7 @@ static_assert(WALLET_INCREMENTAL_RELAY_FEE >= DEFAULT_INCREMENTAL_RELAY_FEE, "wa
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
-static const std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
+static std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
{
DatabaseOptions options;
options.create_flags = WALLET_FLAG_DESCRIPTORS;
@@ -98,7 +98,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions fails to read an unknown start block.
{
- CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -119,7 +119,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions picks up transactions in both the old
// and new block files.
{
- CWallet wallet(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateMockWalletDatabase());
{
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -164,7 +164,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions only picks transactions in the new block
// file.
{
- CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -192,7 +192,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions scans no blocks.
{
- CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -232,7 +232,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
// before the missing block, and success for a key whose creation time is
// after.
{
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(newTip->nHeight, newTip->GetBlockHash()));
WalletContext context;
@@ -298,7 +298,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
{
WalletContext context;
context.args = &m_args;
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
{
auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
@@ -321,7 +321,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
// were scanned, and no prior blocks were scanned.
{
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
LOCK(wallet->cs_wallet);
wallet->SetupLegacyScriptPubKeyMan();
@@ -355,7 +355,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// debit functions.
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
- CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -527,7 +527,7 @@ public:
ListCoinsTestingSetup()
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- wallet = CreateSyncedWallet(*m_node.chain, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), m_args, coinbaseKey);
+ wallet = CreateSyncedWallet(*m_node.chain, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), coinbaseKey);
}
~ListCoinsTestingSetup()
@@ -587,7 +587,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
// returns the coin associated with the change address underneath the
// coinbaseKey pubkey, even though the change address has a different
// pubkey.
- AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */});
+ AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, /*subtract_fee=*/false});
{
LOCK(wallet->cs_wallet);
list = ListCoins(*wallet);
@@ -622,10 +622,50 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);
}
+void TestCoinsResult(ListCoinsTest& context, OutputType out_type, CAmount amount,
+ std::map<OutputType, size_t>& expected_coins_sizes)
+{
+ LOCK(context.wallet->cs_wallet);
+ util::Result<CTxDestination> dest = Assert(context.wallet->GetNewDestination(out_type, ""));
+ CWalletTx& wtx = context.AddTx(CRecipient{{GetScriptForDestination(*dest)}, amount, /*fSubtractFeeFromAmount=*/true});
+ CoinFilterParams filter;
+ filter.skip_locked = false;
+ CoinsResult available_coins = AvailableCoins(*context.wallet, nullptr, std::nullopt, filter);
+ // Lock outputs so they are not spent in follow-up transactions
+ for (uint32_t i = 0; i < wtx.tx->vout.size(); i++) context.wallet->LockCoin({wtx.GetHash(), i});
+ for (const auto& [type, size] : expected_coins_sizes) BOOST_CHECK_EQUAL(size, available_coins.coins[type].size());
+}
+
+BOOST_FIXTURE_TEST_CASE(BasicOutputTypesTest, ListCoinsTest)
+{
+ std::map<OutputType, size_t> expected_coins_sizes;
+ for (const auto& out_type : OUTPUT_TYPES) { expected_coins_sizes[out_type] = 0U; }
+
+ // Verify our wallet has one usable coinbase UTXO before starting
+ // This UTXO is a P2PK, so it should show up in the Other bucket
+ expected_coins_sizes[OutputType::UNKNOWN] = 1U;
+ CoinsResult available_coins = WITH_LOCK(wallet->cs_wallet, return AvailableCoins(*wallet));
+ BOOST_CHECK_EQUAL(available_coins.Size(), expected_coins_sizes[OutputType::UNKNOWN]);
+ BOOST_CHECK_EQUAL(available_coins.coins[OutputType::UNKNOWN].size(), expected_coins_sizes[OutputType::UNKNOWN]);
+
+ // We will create a self transfer for each of the OutputTypes and
+ // verify it is put in the correct bucket after running GetAvailablecoins
+ //
+ // For each OutputType, We expect 2 UTXOs in our wallet following the self transfer:
+ // 1. One UTXO as the recipient
+ // 2. One UTXO from the change, due to payment address matching logic
+
+ for (const auto& out_type : OUTPUT_TYPES) {
+ if (out_type == OutputType::UNKNOWN) continue;
+ expected_coins_sizes[out_type] = 2U;
+ TestCoinsResult(*this, out_type, 1 * COIN, expected_coins_sizes);
+ }
+}
+
BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{
{
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
@@ -633,7 +673,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
BOOST_CHECK(!wallet->GetNewDestination(OutputType::BECH32, ""));
}
{
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet->SetMinVersion(FEATURE_LATEST);
@@ -696,10 +736,10 @@ BOOST_FIXTURE_TEST_CASE(wallet_descriptor_test, BasicTestingSetup)
std::vector<unsigned char> malformed_record;
CVectorWriter vw(0, 0, malformed_record, 0);
vw << std::string("notadescriptor");
- vw << (uint64_t)0;
- vw << (int32_t)0;
- vw << (int32_t)0;
- vw << (int32_t)1;
+ vw << uint64_t{0};
+ vw << int32_t{0};
+ vw << int32_t{0};
+ vw << int32_t{1};
SpanReader vr{0, 0, malformed_record};
WalletDescriptor w_desc;
@@ -867,24 +907,28 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup)
TestUnloadWallet(std::move(wallet));
}
+class FailCursor : public DatabaseCursor
+{
+public:
+ Status Next(DataStream& key, DataStream& value) override { return Status::FAIL; }
+};
+
/** RAII class that provides access to a FailDatabase. Which fails if needed. */
class FailBatch : public DatabaseBatch
{
private:
bool m_pass{true};
- bool ReadKey(CDataStream&& key, CDataStream& value) override { return m_pass; }
- bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite=true) override { return m_pass; }
- bool EraseKey(CDataStream&& key) override { return m_pass; }
- bool HasKey(CDataStream&& key) override { return m_pass; }
+ bool ReadKey(DataStream&& key, DataStream& value) override { return m_pass; }
+ bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override { return m_pass; }
+ bool EraseKey(DataStream&& key) override { return m_pass; }
+ bool HasKey(DataStream&& key) override { return m_pass; }
public:
explicit FailBatch(bool pass) : m_pass(pass) {}
void Flush() override {}
void Close() override {}
- bool StartCursor() override { return true; }
- bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) override { return false; }
- void CloseCursor() override {}
+ std::unique_ptr<DatabaseCursor> GetNewCursor() override { return std::make_unique<FailCursor>(); }
bool TxnBegin() override { return false; }
bool TxnCommit() override { return false; }
bool TxnAbort() override { return false; }
@@ -917,7 +961,7 @@ public:
*/
BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
{
- CWallet wallet(m_node.chain.get(), "", m_args, std::make_unique<FailDatabase>());
+ CWallet wallet(m_node.chain.get(), "", std::make_unique<FailDatabase>());
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -946,7 +990,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
mtx.vin.clear();
mtx.vin.push_back(CTxIn(tx_id_to_spend, 0));
- wallet.transactionAddedToMempool(MakeTransactionRef(mtx), 0);
+ wallet.transactionAddedToMempool(MakeTransactionRef(mtx));
const uint256& good_tx_id = mtx.GetHash();
{
@@ -967,7 +1011,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
static_cast<FailDatabase&>(wallet.GetDatabase()).m_pass = false;
mtx.vin.clear();
mtx.vin.push_back(CTxIn(good_tx_id, 0));
- BOOST_CHECK_EXCEPTION(wallet.transactionAddedToMempool(MakeTransactionRef(mtx), 0),
+ BOOST_CHECK_EXCEPTION(wallet.transactionAddedToMempool(MakeTransactionRef(mtx)),
std::runtime_error,
HasReason("DB error adding transaction to wallet, write failed"));
}
diff --git a/src/wallet/test/walletdb_tests.cpp b/src/wallet/test/walletdb_tests.cpp
index e251a3a0e4..21842fe780 100644
--- a/src/wallet/test/walletdb_tests.cpp
+++ b/src/wallet/test/walletdb_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2020 The Bitcoin Core developers
+// Copyright (c) 2012-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/walletload_tests.cpp b/src/wallet/test/walletload_tests.cpp
index f45b69a418..9f5a4b14d3 100644
--- a/src/wallet/test/walletload_tests.cpp
+++ b/src/wallet/test/walletload_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php.
+#include <wallet/test/util.h>
#include <wallet/wallet.h>
#include <test/util/setup_common.h>
@@ -45,10 +46,146 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_unknown_descriptor, TestingSetup)
{
// Now try to load the wallet and verify the error.
- const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", m_args, std::move(database)));
+ const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::UNKNOWN_DESCRIPTOR);
}
}
+bool HasAnyRecordOfType(WalletDatabase& db, const std::string& key)
+{
+ std::unique_ptr<DatabaseBatch> batch = db.MakeBatch(false);
+ BOOST_CHECK(batch);
+ std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
+ BOOST_CHECK(cursor);
+ while (true) {
+ DataStream ssKey{};
+ DataStream ssValue{};
+ DatabaseCursor::Status status = cursor->Next(ssKey, ssValue);
+ assert(status != DatabaseCursor::Status::FAIL);
+ if (status == DatabaseCursor::Status::DONE) break;
+ std::string type;
+ ssKey >> type;
+ if (type == key) return true;
+ }
+ return false;
+}
+
+BOOST_FIXTURE_TEST_CASE(wallet_load_verif_crypted_key_checksum, TestingSetup)
+{
+ // The test duplicates the db so each case has its own db instance.
+ int NUMBER_OF_TESTS = 4;
+ std::vector<std::unique_ptr<WalletDatabase>> dbs;
+ CKey first_key;
+ auto get_db = [](std::vector<std::unique_ptr<WalletDatabase>>& dbs) {
+ std::unique_ptr<WalletDatabase> db = std::move(dbs.back());
+ dbs.pop_back();
+ return db;
+ };
+
+ { // Context setup.
+ // Create and encrypt legacy wallet
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", CreateMockWalletDatabase()));
+ LOCK(wallet->cs_wallet);
+ auto legacy_spkm = wallet->GetOrCreateLegacyScriptPubKeyMan();
+ BOOST_CHECK(legacy_spkm->SetupGeneration(true));
+
+ // Get the first key in the wallet
+ CTxDestination dest = *Assert(legacy_spkm->GetNewDestination(OutputType::LEGACY));
+ CKeyID key_id = GetKeyForDestination(*legacy_spkm, dest);
+ BOOST_CHECK(legacy_spkm->GetKey(key_id, first_key));
+
+ // Encrypt the wallet and duplicate database
+ BOOST_CHECK(wallet->EncryptWallet("encrypt"));
+ wallet->Flush();
+
+ DatabaseOptions options;
+ for (int i=0; i < NUMBER_OF_TESTS; i++) {
+ dbs.emplace_back(DuplicateMockDatabase(wallet->GetDatabase(), options));
+ }
+ }
+
+ {
+ // First test case:
+ // Erase all the crypted keys from db and unlock the wallet.
+ // The wallet will only re-write the crypted keys to db if any checksum is missing at load time.
+ // So, if any 'ckey' record re-appears on db, then the checksums were not properly calculated, and we are re-writing
+ // the records every time that 'CWallet::Unlock' gets called, which is not good.
+
+ // Load the wallet and check that is encrypted
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", get_db(dbs)));
+ BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::LOAD_OK);
+ BOOST_CHECK(wallet->IsCrypted());
+ BOOST_CHECK(HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY));
+
+ // Now delete all records and check that the 'Unlock' function doesn't re-write them
+ BOOST_CHECK(wallet->GetLegacyScriptPubKeyMan()->DeleteRecords());
+ BOOST_CHECK(!HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY));
+ BOOST_CHECK(wallet->Unlock("encrypt"));
+ BOOST_CHECK(!HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY));
+ }
+
+ {
+ // Second test case:
+ // Verify that loading up a 'ckey' with no checksum triggers a complete re-write of the crypted keys.
+ std::unique_ptr<WalletDatabase> db = get_db(dbs);
+ {
+ std::unique_ptr<DatabaseBatch> batch = db->MakeBatch(false);
+ std::pair<std::vector<unsigned char>, uint256> value;
+ BOOST_CHECK(batch->Read(std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey()), value));
+
+ const auto key = std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey());
+ BOOST_CHECK(batch->Write(key, value.first, /*fOverwrite=*/true));
+ }
+
+ // Load the wallet and check that is encrypted
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(db)));
+ BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::LOAD_OK);
+ BOOST_CHECK(wallet->IsCrypted());
+ BOOST_CHECK(HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY));
+
+ // Now delete all ckey records and check that the 'Unlock' function re-writes them
+ // (this is because the wallet, at load time, found a ckey record with no checksum)
+ BOOST_CHECK(wallet->GetLegacyScriptPubKeyMan()->DeleteRecords());
+ BOOST_CHECK(!HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY));
+ BOOST_CHECK(wallet->Unlock("encrypt"));
+ BOOST_CHECK(HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY));
+ }
+
+ {
+ // Third test case:
+ // Verify that loading up a 'ckey' with an invalid checksum throws an error.
+ std::unique_ptr<WalletDatabase> db = get_db(dbs);
+ {
+ std::unique_ptr<DatabaseBatch> batch = db->MakeBatch(false);
+ std::vector<unsigned char> crypted_data;
+ BOOST_CHECK(batch->Read(std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey()), crypted_data));
+
+ // Write an invalid checksum
+ std::pair<std::vector<unsigned char>, uint256> value = std::make_pair(crypted_data, uint256::ONE);
+ const auto key = std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey());
+ BOOST_CHECK(batch->Write(key, value, /*fOverwrite=*/true));
+ }
+
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(db)));
+ BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::CORRUPT);
+ }
+
+ {
+ // Fourth test case:
+ // Verify that loading up a 'ckey' with an invalid pubkey throws an error
+ std::unique_ptr<WalletDatabase> db = get_db(dbs);
+ {
+ CPubKey invalid_key;
+ BOOST_ASSERT(!invalid_key.IsValid());
+ const auto key = std::make_pair(DBKeys::CRYPTED_KEY, invalid_key);
+ std::pair<std::vector<unsigned char>, uint256> value;
+ BOOST_CHECK(db->MakeBatch(false)->Write(key, value, /*fOverwrite=*/true));
+ }
+
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(db)));
+ BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::CORRUPT);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h
index 27983e356d..290ef4eaa9 100644
--- a/src/wallet/transaction.h
+++ b/src/wallet/transaction.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Bitcoin Core developers
+// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -293,6 +293,7 @@ public:
bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }
bool isConflicted() const { return state<TxStateConflicted>(); }
+ bool isInactive() const { return state<TxStateInactive>(); }
bool isUnconfirmed() const { return !isAbandoned() && !isConflicted() && !isConfirmed(); }
bool isConfirmed() const { return state<TxStateConfirmed>(); }
const uint256& GetHash() const { return tx->GetHash(); }
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 6ed2373294..ef8fb29e64 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1,10 +1,11 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 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 <wallet/wallet.h>
+#include <blockfilter.h>
#include <chain.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
@@ -21,9 +22,11 @@
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <psbt.h>
+#include <random.h>
#include <script/descriptor.h>
#include <script/script.h>
#include <script/signingprovider.h>
+#include <support/cleanse.h>
#include <txmempool.h>
#include <util/bip32.h>
#include <util/check.h>
@@ -32,6 +35,7 @@
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/string.h>
+#include <util/system.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/context.h>
@@ -124,7 +128,7 @@ bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet
interfaces::Chain& chain = wallet->chain();
std::string name = wallet->GetName();
- // Unregister with the validation interface which also drops shared ponters.
+ // Unregister with the validation interface which also drops shared pointers.
wallet->m_chain_notifications_handler.reset();
LOCK(context.wallets_mutex);
std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet);
@@ -169,7 +173,7 @@ std::unique_ptr<interfaces::Handler> HandleLoadWallet(WalletContext& context, Lo
{
LOCK(context.wallets_mutex);
auto it = context.wallet_load_fns.emplace(context.wallet_load_fns.end(), std::move(load_wallet));
- return interfaces::MakeHandler([&context, it] { LOCK(context.wallets_mutex); context.wallet_load_fns.erase(it); });
+ return interfaces::MakeCleanupHandler([&context, it] { LOCK(context.wallets_mutex); context.wallet_load_fns.erase(it); });
}
void NotifyWalletLoaded(WalletContext& context, const std::shared_ptr<CWallet>& wallet)
@@ -239,7 +243,7 @@ std::shared_ptr<CWallet> LoadWalletInternal(WalletContext& context, const std::s
}
context.chain->initMessage(_("Loading wallet…").translated);
- const std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings);
+ std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings);
if (!wallet) {
error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error;
status = DatabaseStatus::FAILED_LOAD;
@@ -260,6 +264,64 @@ std::shared_ptr<CWallet> LoadWalletInternal(WalletContext& context, const std::s
return nullptr;
}
}
+
+class FastWalletRescanFilter
+{
+public:
+ FastWalletRescanFilter(const CWallet& wallet) : m_wallet(wallet)
+ {
+ // fast rescanning via block filters is only supported by descriptor wallets right now
+ assert(!m_wallet.IsLegacy());
+
+ // create initial filter with scripts from all ScriptPubKeyMans
+ for (auto spkm : m_wallet.GetAllScriptPubKeyMans()) {
+ auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
+ assert(desc_spkm != nullptr);
+ AddScriptPubKeys(desc_spkm);
+ // save each range descriptor's end for possible future filter updates
+ if (desc_spkm->IsHDEnabled()) {
+ m_last_range_ends.emplace(desc_spkm->GetID(), desc_spkm->GetEndRange());
+ }
+ }
+ }
+
+ void UpdateIfNeeded()
+ {
+ // repopulate filter with new scripts if top-up has happened since last iteration
+ for (const auto& [desc_spkm_id, last_range_end] : m_last_range_ends) {
+ auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(m_wallet.GetScriptPubKeyMan(desc_spkm_id))};
+ assert(desc_spkm != nullptr);
+ int32_t current_range_end{desc_spkm->GetEndRange()};
+ if (current_range_end > last_range_end) {
+ AddScriptPubKeys(desc_spkm, last_range_end);
+ m_last_range_ends.at(desc_spkm->GetID()) = current_range_end;
+ }
+ }
+ }
+
+ std::optional<bool> MatchesBlock(const uint256& block_hash) const
+ {
+ return m_wallet.chain().blockFilterMatchesAny(BlockFilterType::BASIC, block_hash, m_filter_set);
+ }
+
+private:
+ const CWallet& m_wallet;
+ /** Map for keeping track of each range descriptor's last seen end range.
+ * This information is used to detect whether new addresses were derived
+ * (that is, if the current end range is larger than the saved end range)
+ * after processing a block and hence a filter set update is needed to
+ * take possible keypool top-ups into account.
+ */
+ std::map<uint256, int32_t> m_last_range_ends;
+ GCSFilter::ElementSet m_filter_set;
+
+ void AddScriptPubKeys(const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
+ {
+ for (const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
+ m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
+ }
+ }
+};
} // namespace
std::shared_ptr<CWallet> LoadWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
@@ -321,7 +383,7 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string&
// Make the wallet
context.chain->initMessage(_("Loading wallet…").translated);
- const std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), wallet_creation_flags, error, warnings);
+ std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), wallet_creation_flags, error, warnings);
if (!wallet) {
error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error;
status = DatabaseStatus::FAILED_CREATE;
@@ -412,8 +474,7 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& b
error += strprintf(Untranslated("Unexpected exception: %s"), e.what());
}
if (!wallet) {
- fs::remove(wallet_file);
- fs::remove(wallet_path);
+ fs::remove_all(wallet_path);
}
return wallet;
@@ -491,7 +552,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
bool fWasLocked = IsLocked();
{
- LOCK(cs_wallet);
+ LOCK2(m_relock_mutex, cs_wallet);
Lock();
CCrypter crypter;
@@ -588,8 +649,7 @@ bool CWallet::HasWalletSpend(const CTransactionRef& tx) const
AssertLockHeld(cs_wallet);
const uint256& txid = tx->GetHash();
for (unsigned int i = 0; i < tx->vout.size(); ++i) {
- auto iter = mapTxSpends.find(COutPoint(txid, i));
- if (iter != mapTxSpends.end()) {
+ if (IsSpent(COutPoint(txid, i))) {
return true;
}
}
@@ -727,7 +787,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
return false;
{
- LOCK(cs_wallet);
+ LOCK2(m_relock_mutex, cs_wallet);
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
WalletBatch* encrypted_batch = new WalletBatch(GetDatabase());
if (!encrypted_batch->TxnBegin()) {
@@ -1007,6 +1067,33 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
}
}
+ // Mark inactive coinbase transactions and their descendants as abandoned
+ if (wtx.IsCoinBase() && wtx.isInactive()) {
+ std::vector<CWalletTx*> txs{&wtx};
+
+ TxStateInactive inactive_state = TxStateInactive{/*abandoned=*/true};
+
+ while (!txs.empty()) {
+ CWalletTx* desc_tx = txs.back();
+ txs.pop_back();
+ desc_tx->m_state = inactive_state;
+ // Break caches since we have changed the state
+ desc_tx->MarkDirty();
+ batch.WriteTx(*desc_tx);
+ MarkInputsDirty(desc_tx->tx);
+ for (unsigned int i = 0; i < desc_tx->tx->vout.size(); ++i) {
+ COutPoint outpoint(desc_tx->GetHash(), i);
+ std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
+ for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
+ const auto wit = mapWallet.find(it->second);
+ if (wit != mapWallet.end()) {
+ txs.push_back(&wit->second);
+ }
+ }
+ }
+ }
+ }
+
//// debug print
WalletLogPrintf("AddToWallet %s %s%s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
@@ -1023,7 +1110,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
#if HAVE_SYSTEM
// notify an external script when a wallet transaction comes in or is updated
- std::string strCmd = m_args.GetArg("-walletnotify", "");
+ std::string strCmd = m_notify_tx_changed_script;
if (!strCmd.empty())
{
@@ -1216,7 +1303,11 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
wtx.MarkDirty();
batch.WriteTx(wtx);
NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
- // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
+ // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too.
+ // States are not permanent, so these transactions can become unabandoned if they are re-added to the
+ // mempool, or confirmed in a block, or conflicted.
+ // Note: If the reorged coinbase is re-added to the main chain, the descendants that have not had their
+ // states change will remain abandoned and will require manual broadcast if the user wants them.
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(now, i));
for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
@@ -1295,7 +1386,7 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const SyncTxState& sta
MarkInputsDirty(ptx);
}
-void CWallet::transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {
+void CWallet::transactionAddedToMempool(const CTransactionRef& tx) {
LOCK(cs_wallet);
SyncTransaction(tx, TxStateInMempool{});
@@ -1305,7 +1396,7 @@ void CWallet::transactionAddedToMempool(const CTransactionRef& tx, uint64_t memp
}
}
-void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {
+void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {
LOCK(cs_wallet);
auto it = mapWallet.find(tx->GetHash());
if (it != mapWallet.end()) {
@@ -1351,7 +1442,7 @@ void CWallet::blockConnected(const interfaces::BlockInfo& block)
m_last_block_processed = block.hash;
for (size_t index = 0; index < block.data->vtx.size(); index++) {
SyncTransaction(block.data->vtx[index], TxStateConfirmed{block.hash, block.height, static_cast<int>(index)});
- transactionRemovedFromMempool(block.data->vtx[index], MemPoolRemovalReason::BLOCK, 0 /* mempool_sequence */);
+ transactionRemovedFromMempool(block.data->vtx[index], MemPoolRemovalReason::BLOCK);
}
}
@@ -1551,15 +1642,15 @@ void CWallet::InitWalletFlags(uint64_t flags)
// Helper for producing a max-sized low-S low-R signature (eg 71 bytes)
// or a max-sized low-S signature (e.g. 72 bytes) depending on coin_control
-bool DummySignInput(const SigningProvider& provider, CTxIn &tx_in, const CTxOut &txout, const CCoinControl* coin_control)
+bool DummySignInput(const SigningProvider& provider, CTxIn &tx_in, const CTxOut &txout, bool can_grind_r, const CCoinControl* coin_control)
{
// Fill in dummy signatures for fee calculation.
const CScript& scriptPubKey = txout.scriptPubKey;
SignatureData sigdata;
- // Use max sig if watch only inputs were used or if this particular input is an external input
- // to ensure a sufficient fee is attained for the requested feerate.
- const bool use_max_sig = coin_control && (coin_control->fAllowWatchOnly || coin_control->IsExternalSelected(tx_in.prevout));
+ // Use max sig if watch only inputs were used, if this particular input is an external input,
+ // or if this wallet uses an external signer, to ensure a sufficient fee is attained for the requested feerate.
+ const bool use_max_sig = coin_control && (coin_control->fAllowWatchOnly || coin_control->IsExternalSelected(tx_in.prevout) || !can_grind_r);
if (!ProduceSignature(provider, use_max_sig ? DUMMY_MAXIMUM_SIGNATURE_CREATOR : DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigdata)) {
return false;
}
@@ -1615,6 +1706,7 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut>
{
// Fill in dummy signatures for fee calculation.
int nIn = 0;
+ const bool can_grind_r = CanGrindR();
for (const auto& txout : txouts)
{
CTxIn& txin = txNew.vin[nIn];
@@ -1627,8 +1719,8 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut>
continue;
}
const std::unique_ptr<SigningProvider> provider = GetSolvingProvider(txout.scriptPubKey);
- if (!provider || !DummySignInput(*provider, txin, txout, coin_control)) {
- if (!coin_control || !DummySignInput(coin_control->m_external_provider, txin, txout, coin_control)) {
+ if (!provider || !DummySignInput(*provider, txin, txout, can_grind_r, coin_control)) {
+ if (!coin_control || !DummySignInput(coin_control->m_external_provider, txin, txout, can_grind_r, coin_control)) {
return false;
}
}
@@ -1754,7 +1846,11 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
uint256 block_hash = start_block;
ScanResult result;
- WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString());
+ std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
+ if (!IsLegacy() && chain().hasBlockFilterIndex(BlockFilterType::BASIC)) fast_rescan_filter = std::make_unique<FastWalletRescanFilter>(*this);
+
+ WalletLogPrintf("Rescan started from block %s... (%s)\n", start_block.ToString(),
+ fast_rescan_filter ? "fast variant using block filters" : "slow variant inspecting all blocks");
fAbortRescan = false;
ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if rescan required on startup (e.g. due to corruption)
@@ -1781,9 +1877,22 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
}
- // Read block data
- CBlock block;
- chain().findBlock(block_hash, FoundBlock().data(block));
+ bool fetch_block{true};
+ if (fast_rescan_filter) {
+ fast_rescan_filter->UpdateIfNeeded();
+ auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)};
+ if (matches_block.has_value()) {
+ if (*matches_block) {
+ LogPrint(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (filter matched)\n", block_height, block_hash.ToString());
+ } else {
+ result.last_scanned_block = block_hash;
+ result.last_scanned_height = block_height;
+ fetch_block = false;
+ }
+ } else {
+ LogPrint(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.ToString());
+ }
+ }
// Find next block separately from reading data above, because reading
// is slow and there might be a reorg while it is read.
@@ -1792,35 +1901,41 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
uint256 next_block_hash;
chain().findBlock(block_hash, FoundBlock().inActiveChain(block_still_active).nextBlock(FoundBlock().inActiveChain(next_block).hash(next_block_hash)));
- if (!block.IsNull()) {
- LOCK(cs_wallet);
- if (!block_still_active) {
- // Abort scan if current block is no longer active, to prevent
- // marking transactions as coming from the wrong block.
- 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], TxStateConfirmed{block_hash, block_height, static_cast<int>(posInBlock)}, fUpdate, /*rescanning_old_block=*/true);
- }
- // scan succeeded, record block as most recent successfully scanned
- result.last_scanned_block = block_hash;
- result.last_scanned_height = block_height;
+ if (fetch_block) {
+ // Read block data
+ CBlock block;
+ chain().findBlock(block_hash, FoundBlock().data(block));
+
+ if (!block.IsNull()) {
+ LOCK(cs_wallet);
+ if (!block_still_active) {
+ // Abort scan if current block is no longer active, to prevent
+ // marking transactions as coming from the wrong block.
+ 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], TxStateConfirmed{block_hash, block_height, static_cast<int>(posInBlock)}, fUpdate, /*rescanning_old_block=*/true);
+ }
+ // scan succeeded, record block as most recent successfully scanned
+ result.last_scanned_block = block_hash;
+ result.last_scanned_height = block_height;
- if (save_progress && next_interval) {
- CBlockLocator loc = m_chain->getActiveChainLocator(block_hash);
+ if (save_progress && next_interval) {
+ CBlockLocator loc = m_chain->getActiveChainLocator(block_hash);
- if (!loc.IsNull()) {
- WalletLogPrintf("Saving scan progress %d.\n", block_height);
- WalletBatch batch(GetDatabase());
- batch.WriteBestBlock(loc);
+ if (!loc.IsNull()) {
+ WalletLogPrintf("Saving scan progress %d.\n", block_height);
+ WalletBatch batch(GetDatabase());
+ batch.WriteBestBlock(loc);
+ }
}
+ } else {
+ // could not scan block, keep scanning but record this block as the most recent failure
+ result.last_failed_block = block_hash;
+ result.status = ScanResult::FAILURE;
}
- } else {
- // could not scan block, keep scanning but record this block as the most recent failure
- result.last_failed_block = block_hash;
- result.status = ScanResult::FAILURE;
}
if (max_height && block_height >= *max_height) {
break;
@@ -1903,11 +2018,29 @@ std::set<uint256> CWallet::GetTxConflicts(const CWalletTx& wtx) const
return result;
}
+bool CWallet::ShouldResend() const
+{
+ // Don't attempt to resubmit if the wallet is configured to not broadcast
+ if (!fBroadcastTransactions) return false;
+
+ // During reindex, importing and IBD, old wallet transactions become
+ // unconfirmed. Don't resend them as that would spam other nodes.
+ // We only allow forcing mempool submission when not relaying to avoid this spam.
+ if (!chain().isReadyToBroadcast()) return false;
+
+ // Do this infrequently and randomly to avoid giving away
+ // that these are our transactions.
+ if (NodeClock::now() < m_next_resend) return false;
+
+ return true;
+}
+
+NodeClock::time_point CWallet::GetDefaultNextResend() { return FastRandomContext{}.rand_uniform_delay(NodeClock::now() + 12h, 24h); }
+
// Resubmit transactions from the wallet to the mempool, optionally asking the
// mempool to relay them. On startup, we will do this for all unconfirmed
// transactions but will not ask the mempool to relay them. We do this on startup
-// to ensure that our own mempool is aware of our transactions, and to also
-// initialize m_next_resend so that the actual rebroadcast is scheduled. There
+// to ensure that our own mempool is aware of our transactions. There
// is a privacy side effect here as not broadcasting on startup also means that we won't
// inform the world of our wallet's state, particularly if the wallet (or node) is not
// yet synced.
@@ -1934,17 +2067,6 @@ void CWallet::ResubmitWalletTransactions(bool relay, bool force)
// even if forcing.
if (!fBroadcastTransactions) return;
- // During reindex, importing and IBD, old wallet transactions become
- // unconfirmed. Don't resend them as that would spam other nodes.
- // We only allow forcing mempool submission when not relaying to avoid this spam.
- if (!force && relay && !chain().isReadyToBroadcast()) return;
-
- // Do this infrequently and randomly to avoid giving away
- // that these are our transactions.
- if (!force && GetTime() < m_next_resend) return;
- // resend 12-36 hours from now, ~1 day on average.
- m_next_resend = GetTime() + (12 * 60 * 60) + GetRand(24 * 60 * 60);
-
int submitted_tx_count = 0;
{ // cs_wallet scope
@@ -1957,7 +2079,7 @@ void CWallet::ResubmitWalletTransactions(bool relay, bool force)
// Only rebroadcast unconfirmed txs
if (!wtx.isUnconfirmed()) continue;
- // attempt to rebroadcast all txes more than 5 minutes older than
+ // Attempt to rebroadcast all txes more than 5 minutes older than
// the last block, or all txs if forcing.
if (!force && wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
to_submit.insert(&wtx);
@@ -1979,7 +2101,9 @@ void CWallet::ResubmitWalletTransactions(bool relay, bool force)
void MaybeResendWalletTxs(WalletContext& context)
{
for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
+ if (!pwallet->ShouldResend()) continue;
pwallet->ResubmitWalletTransactions(/*relay=*/true, /*force=*/false);
+ pwallet->SetNextResend();
}
}
@@ -2371,12 +2495,11 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
util::Result<CTxDestination> CWallet::GetNewDestination(const OutputType type, const std::string label)
{
LOCK(cs_wallet);
- auto spk_man = GetScriptPubKeyMan(type, false /* internal */);
+ auto spk_man = GetScriptPubKeyMan(type, /*internal=*/false);
if (!spk_man) {
return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};
}
- spk_man->TopUp();
auto op_dest = spk_man->GetNewDestination(type);
if (op_dest) {
SetAddressBook(*op_dest, label, "receive");
@@ -2470,10 +2593,7 @@ util::Result<CTxDestination> ReserveDestination::GetReservedDestination(bool int
return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};
}
- if (nIndex == -1)
- {
- m_spk_man->TopUp();
-
+ if (nIndex == -1) {
CKeyPool keypool;
auto op_address = m_spk_man->GetReservedDestination(type, internal, nIndex, keypool);
if (!op_address) return op_address;
@@ -2796,7 +2916,11 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
const auto start{SteadyClock::now()};
// TODO: Can't use std::make_shared because we need a custom deleter but
// should be possible to use std::allocate_shared.
- const std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, args, std::move(database)), ReleaseWallet);
+ std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, std::move(database)), ReleaseWallet);
+ walletInstance->m_keypool_size = std::max(args.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{1});
+ walletInstance->m_notify_tx_changed_script = args.GetArg("-walletnotify", "");
+
+ // Load wallet
bool rescan_required = false;
DBErrors nLoadWalletRet = walletInstance->LoadWallet();
if (nLoadWalletRet != DBErrors::LOAD_OK) {
@@ -2831,6 +2955,10 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
"The wallet might had been created on a newer version.\n"
"Please try running the latest software version.\n"), walletFile);
return nullptr;
+ } else if (nLoadWalletRet == DBErrors::UNEXPECTED_LEGACY_ENTRY) {
+ error = strprintf(_("Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
+ "The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
+ return nullptr;
} else {
error = strprintf(_("Error loading %s"), walletFile);
return nullptr;
@@ -2905,7 +3033,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
if (args.IsArgSet("-mintxfee")) {
std::optional<CAmount> min_tx_fee = ParseMoney(args.GetArg("-mintxfee", ""));
- if (!min_tx_fee || min_tx_fee.value() == 0) {
+ if (!min_tx_fee) {
error = AmountErrMsg("mintxfee", args.GetArg("-mintxfee", ""));
return nullptr;
} else if (min_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
@@ -3092,6 +3220,24 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf
if (tip_height && *tip_height != rescan_height)
{
+ // No need to read and scan block if block was created before
+ // our wallet birthday (as adjusted for block time variability)
+ std::optional<int64_t> time_first_key;
+ for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
+ int64_t time = spk_man->GetTimeFirstKey();
+ if (!time_first_key || time < *time_first_key) time_first_key = time;
+ }
+ if (time_first_key) {
+ FoundBlock found = FoundBlock().height(rescan_height);
+ chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, found);
+ if (!found.found) {
+ // We were unable to find a block that had a time more recent than our earliest timestamp
+ // or a height higher than the wallet was synced to, indicating that the wallet is newer than the
+ // current chain tip. Skip rescanning in this case.
+ rescan_height = *tip_height;
+ }
+ }
+
// Technically we could execute the code below in any case, but performing the
// `while` loop below can make startup very slow, so only check blocks on disk
// if necessary.
@@ -3111,12 +3257,14 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf
// If a block is pruned after this check, we will load the wallet,
// but fail the rescan with a generic error.
- error = chain.hasAssumedValidChain() ?
- _(
- "Assumed-valid: last wallet synchronisation goes beyond "
- "available block data. You need to wait for the background "
- "validation chain to download more blocks.") :
- _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
+ error = chain.havePruned() ?
+ _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)") :
+ strprintf(_(
+ "Error loading wallet. Wallet requires blocks to be downloaded, "
+ "and software does not currently support loading wallets while "
+ "blocks are being downloaded out of order when using assumeutxo "
+ "snapshots. Wallet should be able to load successfully after "
+ "node sync reaches height %s"), block_height);
return false;
}
}
@@ -3124,17 +3272,6 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf
chain.initMessage(_("Rescanning…").translated);
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)
- std::optional<int64_t> time_first_key;
- for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
- int64_t time = spk_man->GetTimeFirstKey();
- if (!time_first_key || time < *time_first_key) time_first_key = time;
- }
- if (time_first_key) {
- chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, FoundBlock().height(rescan_height));
- }
-
{
WalletRescanReserver reserver(*walletInstance);
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/true).status)) {
@@ -3196,14 +3333,12 @@ bool CWallet::UpgradeWallet(int version, bilingual_str& error)
void CWallet::postInitProcess()
{
- LOCK(cs_wallet);
-
// Add wallet transactions that aren't already in a block to mempool
// Do this here as mempool requires genesis block to be loaded
ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
// Update wallet transactions with current mempool transactions.
- chain().requestMempoolTransactions(*this);
+ WITH_LOCK(cs_wallet, chain().requestMempoolTransactions(*this));
}
bool CWallet::BackupWallet(const std::string& strDest) const
@@ -3278,8 +3413,11 @@ bool CWallet::Lock()
return false;
{
- LOCK(cs_wallet);
- vMasterKey.clear();
+ LOCK2(m_relock_mutex, cs_wallet);
+ if (!vMasterKey.empty()) {
+ memory_cleanse(vMasterKey.data(), vMasterKey.size() * sizeof(decltype(vMasterKey)::value_type));
+ vMasterKey.clear();
+ }
}
NotifyStatusChanged(this);
@@ -3406,7 +3544,7 @@ void CWallet::SetupLegacyScriptPubKeyMan()
return;
}
- auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new LegacyScriptPubKeyMan(*this));
+ auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new LegacyScriptPubKeyMan(*this, m_keypool_size));
for (const auto& type : LEGACY_OUTPUT_TYPES) {
m_internal_spk_managers[type] = spk_manager.get();
m_external_spk_managers[type] = spk_manager.get();
@@ -3435,10 +3573,10 @@ void CWallet::ConnectScriptPubKeyManNotifiers()
void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
{
if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
- auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc));
+ auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc, m_keypool_size));
m_spk_managers[id] = std::move(spk_manager);
} else {
- auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
+ auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size));
m_spk_managers[id] = std::move(spk_manager);
}
}
@@ -3449,7 +3587,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
for (bool internal : {false, true}) {
for (OutputType t : OUTPUT_TYPES) {
- auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
+ auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, m_keypool_size));
if (IsCrypted()) {
if (IsLocked()) {
throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
@@ -3505,7 +3643,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
continue;
}
OutputType t = *desc->GetOutputType();
- auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this));
+ auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, m_keypool_size));
spk_manager->SetupDescriptor(std::move(desc));
uint256 id = spk_manager->GetID();
m_spk_managers[id] = std::move(spk_manager);
@@ -3621,7 +3759,7 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
WalletLogPrintf("Update existing descriptor: %s\n", desc.descriptor->ToString());
spk_man->UpdateWalletDescriptor(desc);
} else {
- auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
+ auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size));
spk_man = new_spk_man.get();
// Save the descriptor to memory
@@ -3678,26 +3816,27 @@ bool CWallet::MigrateToSQLite(bilingual_str& error)
// Get all of the records for DB type migration
std::unique_ptr<DatabaseBatch> batch = m_database->MakeBatch();
+ std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
std::vector<std::pair<SerializeData, SerializeData>> records;
- if (!batch->StartCursor()) {
+ if (!cursor) {
error = _("Error: Unable to begin reading all records in the database");
return false;
}
- bool complete = false;
+ DatabaseCursor::Status status = DatabaseCursor::Status::FAIL;
while (true) {
- CDataStream ss_key(SER_DISK, CLIENT_VERSION);
- CDataStream ss_value(SER_DISK, CLIENT_VERSION);
- bool ret = batch->ReadAtCursor(ss_key, ss_value, complete);
- if (!ret) {
+ DataStream ss_key{};
+ DataStream ss_value{};
+ status = cursor->Next(ss_key, ss_value);
+ if (status != DatabaseCursor::Status::MORE) {
break;
}
SerializeData key(ss_key.begin(), ss_key.end());
SerializeData value(ss_value.begin(), ss_value.end());
records.emplace_back(key, value);
}
- batch->CloseCursor();
+ cursor.reset();
batch.reset();
- if (!complete) {
+ if (status != DatabaseCursor::Status::DONE) {
error = _("Error: Unable to read all records in the database");
return false;
}
@@ -3723,8 +3862,8 @@ bool CWallet::MigrateToSQLite(bilingual_str& error)
bool began = batch->TxnBegin();
assert(began); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
for (const auto& [key, value] : records) {
- CDataStream ss_key(key, SER_DISK, CLIENT_VERSION);
- CDataStream ss_value(value, SER_DISK, CLIENT_VERSION);
+ DataStream ss_key{key};
+ DataStream ss_value{value};
if (!batch->Write(ss_key, ss_value)) {
batch->TxnAbort();
m_database->Close();
@@ -3742,14 +3881,11 @@ std::optional<MigrationData> CWallet::GetDescriptorsForLegacy(bilingual_str& err
AssertLockHeld(cs_wallet);
LegacyScriptPubKeyMan* legacy_spkm = GetLegacyScriptPubKeyMan();
- if (!legacy_spkm) {
- error = _("Error: This wallet is already a descriptor wallet");
- return std::nullopt;
- }
+ assert(legacy_spkm);
std::optional<MigrationData> res = legacy_spkm->MigrateToDescriptor();
if (res == std::nullopt) {
- error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first");
+ error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
return std::nullopt;
}
return res;
@@ -3910,6 +4046,23 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
}
}
}
+
+ // Persist added address book entries (labels, purpose) for watchonly and solvable wallets
+ auto persist_address_book = [](const CWallet& wallet) {
+ LOCK(wallet.cs_wallet);
+ WalletBatch batch{wallet.GetDatabase()};
+ for (const auto& [destination, addr_book_data] : wallet.m_address_book) {
+ auto address{EncodeDestination(destination)};
+ auto purpose{addr_book_data.purpose};
+ auto label{addr_book_data.GetLabel()};
+ // don't bother writing default values (unknown purpose, empty label)
+ if (purpose != "unknown") batch.WritePurpose(address, purpose);
+ if (!label.empty()) batch.WriteName(address, label);
+ }
+ };
+ if (data.watchonly_wallet) persist_address_book(*data.watchonly_wallet);
+ if (data.solvable_wallet) persist_address_book(*data.solvable_wallet);
+
// Remove the things to delete
if (dests_to_delete.size() > 0) {
for (const auto& dest : dests_to_delete) {
@@ -3929,6 +4082,11 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
return true;
}
+bool CWallet::CanGrindR() const
+{
+ return !IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER);
+}
+
bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error, MigrationResult& res) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
AssertLockHeld(wallet.cs_wallet);
@@ -4022,27 +4180,19 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
return true;
}
-util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>&& wallet, WalletContext& context)
+util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context)
{
MigrationResult res;
bilingual_str error;
std::vector<bilingual_str> warnings;
- // Make a backup of the DB
- std::string wallet_name = wallet->GetName();
- fs::path this_wallet_dir = fs::absolute(fs::PathFromString(wallet->GetDatabase().Filename())).parent_path();
- fs::path backup_filename = fs::PathFromString(strprintf("%s-%d.legacy.bak", wallet_name, GetTime()));
- fs::path backup_path = this_wallet_dir / backup_filename;
- if (!wallet->BackupWallet(fs::PathToString(backup_path))) {
- return util::Error{_("Error: Unable to make a backup of your wallet")};
- }
- res.backup_path = backup_path;
-
- // Unload the wallet so that nothing else tries to use it while we're changing it
- if (!RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings)) {
- return util::Error{_("Unable to unload the wallet before migrating")};
+ // If the wallet is still loaded, unload it so that nothing else tries to use it while we're changing it
+ if (auto wallet = GetWallet(context, wallet_name)) {
+ if (!RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings)) {
+ return util::Error{_("Unable to unload the wallet before migrating")};
+ }
+ UnloadWallet(std::move(wallet));
}
- UnloadWallet(std::move(wallet));
// Load the wallet but only in the context of this function.
// No signals should be connected nor should anything else be aware of this wallet
@@ -4056,15 +4206,43 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
return util::Error{Untranslated("Wallet file verification failed.") + Untranslated(" ") + error};
}
+ // Make the local wallet
std::shared_ptr<CWallet> local_wallet = CWallet::Create(empty_context, wallet_name, std::move(database), options.create_flags, error, warnings);
if (!local_wallet) {
return util::Error{Untranslated("Wallet loading failed.") + Untranslated(" ") + error};
}
+ // Before anything else, check if there is something to migrate.
+ if (!local_wallet->GetLegacyScriptPubKeyMan()) {
+ return util::Error{_("Error: This wallet is already a descriptor wallet")};
+ }
+
+ // Make a backup of the DB
+ fs::path this_wallet_dir = fs::absolute(fs::PathFromString(local_wallet->GetDatabase().Filename())).parent_path();
+ fs::path backup_filename = fs::PathFromString(strprintf("%s-%d.legacy.bak", wallet_name, GetTime()));
+ fs::path backup_path = this_wallet_dir / backup_filename;
+ if (!local_wallet->BackupWallet(fs::PathToString(backup_path))) {
+ return util::Error{_("Error: Unable to make a backup of your wallet")};
+ }
+ res.backup_path = backup_path;
+
bool success = false;
{
LOCK(local_wallet->cs_wallet);
+ // Unlock the wallet if needed
+ if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
+ if (passphrase.find('\0') == std::string::npos) {
+ return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
+ } else {
+ return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
+ "The passphrase contains a null character (ie - a zero byte). "
+ "If this passphrase was set with a version of this software prior to 25.0, "
+ "please try again with only the characters up to — but not including — "
+ "the first null character.")};
+ }
+ }
+
// First change to using SQLite
if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
@@ -4094,8 +4272,8 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
// Make list of wallets to cleanup
std::vector<std::shared_ptr<CWallet>> created_wallets;
- created_wallets.push_back(std::move(res.watchonly_wallet));
- created_wallets.push_back(std::move(res.solvables_wallet));
+ if (res.watchonly_wallet) created_wallets.push_back(std::move(res.watchonly_wallet));
+ if (res.solvables_wallet) created_wallets.push_back(std::move(res.solvables_wallet));
// Get the directories to remove after unloading
for (std::shared_ptr<CWallet>& w : created_wallets) {
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 6a1b76505c..e8c18dbb67 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,6 +10,7 @@
#include <fs.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
+#include <logging.h>
#include <outputtype.h>
#include <policy/feerate.h>
#include <psbt.h>
@@ -19,7 +20,7 @@
#include <util/result.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
+#include <util/time.h>
#include <util/ui_change_type.h>
#include <validationinterface.h>
#include <wallet/crypter.h>
@@ -195,7 +196,7 @@ public:
util::Result<CTxDestination> GetReservedDestination(bool internal);
//! Return reserved address
void ReturnDestination();
- //! Keep the address. Do not return it's key to the keypool when this object goes out of scope
+ //! Keep the address. Do not return its key to the keypool when this object goes out of scope
void KeepDestination();
};
@@ -242,6 +243,7 @@ private:
std::atomic<bool> fAbortRescan{false};
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
std::atomic<bool> m_attaching_chain{false};
+ std::atomic<bool> m_scanning_with_passphrase{false};
std::atomic<int64_t> m_scanning_start{0};
std::atomic<double> m_scanning_progress{0};
friend class WalletRescanReserver;
@@ -250,7 +252,7 @@ private:
int nWalletVersion GUARDED_BY(cs_wallet){FEATURE_BASE};
/** The next scheduled rebroadcast of wallet transactions. */
- std::atomic<int64_t> m_next_resend{};
+ NodeClock::time_point m_next_resend{GetDefaultNextResend()};
/** Whether this wallet will submit newly created transactions to the node's mempool and
* prompt rebroadcasts (see ResendWalletTransactions()). */
bool fBroadcastTransactions = false;
@@ -306,9 +308,6 @@ private:
//! Unset the blank wallet flag and saves it to disk
void UnsetBlankWalletFlag(WalletBatch& batch) override;
- /** Provider of aplication-wide arguments. */
- const ArgsManager& m_args;
-
/** Interface for accessing chain state. */
interfaces::Chain* m_chain;
@@ -348,6 +347,8 @@ private:
*/
static bool AttachChain(const std::shared_ptr<CWallet>& wallet, interfaces::Chain& chain, const bool rescan_required, bilingual_str& error, std::vector<bilingual_str>& warnings);
+ static NodeClock::time_point GetDefaultNextResend();
+
public:
/**
* Main wallet lock.
@@ -370,9 +371,8 @@ public:
unsigned int nMasterKeyMaxID = 0;
/** Construct wallet with specified name and database implementation. */
- CWallet(interfaces::Chain* chain, const std::string& name, const ArgsManager& args, std::unique_ptr<WalletDatabase> database)
- : m_args(args),
- m_chain(chain),
+ CWallet(interfaces::Chain* chain, const std::string& name, std::unique_ptr<WalletDatabase> database)
+ : m_chain(chain),
m_name(name),
m_database(std::move(database))
{
@@ -399,7 +399,6 @@ public:
TxItems wtxOrdered;
int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0;
- uint64_t nAccountingEntryNumber = 0;
std::map<CTxDestination, CAddressBookData> m_address_book GUARDED_BY(cs_wallet);
const CAddressBookData* FindAddressBookEntry(const CTxDestination&, bool allow_change = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -465,6 +464,7 @@ public:
void AbortRescan() { fAbortRescan = true; }
bool IsAbortingRescan() const { return fAbortRescan; }
bool IsScanning() const { return fScanningWallet; }
+ bool IsScanningWithPassphrase() const { return m_scanning_with_passphrase; }
int64_t ScanningDuration() const { return fScanningWallet ? GetTimeMillis() - m_scanning_start : 0; }
double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; }
@@ -484,6 +484,9 @@ public:
// Used to prevent concurrent calls to walletpassphrase RPC.
Mutex m_unlock_mutex;
+ // Used to prevent deleting the passphrase from memory when it is still in use.
+ RecursiveMutex m_relock_mutex;
+
bool Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys = false);
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
@@ -514,7 +517,7 @@ public:
*/
CWalletTx* AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false);
bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override;
+ void transactionAddedToMempool(const CTransactionRef& tx) override;
void blockConnected(const interfaces::BlockInfo& block) override;
void blockDisconnected(const interfaces::BlockInfo& block) override;
void updatedBlockTip() override;
@@ -536,7 +539,11 @@ public:
uint256 last_failed_block;
};
ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate, const bool save_progress);
- void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
+ void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) override;
+ /** Set the next time this wallet should resend transactions to 12-36 hours from now, ~1 day on average. */
+ void SetNextResend() { m_next_resend = GetDefaultNextResend(); }
+ /** Return true if all conditions for periodically resending transactions are met. */
+ bool ShouldResend() const;
void ResubmitWalletTransactions(bool relay, bool force);
OutputType TransactionChangeType(const std::optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const;
@@ -585,12 +592,6 @@ public:
bool SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, bool relay) const
EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, const CCoinControl* coin_control = nullptr) const
- {
- std::vector<CTxOut> v_txouts(txouts.size());
- std::copy(txouts.begin(), txouts.end(), v_txouts.begin());
- return DummySignTx(txNew, v_txouts, coin_control);
- }
bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, const CCoinControl* coin_control = nullptr) const;
bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -636,6 +637,12 @@ public:
/** Absolute maximum transaction fee (in satoshis) used by default for the wallet */
CAmount m_default_max_tx_fee{DEFAULT_TRANSACTION_MAXFEE};
+ /** Number of pre-generated keys/scripts by each spkm (part of the look-ahead process, used to detect payments) */
+ int64_t m_keypool_size{DEFAULT_KEYPOOL_SIZE};
+
+ /** Notify external script when a wallet transaction comes in or is updated (handled by -walletnotify) */
+ std::string m_notify_tx_changed_script;
+
size_t KeypoolCountExternalKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool TopUpKeyPool(unsigned int kpSize = 0);
@@ -815,7 +822,8 @@ public:
bool IsLegacy() const;
/** Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet has no name */
- const std::string GetDisplayName() const override {
+ std::string GetDisplayName() const override
+ {
std::string wallet_name = GetName().length() == 0 ? "default wallet" : GetName();
return strprintf("[%s]", wallet_name);
};
@@ -933,6 +941,9 @@ public:
//! Adds the ScriptPubKeyMans given in MigrationData to this wallet, removes LegacyScriptPubKeyMan,
//! and where needed, moves tx and address book entries to watchonly_wallet or solvable_wallet
bool ApplyMigrationData(MigrationData& data, bilingual_str& error) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ //! Whether the (external) signer performs R-value signature grinding
+ bool CanGrindR() const;
};
/**
@@ -948,17 +959,18 @@ private:
using Clock = std::chrono::steady_clock;
using NowFn = std::function<Clock::time_point()>;
CWallet& m_wallet;
- bool m_could_reserve;
+ bool m_could_reserve{false};
NowFn m_now;
public:
- explicit WalletRescanReserver(CWallet& w) : m_wallet(w), m_could_reserve(false) {}
+ explicit WalletRescanReserver(CWallet& w) : m_wallet(w) {}
- bool reserve()
+ bool reserve(bool with_passphrase = false)
{
assert(!m_could_reserve);
if (m_wallet.fScanningWallet.exchange(true)) {
return false;
}
+ m_wallet.m_scanning_with_passphrase.exchange(with_passphrase);
m_wallet.m_scanning_start = GetTimeMillis();
m_wallet.m_scanning_progress = 0;
m_could_reserve = true;
@@ -978,6 +990,7 @@ public:
{
if (m_could_reserve) {
m_wallet.fScanningWallet = false;
+ m_wallet.m_scanning_with_passphrase = false;
}
}
};
@@ -988,7 +1001,7 @@ bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name);
//! Remove wallet name from persistent configuration so it will not be loaded on startup.
bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name);
-bool DummySignInput(const SigningProvider& provider, CTxIn &tx_in, const CTxOut &txout, const CCoinControl* coin_control = nullptr);
+bool DummySignInput(const SigningProvider& provider, CTxIn &tx_in, const CTxOut &txout, bool can_grind_r, const CCoinControl* coin_control);
bool FillInputToWeight(CTxIn& txin, int64_t target_weight);
@@ -1000,7 +1013,7 @@ struct MigrationResult {
};
//! Do all steps to migrate a legacy wallet to a descriptor wallet
-util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>&& wallet, WalletContext& context);
+util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context);
} // namespace wallet
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 6a8f0d2481..2cd35ae40e 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -315,12 +315,13 @@ public:
std::map<uint160, CHDChain> m_hd_chains;
bool tx_corrupt{false};
bool descriptor_unknown{false};
+ bool unexpected_legacy_entry{false};
CWalletScanState() = default;
};
static bool
-ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
+ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
try {
@@ -332,6 +333,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
if (filter_fn && !filter_fn(strType)) {
return true;
}
+ // Legacy entries in descriptor wallets are not allowed, abort immediately
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) && DBKeys::LEGACY_TYPES.count(strType) > 0) {
+ wss.unexpected_legacy_entry = true;
+ return false;
+ }
if (strType == DBKeys::NAME) {
std::string strAddress;
ssKey >> strAddress;
@@ -482,7 +488,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
if (!ssValue.eof()) {
uint256 checksum;
ssValue >> checksum;
- if ((checksum_valid = Hash(vchPrivKey) != checksum)) {
+ if (!(checksum_valid = Hash(vchPrivKey) == checksum)) {
strErr = "Error reading wallet database: Encrypted key corrupt";
return false;
}
@@ -753,7 +759,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
return true;
}
-bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn)
+bool ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn)
{
CWalletScanState dummy_wss;
LOCK(pwallet->cs_wallet);
@@ -806,7 +812,8 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
#endif
// Get cursor
- if (!m_batch->StartCursor())
+ std::unique_ptr<DatabaseCursor> cursor = m_batch->GetNewCursor();
+ if (!cursor)
{
pwallet->WalletLogPrintf("Error getting wallet database cursor\n");
return DBErrors::CORRUPT;
@@ -815,16 +822,13 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
while (true)
{
// Read next record
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ DataStream ssKey{};
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- bool complete;
- bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
- if (complete) {
+ DatabaseCursor::Status status = cursor->Next(ssKey, ssValue);
+ if (status == DatabaseCursor::Status::DONE) {
break;
- }
- else if (!ret)
- {
- m_batch->CloseCursor();
+ } else if (status == DatabaseCursor::Status::FAIL) {
+ cursor.reset();
pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
return DBErrors::CORRUPT;
}
@@ -833,6 +837,12 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
std::string strType, strErr;
if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
{
+ if (wss.unexpected_legacy_entry) {
+ strErr = strprintf("Error: Unexpected legacy entry found in descriptor wallet %s. ", pwallet->GetName());
+ strErr += "The wallet might have been tampered with or created with malicious intent.";
+ pwallet->WalletLogPrintf("%s\n", strErr);
+ return DBErrors::UNEXPECTED_LEGACY_ENTRY;
+ }
// losing keys is considered a catastrophic error, anything else
// we assume the user can live with:
if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
@@ -866,7 +876,6 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
} catch (...) {
result = DBErrors::CORRUPT;
}
- m_batch->CloseCursor();
// Set the active ScriptPubKeyMans
for (auto spk_man_pair : wss.m_active_external_spks) {
@@ -962,7 +971,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
return result;
}
-DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx)
+DBErrors WalletBatch::FindWalletTxHashes(std::vector<uint256>& tx_hashes)
{
DBErrors result = DBErrors::LOAD_OK;
@@ -974,7 +983,8 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
}
// Get cursor
- if (!m_batch->StartCursor())
+ std::unique_ptr<DatabaseCursor> cursor = m_batch->GetNewCursor();
+ if (!cursor)
{
LogPrintf("Error getting wallet database cursor\n");
return DBErrors::CORRUPT;
@@ -983,14 +993,12 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
while (true)
{
// Read next record
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- bool complete;
- bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
- if (complete) {
+ DataStream ssKey{};
+ DataStream ssValue{};
+ DatabaseCursor::Status status = cursor->Next(ssKey, ssValue);
+ if (status == DatabaseCursor::Status::DONE) {
break;
- } else if (!ret) {
- m_batch->CloseCursor();
+ } else if (status == DatabaseCursor::Status::FAIL) {
LogPrintf("Error reading next record from wallet database\n");
return DBErrors::CORRUPT;
}
@@ -1000,25 +1008,21 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
if (strType == DBKeys::TX) {
uint256 hash;
ssKey >> hash;
- vTxHash.push_back(hash);
- vWtx.emplace_back(/*tx=*/nullptr, TxStateInactive{});
- ssValue >> vWtx.back();
+ tx_hashes.push_back(hash);
}
}
} catch (...) {
result = DBErrors::CORRUPT;
}
- m_batch->CloseCursor();
return result;
}
DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
{
- // build list of wallet TXs and hashes
+ // build list of wallet TX hashes
std::vector<uint256> vTxHash;
- std::list<CWalletTx> vWtx;
- DBErrors err = FindWalletTx(vTxHash, vWtx);
+ DBErrors err = FindWalletTxHashes(vTxHash);
if (err != DBErrors::LOAD_OK) {
return err;
}
@@ -1102,7 +1106,8 @@ bool WalletBatch::WriteWalletFlags(const uint64_t flags)
bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
{
// Get cursor
- if (!m_batch->StartCursor())
+ std::unique_ptr<DatabaseCursor> cursor = m_batch->GetNewCursor();
+ if (!cursor)
{
return false;
}
@@ -1111,16 +1116,12 @@ bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
while (true)
{
// Read next record
- CDataStream key(SER_DISK, CLIENT_VERSION);
- CDataStream value(SER_DISK, CLIENT_VERSION);
- bool complete;
- bool ret = m_batch->ReadAtCursor(key, value, complete);
- if (complete) {
+ DataStream key{};
+ DataStream value{};
+ DatabaseCursor::Status status = cursor->Next(key, value);
+ if (status == DatabaseCursor::Status::DONE) {
break;
- }
- else if (!ret)
- {
- m_batch->CloseCursor();
+ } else if (status == DatabaseCursor::Status::FAIL) {
return false;
}
@@ -1134,7 +1135,6 @@ bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
m_batch->Erase(key_data);
}
}
- m_batch->CloseCursor();
return true;
}
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index da6efe534b..c97356a71f 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -52,7 +52,8 @@ enum class DBErrors
LOAD_FAIL,
NEED_REWRITE,
NEED_RESCAN,
- UNKNOWN_DESCRIPTOR
+ UNKNOWN_DESCRIPTOR,
+ UNEXPECTED_LEGACY_ENTRY
};
namespace DBKeys {
@@ -272,7 +273,7 @@ public:
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal);
DBErrors LoadWallet(CWallet* pwallet);
- DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx);
+ DBErrors FindWalletTxHashes(std::vector<uint256>& tx_hashes);
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
/* Function to determine if a certain KV/key-type is a key (cryptographical key) type */
static bool IsKeyType(const std::string& strType);
@@ -302,7 +303,7 @@ void MaybeCompactWalletDB(WalletContext& context);
using KeyFilterFn = std::function<bool(const std::string&)>;
//! Unserialize a given Key-Value pair and load it into the wallet
-bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr);
+bool ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr);
/** Return object for accessing dummy database with no read/write capabilities. */
std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase();
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index e991bc0814..f389676204 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2021 The Bitcoin Core developers
+// Copyright (c) 2016-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -47,7 +47,7 @@ static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flag
wallet_instance->TopUpKeyPool();
}
-static const std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, const ArgsManager& args, DatabaseOptions options)
+static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options)
{
DatabaseStatus status;
bilingual_str error;
@@ -58,7 +58,7 @@ static const std::shared_ptr<CWallet> MakeWallet(const std::string& name, const
}
// dummy chain interface
- std::shared_ptr<CWallet> wallet_instance{new CWallet(nullptr /* chain */, name, args, std::move(database)), WalletToolReleaseWallet};
+ std::shared_ptr<CWallet> wallet_instance{new CWallet(/*chain=*/nullptr, name, std::move(database)), WalletToolReleaseWallet};
DBErrors load_wallet_ret;
try {
load_wallet_ret = wallet_instance->LoadWallet();
@@ -159,7 +159,7 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
options.require_format = DatabaseFormat::SQLITE;
}
- const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, args, options);
+ const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
if (wallet_instance) {
WalletShowInfo(wallet_instance.get());
wallet_instance->Close();
@@ -168,7 +168,7 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
DatabaseOptions options;
ReadDatabaseArgs(args, options);
options.require_existing = true;
- const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, args, options);
+ const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
if (!wallet_instance) return false;
WalletShowInfo(wallet_instance.get());
wallet_instance->Close();
@@ -194,7 +194,7 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
DatabaseOptions options;
ReadDatabaseArgs(args, options);
options.require_existing = true;
- const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, args, options);
+ const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
if (!wallet_instance) return false;
bilingual_str error;
bool ret = DumpWallet(args, *wallet_instance, error);
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index df1b10a634..299c74d01c 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021 The Bitcoin Core developers
+// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h
index 7624c2b16d..ce8b6cfd6e 100644
--- a/src/walletinitinterface.h
+++ b/src/walletinitinterface.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2020 The Bitcoin Core developers
+// Copyright (c) 2017-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/warnings.cpp b/src/warnings.cpp
index dabb194ce1..d0de706953 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index fa3944e32b..cf0ee48f47 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 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_ZMQ_ZMQABSTRACTNOTIFIER_H
#define BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
-
+#include <cstdint>
#include <memory>
#include <string>
@@ -20,7 +20,7 @@ class CZMQAbstractNotifier
public:
static const int DEFAULT_ZMQ_SNDHWM {1000};
- CZMQAbstractNotifier() : psocket(nullptr), outbound_message_high_water_mark(DEFAULT_ZMQ_SNDHWM) { }
+ CZMQAbstractNotifier() : outbound_message_high_water_mark(DEFAULT_ZMQ_SNDHWM) {}
virtual ~CZMQAbstractNotifier();
template <typename T>
@@ -57,7 +57,7 @@ public:
virtual bool NotifyTransaction(const CTransaction &transaction);
protected:
- void *psocket;
+ void* psocket{nullptr};
std::string type;
std::string address;
int outbound_message_high_water_mark; // aka SNDHWM
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index b9b7019a3c..df129c0830 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -1,17 +1,27 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 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 <zmq/zmqnotificationinterface.h>
+
+#include <logging.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <util/system.h>
+#include <validationinterface.h>
+#include <zmq/zmqabstractnotifier.h>
#include <zmq/zmqpublishnotifier.h>
#include <zmq/zmqutil.h>
#include <zmq.h>
-#include <primitives/block.h>
-#include <util/system.h>
+#include <cassert>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
-CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(nullptr)
+CZMQNotificationInterface::CZMQNotificationInterface()
{
}
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index 8f81bfd63f..a43f9bfef3 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -1,14 +1,18 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 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_ZMQ_ZMQNOTIFICATIONINTERFACE_H
#define BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
+#include <primitives/transaction.h>
#include <validationinterface.h>
+
+#include <cstdint>
#include <list>
#include <memory>
+class CBlock;
class CBlockIndex;
class CZMQAbstractNotifier;
@@ -35,7 +39,7 @@ protected:
private:
CZMQNotificationInterface();
- void *pcontext;
+ void* pcontext{nullptr};
std::list<std::unique_ptr<CZMQAbstractNotifier>> notifiers;
};
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index 51c8ad515e..6418455d19 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2021 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,21 +6,38 @@
#include <chain.h>
#include <chainparams.h>
+#include <crypto/common.h>
+#include <kernel/cs_main.h>
+#include <logging.h>
+#include <netaddress.h>
#include <netbase.h>
#include <node/blockstorage.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
#include <rpc/server.h>
+#include <serialize.h>
#include <streams.h>
-#include <util/system.h>
+#include <sync.h>
+#include <uint256.h>
+#include <version.h>
#include <zmq/zmqutil.h>
#include <zmq.h>
+#include <cassert>
#include <cstdarg>
#include <cstddef>
+#include <cstdint>
+#include <cstring>
#include <map>
#include <optional>
#include <string>
#include <utility>
+#include <vector>
+
+namespace Consensus {
+struct Params;
+}
using node::ReadBlockFromDisk;
@@ -232,18 +249,14 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
const Consensus::Params& consensusParams = Params().GetConsensus();
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
- {
- LOCK(cs_main);
- CBlock block;
- if(!ReadBlockFromDisk(block, pindex, consensusParams))
- {
- zmqError("Can't read block from disk");
- return false;
- }
-
- ss << block;
+ CBlock block;
+ if (!ReadBlockFromDisk(block, pindex, consensusParams)) {
+ zmqError("Can't read block from disk");
+ return false;
}
+ ss << block;
+
return SendZmqMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size());
}
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index c1d66bddb1..18336a5eb0 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2020 The Bitcoin Core developers
+// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,7 +7,11 @@
#include <zmq/zmqabstractnotifier.h>
+#include <cstddef>
+#include <cstdint>
+
class CBlockIndex;
+class CTransaction;
class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier
{
diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp
index ec6d1cbba3..fcc2608262 100644
--- a/src/zmq/zmqrpc.cpp
+++ b/src/zmq/zmqrpc.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
+// Copyright (c) 2018-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,11 @@
#include <univalue.h>
+#include <list>
+#include <string>
+
+class JSONRPCRequest;
+
namespace {
static RPCHelpMan getzmqnotifications()
diff --git a/src/zmq/zmqutil.cpp b/src/zmq/zmqutil.cpp
index cf3a0b2d71..3c6d1b9ab5 100644
--- a/src/zmq/zmqutil.cpp
+++ b/src/zmq/zmqutil.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2021 The Bitcoin Core developers
+// Copyright (c) 2014-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/README.md b/test/README.md
index fdbb91832a..0eddb72e1f 100644
--- a/test/README.md
+++ b/test/README.md
@@ -109,34 +109,57 @@ how many jobs to run, append `--jobs=n`
The individual tests and the test_runner harness have many command-line
options. Run `test/functional/test_runner.py -h` to see them all.
-#### Speed up test runs with a ramdisk
+#### Speed up test runs with a RAM disk
-If you have available RAM on your system you can create a ramdisk to use as the `cache` and `tmp` directories for the functional tests in order to speed them up.
-Speed-up amount varies on each system (and according to your ram speed and other variables), but a 2-3x speed-up is not uncommon.
+If you have available RAM on your system you can create a RAM disk to use as the `cache` and `tmp` directories for the functional tests in order to speed them up.
+Speed-up amount varies on each system (and according to your RAM speed and other variables), but a 2-3x speed-up is not uncommon.
-To create a 4GB ramdisk on Linux at `/mnt/tmp/`:
+**Linux**
+
+To create a 4 GiB RAM disk at `/mnt/tmp/`:
```bash
sudo mkdir -p /mnt/tmp
sudo mount -t tmpfs -o size=4g tmpfs /mnt/tmp/
```
-Configure the size of the ramdisk using the `size=` option.
-The size of the ramdisk needed is relative to the number of concurrent jobs the test suite runs.
-For example running the test suite with `--jobs=100` might need a 4GB ramdisk, but running with `--jobs=32` will only need a 2.5GB ramdisk.
+Configure the size of the RAM disk using the `size=` option.
+The size of the RAM disk needed is relative to the number of concurrent jobs the test suite runs.
+For example running the test suite with `--jobs=100` might need a 4 GiB RAM disk, but running with `--jobs=32` will only need a 2.5 GiB RAM disk.
-To use, run the test suite specifying the ramdisk as the `cachedir` and `tmpdir`:
+To use, run the test suite specifying the RAM disk as the `cachedir` and `tmpdir`:
```bash
test/functional/test_runner.py --cachedir=/mnt/tmp/cache --tmpdir=/mnt/tmp
```
-Once finished with the tests and the disk, and to free the ram, simply unmount the disk:
+Once finished with the tests and the disk, and to free the RAM, simply unmount the disk:
```bash
sudo umount /mnt/tmp
```
+**macOS**
+
+To create a 4 GiB RAM disk named "ramdisk" at `/Volumes/ramdisk/`:
+
+```bash
+diskutil erasevolume HFS+ ramdisk $(hdiutil attach -nomount ram://8388608)
+```
+
+Configure the RAM disk size, expressed as the number of blocks, at the end of the command
+(`4096 MiB * 2048 blocks/MiB = 8388608 blocks` for 4 GiB). To run the tests using the RAM disk:
+
+```bash
+test/functional/test_runner.py --cachedir=/Volumes/ramdisk/cache --tmpdir=/Volumes/ramdisk/tmp
+```
+
+To unmount:
+
+```bash
+umount /Volumes/ramdisk
+```
+
#### Troubleshooting and debugging test failures
##### Resource contention
diff --git a/test/functional/data/invalid_txs.py b/test/functional/data/invalid_txs.py
index 3747b2a98d..33054fd517 100644
--- a/test/functional/data/invalid_txs.py
+++ b/test/functional/data/invalid_txs.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
@@ -46,18 +46,19 @@ from test_framework.script import (
OP_MOD,
OP_MUL,
OP_OR,
+ OP_RETURN,
OP_RIGHT,
OP_RSHIFT,
OP_SUBSTR,
- OP_TRUE,
OP_XOR,
)
from test_framework.script_util import (
+ MIN_PADDING,
+ MIN_STANDARD_TX_NONWITNESS_SIZE,
script_to_p2sh_script,
)
basic_p2sh = script_to_p2sh_script(CScript([OP_0]))
-
class BadTxTemplate:
"""Allows simple construction of a certain kind of invalid tx. Base class to be subclassed."""
__metaclass__ = abc.ABCMeta
@@ -122,7 +123,9 @@ class SizeTooSmall(BadTxTemplate):
def get_tx(self):
tx = CTransaction()
tx.vin.append(self.valid_txin)
- tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
+ tx.vout.append(CTxOut(0, CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 2)))))
+ assert len(tx.serialize_without_witness()) == 64
+ assert MIN_STANDARD_TX_NONWITNESS_SIZE - 1 == 64
tx.calc_sha256()
return tx
diff --git a/test/functional/data/rpc_decodescript.json b/test/functional/data/rpc_decodescript.json
index 4a15ae8792..5f3e725d4c 100644
--- a/test/functional/data/rpc_decodescript.json
+++ b/test/functional/data/rpc_decodescript.json
@@ -69,7 +69,7 @@
"p2sh": "2N34iiGoUUkVSPiaaTFpJjB1FR9TXQu3PGM",
"segwit": {
"asm": "0 96c2368fc30514a438a8bd909f93c49a1549d77198ccbdb792043b666cb24f42",
- "desc": "addr(bcrt1qjmprdr7rq522gw9ghkgfly7yng25n4m3nrxtmdujqsakvm9jfapqk795l5)#5akkdska",
+ "desc": "wsh(raw(02eeee))#gtay4y0z",
"hex": "002096c2368fc30514a438a8bd909f93c49a1549d77198ccbdb792043b666cb24f42",
"address": "bcrt1qjmprdr7rq522gw9ghkgfly7yng25n4m3nrxtmdujqsakvm9jfapqk795l5",
"type": "witness_v0_scripthash",
diff --git a/test/functional/data/rpc_getblockstats.json b/test/functional/data/rpc_getblockstats.json
index 16dbc5fe60..7d7460aacc 100644
--- a/test/functional/data/rpc_getblockstats.json
+++ b/test/functional/data/rpc_getblockstats.json
@@ -102,8 +102,8 @@
"00000020f44e7a48b9f221af95f3295c8dcefc5358934a68dc79e2933dc0794b350cad0a90fad2cd50b41d4ef45e76c2a456b98c180632bb4b44e0cd18ce90679fe54e552b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401630101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
"0000002087454276cce83f4d19e0120f6e9728ac5905f7adaf6b27e3f5bbe43ab823f85db7d1f44666531483df3d67c15f2c231718ad93b63b851dce5ff4c4a67f524ffa2b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401640101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
"000000202cdc3e99f07a80252dd6097faa0eddf3f2dde5ae390610e0bca94ecc25931551d31fceb8fe0a682f6017ca3dbb582f3a2f06e5d99ec99c42c8a744dd4c9216b82b4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000209b3ace9bd510918d20e87518c0cf5976cab3e28cc7af41259a89c6dd7668a32922808b8a082be71bcd6152cb8fd223650b5579a41344ba749e4d17b9bf211a9e2b4ae75affff7f200000000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401660101ffffffff026c03062a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9edb85d8f3c122c43a72f1e0dd122c8f7af040aa0b0a46001621110fb37818021510120000000000000000000000000000000000000000000000000000000000000000000000000020000000128394022bf44bff30d7399cb5a16e3b94fed67dc174c2e1d77df91bad5a51cb3000000006a47304402201c16d06a5c4353168b3881071aea7d1eb4d88eedfea53a9d6af9abb56da9060002205abf3ae535f1f1b5cfe8ba955535c2b20ac003e7d7720c5b7d2640ac2a04d19001210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff0294b89a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac00286bee0000000017a91452bab4f229415d0dc5c6d30b162f93a1a0cac5958765000000",
- "000000200fa168b50a79ad24378a6b0f96e4c9f4ccb657a2663320d5fc1efd8ee7caa10ab42a31c444f2153387530a0979d4dc3dcc134b394c821227b8abff930c03c8412b4ae75affff7f200200000004020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401670101ffffffff02e015072a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ed20376d4bc90f9c689850eec3603cda658ba6295241730473ceb0e970b8d594150120000000000000000000000000000000000000000000000000000000000000000000000000020000000191e549a6cc852bbf1d3f11144b1a34079f64305e6971d2e685d2b40cd386e8a6000000006a47304402200bf62021c0a9a47ced8eba1e0998f5c71b2950763198d83ad284bd791241dbb00220446a05b7c35e7458924de88a8dcccab1ec6a106aa005345e55b482d8eb66337301210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff02acdbf405000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac94d7a4350000000017a914dfa6f0b17d2c64962c94203e744a9d4179ed22c18766000000020000000112d2f07672102dc6f099c4be308f598e4c4da1a7e0cb462ae14f0444525a1332000000006a47304402200a6a2f544f3f9d299608a7c745e2326de176fb1cac03ae3e74943f4250b8896e02205023a5b4faff99865bf91f1263605a502c723628be9240c0b7bec81d2ed106f101210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff0200ca9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac94166bee0000000017a914152cc82f7944f5c416de7dbffb052f7081765d7987660000000200000000010191e549a6cc852bbf1d3f11144b1a34079f64305e6971d2e685d2b40cd386e8a601000000171600147cc872ad7350c37fecab9c4c6d9f08aceb53bdb8feffffff02005ed0b20000000017a914aab1c8c53fe62e283a53efa28097709f4f2ed37b87e0bc9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0247304402201b4476f238ed5d515bfcd6927d0d008a4993770763eca73e3ee66f69971831d902200f5215a6dfd90391dd63462cfdf69804fe31224c309ec9c38d33a04dce71c0ee0121028c9d2955a95301b699db62e97d54bf0a91feb44e5cd94bbf5b62f1df57fb643966000000"
+ "000000209b3ace9bd510918d20e87518c0cf5976cab3e28cc7af41259a89c6dd7668a329f03ef4716ad5d88bccfd71088bf2ec3eb5b32e0ff60f35f9becd73052bfa8af12b4ae75affff7f200000000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401660101ffffffff025803062a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9edb11910e4e0ee6ee6d6bad42736999d1eba649243dc781438e5ef845c7227aaad0120000000000000000000000000000000000000000000000000000000000000000000000000020000000128394022bf44bff30d7399cb5a16e3b94fed67dc174c2e1d77df91bad5a51cb3000000006a47304402200650c6c50bd4952ca13b7aa37d458a36628434bbb968701063cdd36d0725e36c02202e059ccf7a4a049de028c4f140e543baa7e69ea3663e3d1fdfbc8ba7247e82f901210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff02a8b89a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac00286bee0000000016001423838e991caedd69289d9dac88ca423cca683a2265000000",
+ "0000002061597bf3305ee2334b5d7fec136c2064b69d14955b50cd0b81f49ac33d88e506d80731ce60c2f275d29539a4d04c7e8c72aa4ade3c9baec24881a581fc524c6a2b4ae75affff7f200000000005020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401670101ffffffff023840072a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ed89a3c65f40921b14168368cf4775a710ad17b613cedcff001f1f1ca3c863cc11012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101bb475ac72ba1a45a96be584a689d6d0ace820d9587b0db53dc40a15555b9be770100000000feffffff02c0be9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac005ed0b200000000160014a57f6871c70569e0543322614c5c85438b796a900247304402207893b5466cdbf9cdedcc73fb8e10e01c4dd9aac4345031ef0c35d91e82ff5fd602207f0e1d7e4270a532060fd1e6ad7881d18acb173fd4fd1d61f3c8ff6707bdb972012103bb4c79ca594b19bbec7ee6302af0ef4191345fa7f03a30ed4e042aeed680924b6600000002000000000101e6a996cbac10b2d6b2bb2796a4ebf639ee21b136e06c7d8c6bc62b7cb4a311870100000000feffffff0200ca9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88acc088357700000000160014c48ea35298422796eb75ee9a04ebada66780083902473044022062963ff9f1f0d2c885060c083b97ddd67bd6e8a7daaed6578a62c1f905fd31a6022001836efe75bbce64d29700f5568aed78ce68f098ef0b8efdad0679e2f6c0ceb5012102228c4d459ce647b63b2681597a6e8391e4b5afab147f90747184a0893e4934c26600000002000000000101c654a35d86b4c3112ae9ec75e3bc271e0b8f928620386fdaf9517e8a9b511d850100000000feffffff024038f505000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88acc0a73f7100000000160014cb1049e20cebfe756d657af0d47a3357c1db3c9702473044022024728eb27e884d08b2b95e670fd58c0e10106a18bc9e01f753f9ae474aa2c95e02201d5abe91302b373507dce1fd2f4b95ddc36e21d23eda6c476cc9efea80338ef90121036be02fd68622ce6740f0d028059af96a310c23c675f044732171df6f64f0fcb2660000000200000000010135c4ee1a780d8279ea7c79d3ad6fbb39315a13e6b51dd51f49db6e2f4796bada0100000000feffffff020000000000000000036a0121c8183f71000000001600147ea4d830ca77c20a23155a176a1472613dc4e7840247304402202db3527431e09ca8034d207134d79fc063939bd402286dd8b3872de3b2a746b402207faae5fb8838e6877822a9209fe2e81d4be4a69ce8164215e03f9b92d75e94f90121024d456d37df6f3436ee1685b78d90d2d24c4dd8c602d5f41405fe7f449b43415f00000000"
],
"mocktime": 1525107225,
"stats": [
@@ -142,13 +142,15 @@
"totalfee": 0,
"txs": 1,
"utxo_increase": 2,
- "utxo_size_inc": 163
+ "utxo_increase_actual": 1,
+ "utxo_size_inc": 163,
+ "utxo_size_inc_actual": 75
},
{
- "avgfee": 4460,
+ "avgfee": 4440,
"avgfeerate": 20,
- "avgtxsize": 223,
- "blockhash": "0aa1cae78efd1efcd5203366a257b6ccf4c9e4960f6b8a3724ad790ab568a10f",
+ "avgtxsize": 222,
+ "blockhash": "06e5883dc39af4810bcd505b95149db664206c13ec7f5d4b33e25e30f37b5961",
"feerate_percentiles": [
20,
20,
@@ -158,65 +160,69 @@
],
"height": 102,
"ins": 1,
- "maxfee": 4460,
+ "maxfee": 4440,
"maxfeerate": 20,
- "maxtxsize": 223,
- "medianfee": 4460,
+ "maxtxsize": 222,
+ "medianfee": 4440,
"mediantime": 1525107242,
- "mediantxsize": 223,
- "minfee": 4460,
+ "mediantxsize": 222,
+ "minfee": 4440,
"minfeerate": 20,
- "mintxsize": 223,
+ "mintxsize": 222,
"outs": 4,
"subsidy": 5000000000,
"swtotal_size": 0,
"swtotal_weight": 0,
"swtxs": 0,
"time": 1525107243,
- "total_out": 4999995540,
- "total_size": 223,
- "total_weight": 892,
- "totalfee": 4460,
+ "total_out": 4999995560,
+ "total_size": 222,
+ "total_weight": 888,
+ "totalfee": 4440,
"txs": 2,
"utxo_increase": 3,
- "utxo_size_inc": 236
+ "utxo_increase_actual": 2,
+ "utxo_size_inc": 235,
+ "utxo_size_inc_actual": 147
},
{
- "avgfee": 24906,
- "avgfeerate": 121,
- "avgtxsize": 231,
- "blockhash": "53e416e2538bc783c42a7aea566e884321afed893e9e58cf356d6429759dfa46",
+ "avgfee": 21390,
+ "avgfeerate": 155,
+ "avgtxsize": 219,
+ "blockhash": "7474991c2ae3c94c4813d75b4c752028304b773dd4dce8d460dfa2d1e7b542a3",
"feerate_percentiles": [
20,
20,
20,
- 300,
- 300
+ 301,
+ 301
],
"height": 103,
- "ins": 3,
- "maxfee": 66900,
- "maxfeerate": 300,
- "maxtxsize": 249,
- "medianfee": 4460,
+ "ins": 4,
+ "maxfee": 43200,
+ "maxfeerate": 301,
+ "maxtxsize": 225,
+ "medianfee": 19740,
"mediantime": 1525107243,
- "mediantxsize": 223,
- "minfee": 3360,
+ "mediantxsize": 225,
+ "minfee": 2880,
"minfeerate": 20,
- "mintxsize": 223,
- "outs": 8,
+ "mintxsize": 203,
+ "outs": 10,
"subsidy": 5000000000,
- "swtotal_size": 249,
- "swtotal_weight": 669,
- "swtxs": 1,
+ "swtotal_size": 878,
+ "swtotal_weight": 2204,
+ "swtxs": 4,
"time": 1525107243,
- "total_out": 9999920820,
- "total_size": 695,
- "total_weight": 2453,
- "totalfee": 74720,
- "txs": 4,
- "utxo_increase": 5,
- "utxo_size_inc": 384
+ "total_out": 10899908680,
+ "total_size": 878,
+ "total_weight": 2204,
+ "totalfee": 85560,
+ "txs": 5,
+ "utxo_increase": 6,
+ "utxo_increase_actual": 4,
+ "utxo_size_inc": 441,
+ "utxo_size_inc_actual": 300
}
]
} \ No newline at end of file
diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json
index 657faebffc..3127350872 100644
--- a/test/functional/data/rpc_psbt.json
+++ b/test/functional/data/rpc_psbt.json
@@ -44,6 +44,10 @@
[
"cHNidP8BAKOro2MDAwMDA5ggCAAA////CQAtAAD+///1AAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAD+///1Zm9ybmV3nWx1Y2vmelLmegAAAAAAAAAAAAAAAAAAAAMKAwMDAwMDAwMDAwMACvMBA3FkAAAAAAAAAAAABAAlAAAAAAAAACEWDQ0zDQ0NDQ0NDQ0NCwEAAH9/f39/fwMAAABNo6P///kAAA==",
"Input Taproot BIP32 keypath has an invalid length"
+ ],
+ [
+ "cHNidP8BAIkCAAAAAapfm08b0MipBvW9thL06f8rMbeazW7TIa0W9plHj4WoAAAAAAD9////AoCWmAAAAAAAIlEgC+blBlIP1iijRWxqjw1u9H02sqr7y8fno6/LdnvGqPl895x2AAAAACJRIM5wyjSexMbADl4K+AI1/68zyaDlE7guKvrEDUAjwqU1AAAAAAABASsAlDV3AAAAACJRIDfCpO/CIAqc0JKgBhsCfaPGdyroYtmH+4gQK/Mnn72UIRZGOixxmh9h2gqDIecYHcQHRa8w+Sokc//iDiqXz7uMGRkAHzYIzlYAAIABAACAAAAAgAAAAABhAAAAARcgRjoscZofYdoKgyHnGB3EB0WvMPkqJHP/4g4ql8+7jBkAAQUg1YCB33LpmkGemw3ncz7fcnjhL/bBG/PjH8vpgr2L3cUBBgAhB9WAgd9y6ZpBnpsN53M+33J44S/2wRvz4x/L6YK9i93FGQAfNgjOVgAAgAEAAIAAAACAAAAAAGIAAAAAAQUg9jMNus8cd+GAosBk9wn+pNP9wn7A+jy2Vq0cy+siJ8wBBgAhB/YzDbrPHHfhgKLAZPcJ/qTT/cJ+wPo8tlatHMvrIifMGQAfNgjOVgAAgAEAAIAAAACAAQAAAFEBAAAA",
+ "Output Taproot tree must not be empty"
]
],
"valid" : [
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index 9cf756060e..7f7aa065ad 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""An example functional test
@@ -79,6 +79,9 @@ class ExampleTest(BitcoinTestFramework):
# Override the set_test_params(), skip_test_if_missing_module(), add_options(), setup_chain(), setup_network()
# and setup_nodes() methods to customize the test setup as required.
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
"""Override test parameters for your individual test.
diff --git a/test/functional/feature_abortnode.py b/test/functional/feature_abortnode.py
index 32cf4a47f4..fa1bb6506a 100755
--- a/test/functional/feature_abortnode.py
+++ b/test/functional/feature_abortnode.py
@@ -19,7 +19,6 @@ class AbortNodeTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
- self.rpc_timeout = 240
def setup_network(self):
self.setup_nodes()
@@ -41,7 +40,7 @@ class AbortNodeTest(BitcoinTestFramework):
# Check that node0 aborted
self.log.info("Waiting for crash")
- self.nodes[0].wait_until_stopped(timeout=200)
+ self.nodes[0].wait_until_stopped(timeout=5)
self.log.info("Node crashed - now verifying restart fails")
self.nodes[0].assert_start_raises_init_error()
diff --git a/test/functional/feature_addrman.py b/test/functional/feature_addrman.py
index 63abf0d9f8..28c3880513 100755
--- a/test/functional/feature_addrman.py
+++ b/test/functional/feature_addrman.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 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 addrman functionality"""
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 67cacaa9ce..36ee79dab9 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 logic for skipping signature validation on old blocks.
@@ -83,8 +83,6 @@ class AssumeValidTest(BitcoinTestFramework):
break
def run_test(self):
- p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
-
# Build the blockchain
self.tip = int(self.nodes[0].getbestblockhash(), 16)
self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
@@ -139,28 +137,23 @@ class AssumeValidTest(BitcoinTestFramework):
self.block_time += 1
height += 1
- self.nodes[0].disconnect_p2ps()
-
# Start node1 and node2 with assumevalid so they accept a block with a bad signature.
self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)])
self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)])
p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
- p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
- p2p2 = self.nodes[2].add_p2p_connection(BaseNode())
-
- # send header lists to all three nodes
p2p0.send_header_for_blocks(self.blocks[0:2000])
p2p0.send_header_for_blocks(self.blocks[2000:])
- p2p1.send_header_for_blocks(self.blocks[0:2000])
- p2p1.send_header_for_blocks(self.blocks[2000:])
- p2p2.send_header_for_blocks(self.blocks[0:200])
# Send blocks to node0. Block 102 will be rejected.
self.send_blocks_until_disconnected(p2p0)
self.wait_until(lambda: self.nodes[0].getblockcount() >= COINBASE_MATURITY + 1)
assert_equal(self.nodes[0].getblockcount(), COINBASE_MATURITY + 1)
+ p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
+ p2p1.send_header_for_blocks(self.blocks[0:2000])
+ p2p1.send_header_for_blocks(self.blocks[2000:])
+
# Send all blocks to node1. All blocks will be accepted.
for i in range(2202):
p2p1.send_message(msg_block(self.blocks[i]))
@@ -168,6 +161,9 @@ class AssumeValidTest(BitcoinTestFramework):
p2p1.sync_with_ping(960)
assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
+ p2p2 = self.nodes[2].add_p2p_connection(BaseNode())
+ p2p2.send_header_for_blocks(self.blocks[0:200])
+
# Send blocks to node2. Block 102 will be rejected.
self.send_blocks_until_disconnected(p2p2)
self.wait_until(lambda: self.nodes[2].getblockcount() >= COINBASE_MATURITY + 1)
diff --git a/test/functional/feature_bind_extra.py b/test/functional/feature_bind_extra.py
index 5de9ff203c..4a94d2ce7b 100755
--- a/test/functional/feature_bind_extra.py
+++ b/test/functional/feature_bind_extra.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index 05d274a9fe..894afffc79 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 BIP68 implementation."""
@@ -10,15 +10,21 @@ from test_framework.blocktools import (
NORMAL_GBT_REQUEST_PARAMS,
add_witness_commitment,
create_block,
+ script_to_p2wsh_script,
)
from test_framework.messages import (
COIN,
COutPoint,
CTransaction,
CTxIn,
+ CTxInWitness,
CTxOut,
tx_from_hex,
)
+from test_framework.script import (
+ CScript,
+ OP_TRUE,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -26,7 +32,9 @@ from test_framework.util import (
assert_raises_rpc_error,
softfork_active,
)
-from test_framework.script_util import DUMMY_P2WPKH_SCRIPT
+from test_framework.wallet import MiniWallet
+
+SCRIPT_W0_SH_OP_TRUE = script_to_p2wsh_script(CScript([OP_TRUE]))
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
SEQUENCE_LOCKTIME_TYPE_FLAG = (1<<22) # this means use time (0 means height)
@@ -37,27 +45,23 @@ SEQUENCE_LOCKTIME_MASK = 0x0000ffff
NOT_FINAL_ERROR = "non-BIP68-final"
class BIP68Test(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [
[
'-testactivationheight=csv@432',
- "-acceptnonstdtxn=1",
],
[
'-testactivationheight=csv@432',
- "-acceptnonstdtxn=0",
],
]
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def run_test(self):
self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
-
- # Generate some coins
- self.generate(self.nodes[0], 110)
+ self.wallet = MiniWallet(self.nodes[0])
self.log.info("Running test disable flag")
self.test_disable_flag()
@@ -84,26 +88,20 @@ class BIP68Test(BitcoinTestFramework):
# the first sequence bit is set.
def test_disable_flag(self):
# Create some unconfirmed inputs
- new_addr = self.nodes[0].getnewaddress()
- self.nodes[0].sendtoaddress(new_addr, 2) # send 2 BTC
-
- utxos = self.nodes[0].listunspent(0, 0)
- assert len(utxos) > 0
-
- utxo = utxos[0]
+ utxo = self.wallet.send_self_transfer(from_node=self.nodes[0])["new_utxo"]
tx1 = CTransaction()
- value = int((utxo["amount"] - self.relayfee) * COIN)
+ value = int((utxo["value"] - self.relayfee) * COIN)
# Check that the disable flag disables relative locktime.
# If sequence locks were used, this would require 1 block for the
# input to mature.
sequence_value = SEQUENCE_LOCKTIME_DISABLE_FLAG | 1
tx1.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=sequence_value)]
- tx1.vout = [CTxOut(value, DUMMY_P2WPKH_SCRIPT)]
+ tx1.vout = [CTxOut(value, SCRIPT_W0_SH_OP_TRUE)]
- tx1_signed = self.nodes[0].signrawtransactionwithwallet(tx1.serialize().hex())["hex"]
- tx1_id = self.nodes[0].sendrawtransaction(tx1_signed)
+ self.wallet.sign_tx(tx=tx1)
+ tx1_id = self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx1.serialize().hex())
tx1_id = int(tx1_id, 16)
# This transaction will enable sequence-locks, so this transaction should
@@ -112,16 +110,18 @@ class BIP68Test(BitcoinTestFramework):
tx2.nVersion = 2
sequence_value = sequence_value & 0x7fffffff
tx2.vin = [CTxIn(COutPoint(tx1_id, 0), nSequence=sequence_value)]
- tx2.vout = [CTxOut(int(value - self.relayfee * COIN), DUMMY_P2WPKH_SCRIPT)]
+ tx2.wit.vtxinwit = [CTxInWitness()]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
+ tx2.vout = [CTxOut(int(value - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)]
tx2.rehash()
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx2.serialize().hex())
+ assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx2.serialize().hex())
# Setting the version back down to 1 should disable the sequence lock,
# so this should be accepted.
tx2.nVersion = 1
- self.nodes[0].sendrawtransaction(tx2.serialize().hex())
+ self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx2.serialize().hex())
# Calculate the median time past of a prior block ("confirmations" before
# the current tip).
@@ -134,20 +134,13 @@ class BIP68Test(BitcoinTestFramework):
# Create lots of confirmed utxos, and use them to generate lots of random
# transactions.
max_outputs = 50
- addresses = []
- while len(addresses) < max_outputs:
- addresses.append(self.nodes[0].getnewaddress())
- while len(self.nodes[0].listunspent()) < 200:
+ while len(self.wallet.get_utxos(include_immature_coinbase=False, mark_as_spent=False)) < 200:
import random
- random.shuffle(addresses)
num_outputs = random.randint(1, max_outputs)
- outputs = {}
- for i in range(num_outputs):
- outputs[addresses[i]] = random.randint(1, 20)*0.01
- self.nodes[0].sendmany("", outputs)
- self.generate(self.nodes[0], 1)
+ self.wallet.send_self_transfer_multi(from_node=self.nodes[0], num_outputs=num_outputs)
+ self.generate(self.wallet, 1)
- utxos = self.nodes[0].listunspent()
+ utxos = self.wallet.get_utxos(include_immature_coinbase=False)
# Try creating a lot of random transactions.
# Each time, choose a random number of inputs, and randomly set
@@ -204,19 +197,20 @@ class BIP68Test(BitcoinTestFramework):
sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)+1
sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG
tx.vin.append(CTxIn(COutPoint(int(utxos[j]["txid"], 16), utxos[j]["vout"]), nSequence=sequence_value))
- value += utxos[j]["amount"]*COIN
+ value += utxos[j]["value"]*COIN
# Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output
tx_size = len(tx.serialize().hex())//2 + 120*num_inputs + 50
- tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), DUMMY_P2WPKH_SCRIPT))
- rawtx = self.nodes[0].signrawtransactionwithwallet(tx.serialize().hex())["hex"]
+ tx.vout.append(CTxOut(int(value - self.relayfee * tx_size * COIN / 1000), SCRIPT_W0_SH_OP_TRUE))
+ self.wallet.sign_tx(tx=tx)
if (using_sequence_locks and not should_pass):
# This transaction should be rejected
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx)
+ assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx.serialize().hex())
else:
# This raw transaction should be accepted
- self.nodes[0].sendrawtransaction(rawtx)
- utxos = self.nodes[0].listunspent()
+ self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx.serialize().hex())
+ self.wallet.rescan_utxos()
+ utxos = self.wallet.get_utxos(include_immature_coinbase=False)
# Test that sequence locks on unconfirmed inputs must have nSequence
# height or time of 0 to be accepted.
@@ -227,8 +221,8 @@ class BIP68Test(BitcoinTestFramework):
cur_height = self.nodes[0].getblockcount()
# Create a mempool tx.
- txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
- tx1 = tx_from_hex(self.nodes[0].getrawtransaction(txid))
+ self.wallet.rescan_utxos()
+ tx1 = self.wallet.send_self_transfer(from_node=self.nodes[0])["tx"]
tx1.rehash()
# Anyone-can-spend mempool tx.
@@ -236,12 +230,12 @@ class BIP68Test(BitcoinTestFramework):
tx2 = CTransaction()
tx2.nVersion = 2
tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
- tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), DUMMY_P2WPKH_SCRIPT)]
- tx2_raw = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())["hex"]
- tx2 = tx_from_hex(tx2_raw)
+ tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)]
+ self.wallet.sign_tx(tx=tx2)
+ tx2_raw = tx2.serialize().hex()
tx2.rehash()
- self.nodes[0].sendrawtransaction(tx2_raw)
+ self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx2_raw)
# Create a spend of the 0th output of orig_tx with a sequence lock
# of 1, and test what happens when submitting.
@@ -254,15 +248,17 @@ class BIP68Test(BitcoinTestFramework):
tx = CTransaction()
tx.nVersion = 2
tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)]
- tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), DUMMY_P2WPKH_SCRIPT)]
+ tx.wit.vtxinwit = [CTxInWitness()]
+ tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
+ tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)]
tx.rehash()
if (orig_tx.hash in node.getrawmempool()):
# sendrawtransaction should fail if the tx is in the mempool
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, node.sendrawtransaction, tx.serialize().hex())
+ assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=node, tx_hex=tx.serialize().hex())
else:
# sendrawtransaction should succeed if the tx is not in the mempool
- node.sendrawtransaction(tx.serialize().hex())
+ self.wallet.sendrawtransaction(from_node=node, tx_hex=tx.serialize().hex())
return tx
@@ -275,7 +271,7 @@ class BIP68Test(BitcoinTestFramework):
cur_time = int(time.time())
for _ in range(10):
self.nodes[0].setmocktime(cur_time + 600)
- self.generate(self.nodes[0], 1, sync_fun=self.no_op)
+ self.generate(self.wallet, 1, sync_fun=self.no_op)
cur_time += 600
assert tx2.hash in self.nodes[0].getrawmempool()
@@ -309,12 +305,12 @@ class BIP68Test(BitcoinTestFramework):
tx5 = test_nonzero_locks(tx4, self.nodes[0], self.relayfee, use_height_lock=True)
assert tx5.hash not in self.nodes[0].getrawmempool()
- utxos = self.nodes[0].listunspent()
- tx5.vin.append(CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1))
- tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN)
- raw_tx5 = self.nodes[0].signrawtransactionwithwallet(tx5.serialize().hex())["hex"]
+ utxo = self.wallet.get_utxo()
+ tx5.vin.append(CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=1))
+ tx5.vout[0].nValue += int(utxo["value"]*COIN)
+ self.wallet.sign_tx(tx=tx5)
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5)
+ assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx5.serialize().hex())
# Test mempool-BIP68 consistency after reorg
#
@@ -350,7 +346,7 @@ class BIP68Test(BitcoinTestFramework):
# Reset the chain and get rid of the mocktimed-blocks
self.nodes[0].setmocktime(0)
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1))
- self.generate(self.nodes[0], 10, sync_fun=self.no_op)
+ self.generate(self.wallet, 10, sync_fun=self.no_op)
# Make sure that BIP68 isn't being used to validate blocks prior to
# activation height. If more blocks are mined prior to this test
@@ -358,23 +354,23 @@ class BIP68Test(BitcoinTestFramework):
# this test should be moved to run earlier, or deleted.
def test_bip68_not_consensus(self):
assert not softfork_active(self.nodes[0], 'csv')
- txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
- tx1 = tx_from_hex(self.nodes[0].getrawtransaction(txid))
+ tx1 = self.wallet.send_self_transfer(from_node=self.nodes[0])["tx"]
tx1.rehash()
# Make an anyone-can-spend transaction
tx2 = CTransaction()
tx2.nVersion = 1
tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
- tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), DUMMY_P2WPKH_SCRIPT)]
+ tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)]
# sign tx2
- tx2_raw = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())["hex"]
+ self.wallet.sign_tx(tx=tx2)
+ tx2_raw = tx2.serialize().hex()
tx2 = tx_from_hex(tx2_raw)
tx2.rehash()
- self.nodes[0].sendrawtransaction(tx2.serialize().hex())
+ self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx2_raw)
# Now make an invalid spend of tx2 according to BIP68
sequence_value = 100 # 100 block relative locktime
@@ -382,10 +378,12 @@ class BIP68Test(BitcoinTestFramework):
tx3 = CTransaction()
tx3.nVersion = 2
tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), nSequence=sequence_value)]
- tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), DUMMY_P2WPKH_SCRIPT)]
+ tx3.wit.vtxinwit = [CTxInWitness()]
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
+ tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)]
tx3.rehash()
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx3.serialize().hex())
+ assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx3.serialize().hex())
# make a block that violates bip68; ensure that the tip updates
block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS), txlist=[tx1, tx2, tx3])
@@ -401,22 +399,19 @@ class BIP68Test(BitcoinTestFramework):
min_activation_height = 432
height = self.nodes[0].getblockcount()
assert_greater_than(min_activation_height - height, 2)
- self.generate(self.nodes[0], min_activation_height - height - 2, sync_fun=self.no_op)
+ self.generate(self.wallet, min_activation_height - height - 2, sync_fun=self.no_op)
assert not softfork_active(self.nodes[0], 'csv')
- self.generate(self.nodes[0], 1, sync_fun=self.no_op)
+ self.generate(self.wallet, 1, sync_fun=self.no_op)
assert softfork_active(self.nodes[0], 'csv')
self.sync_blocks()
# Use self.nodes[1] to test that version 2 transactions are standard.
def test_version2_relay(self):
- inputs = [ ]
- outputs = { self.nodes[1].getnewaddress() : 1.0 }
- rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
- rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex']
- tx = tx_from_hex(rawtxfund)
+ mini_wallet = MiniWallet(self.nodes[1])
+ mini_wallet.rescan_utxos()
+ tx = mini_wallet.create_self_transfer()["tx"]
tx.nVersion = 2
- tx_signed = self.nodes[1].signrawtransactionwithwallet(tx.serialize().hex())["hex"]
- self.nodes[1].sendrawtransaction(tx_signed)
+ mini_wallet.sendrawtransaction(from_node=self.nodes[1], tx_hex=tx.serialize().hex())
if __name__ == '__main__':
BIP68Test().main()
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 850cb8334c..1080e77c40 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 block processing."""
@@ -161,7 +161,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info(f"Reject block with invalid tx: {TxTemplate.__name__}")
blockname = f"for_invalid.{TxTemplate.__name__}"
- badblock = self.next_block(blockname)
+ self.next_block(blockname)
badtx = template.get_tx()
if TxTemplate != invalid_txs.InputMissing:
self.sign_tx(badtx, attempt_spend_tx)
@@ -473,7 +473,7 @@ class FullBlockTest(BitcoinTestFramework):
#
self.log.info("Check P2SH SIGOPS are correctly counted")
self.move_tip(35)
- b39 = self.next_block(39)
+ self.next_block(39)
b39_outputs = 0
b39_sigops_per_output = 6
@@ -672,7 +672,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with two coinbase transactions")
self.move_tip(44)
- b51 = self.next_block(51)
+ self.next_block(51)
cb2 = create_coinbase(51, self.coinbase_pubkey)
b51 = self.update_block(51, [cb2])
self.send_blocks([b51], success=False, reject_reason='bad-cb-multiple', reconnect=True)
@@ -752,7 +752,7 @@ class FullBlockTest(BitcoinTestFramework):
# b57 - a good block with 2 txs, don't submit until end
self.move_tip(55)
- b57 = self.next_block(57)
+ self.next_block(57)
tx = self.create_and_sign_transaction(out[16], 1)
tx1 = self.create_tx(tx, 0, 1)
b57 = self.update_block(57, [tx, tx1])
@@ -769,7 +769,7 @@ class FullBlockTest(BitcoinTestFramework):
# b57p2 - a good block with 6 tx'es, don't submit until end
self.move_tip(55)
- b57p2 = self.next_block("57p2")
+ self.next_block("57p2")
tx = self.create_and_sign_transaction(out[16], 1)
tx1 = self.create_tx(tx, 0, 1)
tx2 = self.create_tx(tx1, 0, 1)
@@ -803,7 +803,7 @@ class FullBlockTest(BitcoinTestFramework):
# tx with prevout.n out of range
self.log.info("Reject a block with a transaction with prevout.n out of range")
self.move_tip(57)
- b58 = self.next_block(58, spend=out[17])
+ self.next_block(58, spend=out[17])
tx = CTransaction()
assert len(out[17].vout) < 42
tx.vin.append(CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), SEQUENCE_FINAL))
@@ -815,7 +815,7 @@ class FullBlockTest(BitcoinTestFramework):
# tx with output value > input value
self.log.info("Reject a block with a transaction with outputs > inputs")
self.move_tip(57)
- b59 = self.next_block(59)
+ self.next_block(59)
tx = self.create_and_sign_transaction(out[17], 51 * COIN)
b59 = self.update_block(59, [tx])
self.send_blocks([b59], success=False, reject_reason='bad-txns-in-belowout', reconnect=True)
@@ -851,7 +851,7 @@ class FullBlockTest(BitcoinTestFramework):
# \-> b_spend_dup_cb (b_dup_cb) -> b_dup_2 ()
#
self.move_tip(57)
- b_spend_dup_cb = self.next_block('spend_dup_cb')
+ self.next_block('spend_dup_cb')
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(duplicate_tx.sha256, 0)))
tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
@@ -876,7 +876,7 @@ class FullBlockTest(BitcoinTestFramework):
#
self.log.info("Reject a block with a transaction with a nonfinal locktime")
self.move_tip('dup_2')
- b62 = self.next_block(62)
+ self.next_block(62)
tx = CTransaction()
tx.nLockTime = 0xffffffff # this locktime is non-final
tx.vin.append(CTxIn(COutPoint(out[18].sha256, 0))) # don't set nSequence
@@ -957,7 +957,7 @@ class FullBlockTest(BitcoinTestFramework):
#
self.log.info("Accept a block with a transaction spending an output created in the same block")
self.move_tip(64)
- b65 = self.next_block(65)
+ self.next_block(65)
tx1 = self.create_and_sign_transaction(out[19], out[19].vout[0].nValue)
tx2 = self.create_and_sign_transaction(tx1, 0)
b65 = self.update_block(65, [tx1, tx2])
@@ -970,7 +970,7 @@ class FullBlockTest(BitcoinTestFramework):
# \-> b66 (20)
self.log.info("Reject a block with a transaction spending an output created later in the same block")
self.move_tip(65)
- b66 = self.next_block(66)
+ self.next_block(66)
tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
tx2 = self.create_and_sign_transaction(tx1, 1)
b66 = self.update_block(66, [tx2, tx1])
@@ -984,7 +984,7 @@ class FullBlockTest(BitcoinTestFramework):
#
self.log.info("Reject a block with a transaction double spending a transaction created in the same block")
self.move_tip(65)
- b67 = self.next_block(67)
+ self.next_block(67)
tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
tx2 = self.create_and_sign_transaction(tx1, 1)
tx3 = self.create_and_sign_transaction(tx1, 2)
@@ -1005,7 +1005,7 @@ class FullBlockTest(BitcoinTestFramework):
#
self.log.info("Reject a block trying to claim too much subsidy in the coinbase transaction")
self.move_tip(65)
- b68 = self.next_block(68, additional_coinbase_value=10)
+ self.next_block(68, additional_coinbase_value=10)
tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 9)
b68 = self.update_block(68, [tx])
self.send_blocks([b68], success=False, reject_reason='bad-cb-amount', reconnect=True)
@@ -1025,7 +1025,7 @@ class FullBlockTest(BitcoinTestFramework):
#
self.log.info("Reject a block containing a transaction spending from a non-existent input")
self.move_tip(69)
- b70 = self.next_block(70, spend=out[21])
+ self.next_block(70, spend=out[21])
bogus_tx = CTransaction()
bogus_tx.sha256 = uint256_from_str(b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c")
tx = CTransaction()
@@ -1043,7 +1043,7 @@ class FullBlockTest(BitcoinTestFramework):
# b71 is a copy of 72, but re-adds one of its transactions. However, it has the same hash as b72.
self.log.info("Reject a block containing a duplicate transaction but with the same Merkle root (Merkle tree malleability")
self.move_tip(69)
- b72 = self.next_block(72)
+ self.next_block(72)
tx1 = self.create_and_sign_transaction(out[21], 2)
tx2 = self.create_and_sign_transaction(tx1, 1)
b72 = self.update_block(72, [tx1, tx2]) # now tip is 72
@@ -1081,7 +1081,7 @@ class FullBlockTest(BitcoinTestFramework):
# bytearray[20,526] : OP_CHECKSIG (this puts us over the limit)
self.log.info("Reject a block containing too many sigops after a large script element")
self.move_tip(72)
- b73 = self.next_block(73)
+ self.next_block(73)
size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 + 1
a = bytearray([OP_CHECKSIG] * size)
a[MAX_BLOCK_SIGOPS - 1] = int("4e", 16) # OP_PUSHDATA4
@@ -1109,7 +1109,7 @@ class FullBlockTest(BitcoinTestFramework):
# b75 succeeds because we put MAX_BLOCK_SIGOPS before the element
self.log.info("Check sigops are counted correctly after an invalid script element")
self.move_tip(72)
- b74 = self.next_block(74)
+ self.next_block(74)
size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 # total = 20,561
a = bytearray([OP_CHECKSIG] * size)
a[MAX_BLOCK_SIGOPS] = 0x4e
@@ -1122,7 +1122,7 @@ class FullBlockTest(BitcoinTestFramework):
self.send_blocks([b74], success=False, reject_reason='bad-blk-sigops', reconnect=True)
self.move_tip(72)
- b75 = self.next_block(75)
+ self.next_block(75)
size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42
a = bytearray([OP_CHECKSIG] * size)
a[MAX_BLOCK_SIGOPS - 1] = 0x4e
@@ -1137,7 +1137,7 @@ class FullBlockTest(BitcoinTestFramework):
# Check that if we push an element filled with CHECKSIGs, they are not counted
self.move_tip(75)
- b76 = self.next_block(76)
+ self.next_block(76)
size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5
a = bytearray([OP_CHECKSIG] * size)
a[MAX_BLOCK_SIGOPS - 1] = 0x4e # PUSHDATA4, but leave the following bytes as just checksigs
@@ -1165,18 +1165,18 @@ class FullBlockTest(BitcoinTestFramework):
# updated. (Perhaps to spend to a P2SH OP_TRUE script)
self.log.info("Test transaction resurrection during a re-org")
self.move_tip(76)
- b77 = self.next_block(77)
+ self.next_block(77)
tx77 = self.create_and_sign_transaction(out[24], 10 * COIN)
b77 = self.update_block(77, [tx77])
self.send_blocks([b77], True)
self.save_spendable_output()
- b78 = self.next_block(78)
+ self.next_block(78)
tx78 = self.create_tx(tx77, 0, 9 * COIN)
b78 = self.update_block(78, [tx78])
self.send_blocks([b78], True)
- b79 = self.next_block(79)
+ self.next_block(79)
tx79 = self.create_tx(tx78, 0, 8 * COIN)
b79 = self.update_block(79, [tx79])
self.send_blocks([b79], True)
@@ -1208,7 +1208,7 @@ class FullBlockTest(BitcoinTestFramework):
# -> b81 (26) -> b82 (27) -> b83 (28)
#
self.log.info("Accept a block with invalid opcodes in dead execution paths")
- b83 = self.next_block(83)
+ self.next_block(83)
op_codes = [OP_IF, OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF]
script = CScript(op_codes)
tx1 = self.create_and_sign_transaction(out[28], out[28].vout[0].nValue, script)
@@ -1227,7 +1227,7 @@ class FullBlockTest(BitcoinTestFramework):
# \-> b85 (29) -> b86 (30) \-> b89a (32)
#
self.log.info("Test re-orging blocks with OP_RETURN in them")
- b84 = self.next_block(84)
+ self.next_block(84)
tx1 = self.create_tx(out[29], 0, 0, CScript([OP_RETURN]))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
@@ -1265,7 +1265,7 @@ class FullBlockTest(BitcoinTestFramework):
self.save_spendable_output()
# trying to spend the OP_RETURN output is rejected
- b89a = self.next_block("89a", spend=out[32])
+ self.next_block("89a", spend=out[32])
tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE]))
b89a = self.update_block("89a", [tx])
self.send_blocks([b89a], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 9d32749a08..7730db9672 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 BIP65 (CHECKLOCKTIMEVERIFY).
@@ -8,6 +8,7 @@ Test that the CHECKLOCKTIMEVERIFY soft-fork activates.
"""
from test_framework.blocktools import (
+ TIME_GENESIS_BLOCK,
create_block,
create_coinbase,
)
@@ -61,7 +62,7 @@ def cltv_invalidate(tx, failure_reason):
# +-------------------------------------------------+------------+--------------+
[[OP_CHECKLOCKTIMEVERIFY], None, None],
[[OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP], None, None],
- [[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 1296688602], # timestamp of genesis block
+ [[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, TIME_GENESIS_BLOCK],
[[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 50],
[[CScriptNum(50), OP_CHECKLOCKTIMEVERIFY, OP_DROP], SEQUENCE_FINAL, 50],
][failure_reason]
diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py
index 2e21638f80..4f8541a5d7 100755
--- a/test/functional/feature_coinstatsindex.py
+++ b/test/functional/feature_coinstatsindex.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 coinstatsindex across nodes.
@@ -156,9 +156,10 @@ class CoinStatsIndexTest(BitcoinTestFramework):
# Generate and send another tx with an OP_RETURN output (which is unspendable)
tx2 = self.wallet.create_self_transfer(utxo_to_spend=tx1_out_21)['tx']
- tx2.vout = [CTxOut(int(Decimal('20.99') * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
+ tx2_val = '20.99'
+ tx2.vout = [CTxOut(int(Decimal(tx2_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
tx2_hex = tx2.serialize().hex()
- self.nodes[0].sendrawtransaction(tx2_hex)
+ self.nodes[0].sendrawtransaction(tx2_hex, 0, tx2_val)
# Include both txs in a block
self.generate(self.nodes[0], 1)
@@ -221,7 +222,7 @@ class CoinStatsIndexTest(BitcoinTestFramework):
self.generate(index_node, 1, sync_fun=self.no_op)
res10 = index_node.gettxoutsetinfo('muhash')
- assert(res8['txouts'] < res10['txouts'])
+ assert res8['txouts'] < res10['txouts']
self.log.info("Test that the index works with -reindex")
@@ -268,12 +269,12 @@ class CoinStatsIndexTest(BitcoinTestFramework):
res2 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=112)
assert_equal(res["bestblock"], block)
assert_equal(res["muhash"], res2["muhash"])
- assert(res["muhash"] != res_invalid["muhash"])
+ assert res["muhash"] != res_invalid["muhash"]
# Test that requesting reorged out block by hash is still returning correct results
res_invalid2 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=reorg_block)
assert_equal(res_invalid2["muhash"], res_invalid["muhash"])
- assert(res["muhash"] != res_invalid2["muhash"])
+ assert res["muhash"] != res_invalid2["muhash"]
# Add another block, so we don't depend on reconsiderblock remembering which
# blocks were touched by invalidateblock
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index eb31bca29a..f9730b48c5 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 various command line arguments and configuration file parameters."""
@@ -12,6 +12,9 @@ from test_framework import util
class ConfArgsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
@@ -20,11 +23,25 @@ class ConfArgsTest(BitcoinTestFramework):
self.disable_autoconnect = False
def test_config_file_parser(self):
+ self.log.info('Test config file parser')
self.stop_node(0)
+ # Check that startup fails if conf= is set in bitcoin.conf or in an included conf file
+ bad_conf_file_path = os.path.join(self.options.tmpdir, 'node0', 'bitcoin_bad.conf')
+ util.write_config(bad_conf_file_path, n=0, chain='', extra_config=f'conf=some.conf\n')
+ conf_in_config_file_err = 'Error: Error reading configuration file: conf cannot be set in the configuration file; use includeconf= if you want to include additional config files'
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=[f'-conf={bad_conf_file_path}'],
+ expected_msg=conf_in_config_file_err,
+ )
inc_conf_file_path = os.path.join(self.nodes[0].datadir, 'include.conf')
with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf:
conf.write(f'includeconf={inc_conf_file_path}\n')
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('conf=some.conf\n')
+ self.nodes[0].assert_start_raises_init_error(
+ expected_msg=conf_in_config_file_err,
+ )
self.nodes[0].assert_start_raises_init_error(
expected_msg='Error: Error parsing command line arguments: Invalid parameter -dash_cli=1',
@@ -32,11 +49,19 @@ class ConfArgsTest(BitcoinTestFramework):
)
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('dash_conf=1\n')
+
with self.nodes[0].assert_debug_log(expected_msgs=['Ignoring unknown configuration value dash_conf']):
self.start_node(0)
self.stop_node(0)
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('reindex=1\n')
+
+ with self.nodes[0].assert_debug_log(expected_msgs=['Warning: reindex=1 is set in the configuration file, which will significantly slow down startup. Consider removing or commenting out this option for better performance, unless there is currently a condition which makes rebuilding the indexes necessary']):
+ self.start_node(0)
+ self.stop_node(0)
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('-dash=1\n')
self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -')
@@ -101,7 +126,6 @@ class ConfArgsTest(BitcoinTestFramework):
expected_msgs=[
'Command-line arg: addnode="some.node"',
'Command-line arg: rpcauth=****',
- 'Command-line arg: rpcbind=****',
'Command-line arg: rpcpassword=****',
'Command-line arg: rpcuser=****',
'Command-line arg: torpassword=****',
@@ -110,14 +134,17 @@ class ConfArgsTest(BitcoinTestFramework):
],
unexpected_msgs=[
'alice:f7efda5c189b999524f151318c0c86$d5b51b3beffbc0',
- '127.1.1.1',
'secret-rpcuser',
'secret-torpassword',
+ 'Command-line arg: rpcbind=****',
+ 'Command-line arg: rpcallowip=****',
]):
self.start_node(0, extra_args=[
'-addnode=some.node',
'-rpcauth=alice:f7efda5c189b999524f151318c0c86$d5b51b3beffbc0',
'-rpcbind=127.1.1.1',
+ '-rpcbind=127.0.0.1',
+ "-rpcallowip=127.0.0.1",
'-rpcpassword=',
'-rpcuser=secret-rpcuser',
'-torpassword=secret-torpassword',
@@ -224,11 +251,43 @@ class ConfArgsTest(BitcoinTestFramework):
]):
self.nodes[0].setmocktime(start + 65)
+ def test_connect_with_seednode(self):
+ self.log.info('Test -connect with -seednode')
+ seednode_ignored = ['-seednode is ignored when -connect is used\n']
+ dnsseed_ignored = ['-dnsseed is ignored when -connect is used and -proxy is specified\n']
+ addcon_thread_started = ['addcon thread start\n']
+ self.stop_node(0)
+
+ # When -connect is supplied, expanding addrman via getaddr calls to ADDR_FETCH(-seednode)
+ # nodes is irrelevant and -seednode is ignored.
+ with self.nodes[0].assert_debug_log(expected_msgs=seednode_ignored):
+ self.start_node(0, extra_args=['-connect=fakeaddress1', '-seednode=fakeaddress2'])
+
+ # With -proxy, an ADDR_FETCH connection is made to a peer that the dns seed resolves to.
+ # ADDR_FETCH connections are not used when -connect is used.
+ with self.nodes[0].assert_debug_log(expected_msgs=dnsseed_ignored):
+ self.restart_node(0, extra_args=['-connect=fakeaddress1', '-dnsseed=1', '-proxy=1.2.3.4'])
+
+ # If the user did not disable -dnsseed, but it was soft-disabled because they provided -connect,
+ # they shouldn't see a warning about -dnsseed being ignored.
+ with self.nodes[0].assert_debug_log(expected_msgs=addcon_thread_started,
+ unexpected_msgs=dnsseed_ignored):
+ self.restart_node(0, extra_args=['-connect=fakeaddress1', '-proxy=1.2.3.4'])
+
+ # We have to supply expected_msgs as it's a required argument
+ # The expected_msg must be something we are confident will be logged after the unexpected_msg
+ # These cases test for -connect being supplied but only to disable it
+ for connect_arg in ['-connect=0', '-noconnect']:
+ with self.nodes[0].assert_debug_log(expected_msgs=addcon_thread_started,
+ unexpected_msgs=seednode_ignored):
+ self.restart_node(0, extra_args=[connect_arg, '-seednode=fakeaddress2'])
+
def run_test(self):
self.test_log_buffer()
self.test_args_log()
self.test_seed_peers()
self.test_networkactive()
+ self.test_connect_with_seednode()
self.test_config_file_parser()
self.test_invalid_command_line_options()
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index bff95c3b94..a88a97c813 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 CSV soft fork activation.
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index f606f26e70..1f2e0936ed 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 recovery from a crash during chainstate writing.
@@ -85,7 +85,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
self.nodes[node_index].waitforblock(expected_tip)
utxo_hash = self.nodes[node_index].gettxoutsetinfo()['hash_serialized_2']
return utxo_hash
- except:
+ except Exception:
# An exception here should mean the node is about to crash.
# If bitcoind exits, then try again. wait_for_node_exit()
# should raise an exception if bitcoind doesn't exit.
@@ -202,7 +202,6 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[3])
- self.wallet.rescan_utxos()
initial_height = self.nodes[3].getblockcount()
self.generate(self.nodes[3], COINBASE_MATURITY, sync_fun=self.no_op)
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 9a46839969..4a66863d91 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 BIP66 (DER SIG).
diff --git a/test/functional/feature_discover.py b/test/functional/feature_discover.py
new file mode 100755
index 0000000000..7f4b81114e
--- /dev/null
+++ b/test/functional/feature_discover.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 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 -discover command."""
+
+import socket
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+
+def is_valid_ipv4_address(address):
+ try:
+ socket.inet_aton(address)
+ except socket.error:
+ return False
+ return True
+
+
+def is_valid_ipv6_address(address):
+ try:
+ socket.inet_pton(socket.AF_INET6, address)
+ except socket.error:
+ return False
+ return True
+
+
+class DiscoverTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.bind_to_localhost_only = False
+ self.num_nodes = 1
+
+ def validate_addresses(self, addresses_obj):
+ for address_obj in addresses_obj:
+ address = address_obj['address']
+ self.log.info(f"Validating {address}")
+ valid = (is_valid_ipv4_address(address)
+ or is_valid_ipv6_address(address))
+ assert_equal(valid, True)
+
+ def test_local_addresses(self, test_case, *, expect_empty=False):
+ self.log.info(f"Restart node with {test_case}")
+ self.restart_node(0, test_case)
+ network_info = self.nodes[0].getnetworkinfo()
+ network_enabled = [n for n in network_info['networks']
+ if n['reachable'] and n['name'] in ['ipv4', 'ipv6']]
+ local_addrs = list(network_info["localaddresses"])
+ if expect_empty or not network_enabled:
+ assert_equal(local_addrs, [])
+ elif len(local_addrs) > 0:
+ self.validate_addresses(local_addrs)
+
+ def run_test(self):
+ test_cases = [
+ ["-listen", "-discover"],
+ ["-discover"],
+ ]
+
+ test_cases_empty = [
+ ["-discover=0"],
+ ["-listen", "-discover=0"],
+ [],
+ ]
+
+ for test_case in test_cases:
+ self.test_local_addresses(test_case, expect_empty=False)
+
+ for test_case in test_cases_empty:
+ self.test_local_addresses(test_case, expect_empty=True)
+
+
+if __name__ == '__main__':
+ DiscoverTest().main()
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index b0cbcf4edf..05ee556ece 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 fee estimation code."""
@@ -23,7 +23,7 @@ from test_framework.wallet import MiniWallet
def small_txpuzzle_randfee(
- wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment
+ wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment, batch_reqs
):
"""Create and send a transaction with a random fee using MiniWallet.
@@ -57,12 +57,15 @@ def small_txpuzzle_randfee(
tx.vout[0].nValue = int((total_in - amount - fee) * COIN)
tx.vout.append(deepcopy(tx.vout[0]))
tx.vout[1].nValue = int(amount * COIN)
+ tx.rehash()
+ txid = tx.hash
+ tx_hex = tx.serialize().hex()
- txid = from_node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
+ batch_reqs.append(from_node.sendrawtransaction.get_request(hexstring=tx_hex, maxfeerate=0))
unconflist.append({"txid": txid, "vout": 0, "value": total_in - amount - fee})
unconflist.append({"txid": txid, "vout": 1, "value": amount})
- return (tx.serialize().hex(), fee)
+ return (tx.get_vsize(), fee)
def check_raw_estimates(node, fees_seen):
@@ -115,13 +118,12 @@ def check_estimates(node, fees_seen):
check_smart_estimates(node, fees_seen)
-def send_tx(wallet, node, utxo, feerate):
- """Broadcast a 1in-1out transaction with a specific input and feerate (sat/vb)."""
- return wallet.send_self_transfer(
- from_node=node,
+def make_tx(wallet, utxo, feerate):
+ """Create a 1in-1out transaction with a specific input and feerate (sat/vb)."""
+ return wallet.create_self_transfer(
utxo_to_spend=utxo,
fee_rate=Decimal(feerate * 1000) / COIN,
- )['txid']
+ )
class EstimateFeeTest(BitcoinTestFramework):
@@ -156,9 +158,10 @@ class EstimateFeeTest(BitcoinTestFramework):
# resorting to tx's that depend on the mempool when those run out
for _ in range(numblocks):
random.shuffle(self.confutxo)
+ batch_sendtx_reqs = []
for _ in range(random.randrange(100 - 50, 100 + 50)):
from_index = random.randint(1, 2)
- (txhex, fee) = small_txpuzzle_randfee(
+ (tx_bytes, fee) = small_txpuzzle_randfee(
self.wallet,
self.nodes[from_index],
self.confutxo,
@@ -166,9 +169,12 @@ class EstimateFeeTest(BitcoinTestFramework):
Decimal("0.005"),
min_fee,
min_fee,
+ batch_sendtx_reqs,
)
- tx_kbytes = (len(txhex) // 2) / 1000.0
+ tx_kbytes = tx_bytes / 1000.0
self.fees_per_kb.append(float(fee) / tx_kbytes)
+ for node in self.nodes:
+ node.batch(batch_sendtx_reqs)
self.sync_mempools(wait=0.1)
mined = mining_node.getblock(self.generate(mining_node, 1)[0], True)["tx"]
# update which txouts are confirmed
@@ -245,14 +251,20 @@ class EstimateFeeTest(BitcoinTestFramework):
assert_greater_than_or_equal(len(utxos), 250)
for _ in range(5):
# Broadcast 45 low fee transactions that will need to be RBF'd
+ txs = []
for _ in range(45):
u = utxos.pop(0)
- txid = send_tx(self.wallet, node, u, low_feerate)
+ tx = make_tx(self.wallet, u, low_feerate)
utxos_to_respend.append(u)
- txids_to_replace.append(txid)
+ txids_to_replace.append(tx["txid"])
+ txs.append(tx)
# Broadcast 5 low fee transaction which don't need to
for _ in range(5):
- send_tx(self.wallet, node, utxos.pop(0), low_feerate)
+ tx = make_tx(self.wallet, utxos.pop(0), low_feerate)
+ txs.append(tx)
+ batch_send_tx = [node.sendrawtransaction.get_request(tx["hex"]) for tx in txs]
+ for n in self.nodes:
+ n.batch(batch_send_tx)
# Mine the transactions on another node
self.sync_mempools(wait=0.1, nodes=[node, miner])
for txid in txids_to_replace:
@@ -261,7 +273,12 @@ class EstimateFeeTest(BitcoinTestFramework):
# RBF the low-fee transactions
while len(utxos_to_respend) > 0:
u = utxos_to_respend.pop(0)
- send_tx(self.wallet, node, u, high_feerate)
+ tx = make_tx(self.wallet, u, high_feerate)
+ node.sendrawtransaction(tx["hex"])
+ txs.append(tx)
+ dec_txs = [res["result"] for res in node.batch([node.decoderawtransaction.get_request(tx["hex"]) for tx in txs])]
+ self.wallet.scan_txs(dec_txs)
+
# Mine the last replacement txs
self.sync_mempools(wait=0.1, nodes=[node, miner])
@@ -280,7 +297,6 @@ class EstimateFeeTest(BitcoinTestFramework):
# Split two coinbases into many small utxos
self.start_node(0)
self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
self.initial_split(self.nodes[0])
self.log.info("Finished splitting")
diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py
index 945ece6a33..bb4104bf8e 100755
--- a/test/functional/feature_filelock.py
+++ b/test/functional/feature_filelock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Check that it's not possible to start a second bitcoind instance using the same datadir or wallet."""
@@ -11,6 +11,9 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.test_node import ErrorMatch
class FilelockTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py
index bc85e43a57..77a056346a 100755
--- a/test/functional/feature_index_prune.py
+++ b/test/functional/feature_index_prune.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 indices in conjunction with prune."""
@@ -62,7 +62,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
for node in filter_nodes:
assert_greater_than(len(node.getblockfilter(tip)['filter']), 0)
for node in stats_nodes:
- assert(node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash'])
+ assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash']
self.mine_batches(500)
self.sync_index(height=700)
@@ -80,14 +80,14 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
for node in filter_nodes:
assert_greater_than(len(node.getblockfilter(tip)['filter']), 0)
for node in stats_nodes:
- assert(node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash'])
+ assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash']
self.log.info("check if we can access the blockfilter and coinstats of a pruned block")
height_hash = self.nodes[0].getblockhash(2)
for node in filter_nodes:
assert_greater_than(len(node.getblockfilter(height_hash)['filter']), 0)
for node in stats_nodes:
- assert(node.gettxoutsetinfo(hash_type="muhash", hash_or_height=height_hash)['muhash'])
+ assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=height_hash)['muhash']
# mine and sync index up to a height that will later be the pruneheight
self.generate(self.nodes[0], 51)
@@ -138,6 +138,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
self.connect_nodes(i, 3)
self.sync_blocks(timeout=300)
+ self.sync_index(height=2500)
for node in self.nodes[:2]:
with node.assert_debug_log(['limited pruning to height 2489']):
diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py
index 13c7326519..70a802dc58 100755
--- a/test/functional/feature_init.py
+++ b/test/functional/feature_init.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Stress tests related to node initialization."""
@@ -17,6 +17,9 @@ class InitStressTest(BitcoinTestFramework):
subsequent starts.
"""
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = False
self.num_nodes = 1
@@ -55,7 +58,6 @@ class InitStressTest(BitcoinTestFramework):
b'Loading P2P addresses',
b'Loading banlist',
b'Loading block index',
- b'Switching active chainstate',
b'Checking all blk files are present',
b'Loaded best chain:',
b'init message: Verifying blocks',
diff --git a/test/functional/feature_maxtipage.py b/test/functional/feature_maxtipage.py
index 87f9d6962d..51f37ef1e0 100755
--- a/test/functional/feature_maxtipage.py
+++ b/test/functional/feature_maxtipage.py
@@ -2,10 +2,10 @@
# Copyright (c) 2022 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 logic for setting nMaxTipAge on command line.
+"""Test logic for setting -maxtipage on command line.
Nodes don't consider themselves out of "initial block download" as long as
-their best known block header time is more than nMaxTipAge in the past.
+their best known block header time is more than -maxtipage in the past.
"""
import time
@@ -22,23 +22,24 @@ class MaxTipAgeTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 2
- def test_maxtipage(self, maxtipage, set_parameter=True):
+ def test_maxtipage(self, maxtipage, set_parameter=True, test_deltas=True):
node_miner = self.nodes[0]
node_ibd = self.nodes[1]
self.restart_node(1, [f'-maxtipage={maxtipage}'] if set_parameter else None)
self.connect_nodes(0, 1)
-
- # tips older than maximum age -> stay in IBD
cur_time = int(time.time())
- node_ibd.setmocktime(cur_time)
- for delta in [5, 4, 3, 2, 1]:
- node_miner.setmocktime(cur_time - maxtipage - delta)
- self.generate(node_miner, 1)
- assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], True)
+
+ if test_deltas:
+ # tips older than maximum age -> stay in IBD
+ node_ibd.setmocktime(cur_time)
+ for delta in [5, 4, 3, 2, 1]:
+ node_miner.setmocktime(cur_time - maxtipage - delta)
+ self.generate(node_miner, 1)
+ assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], True)
# tip within maximum age -> leave IBD
- node_miner.setmocktime(cur_time - maxtipage)
+ node_miner.setmocktime(max(cur_time - maxtipage, 0))
self.generate(node_miner, 1)
assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], False)
@@ -51,6 +52,10 @@ class MaxTipAgeTest(BitcoinTestFramework):
self.log.info(f"Test IBD with maximum tip age of {hours} hours (-maxtipage={maxtipage}).")
self.test_maxtipage(maxtipage)
+ max_long_val = 9223372036854775807
+ self.log.info(f"Test IBD with highest allowable maximum tip age ({max_long_val}).")
+ self.test_maxtipage(max_long_val, test_deltas=False)
+
if __name__ == '__main__':
MaxTipAgeTest().main()
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index 3ea412002a..c551c0b449 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 behavior of -maxuploadtarget.
@@ -164,6 +164,9 @@ class MaxUploadTest(BitcoinTestFramework):
assert_equal(len(peer_info), 1) # node is still connected
assert_equal(peer_info[0]['permissions'], ['download'])
+ self.log.info("Test passing an unparsable value to -maxuploadtarget throws an error")
+ self.stop_node(0)
+ self.nodes[0].assert_start_raises_init_error(extra_args=["-maxuploadtarget=abc"], expected_msg="Error: Unable to parse -maxuploadtarget: 'abc'")
if __name__ == '__main__':
MaxUploadTest().main()
diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py
index fb4024b1b0..078d2ef63c 100755
--- a/test/functional/feature_minchainwork.py
+++ b/test/functional/feature_minchainwork.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 logic for setting nMinimumChainWork on command line.
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index e038afa1ad..8cb633d454 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 -alertnotify, -blocknotify and -walletnotify options."""
@@ -24,11 +24,14 @@ def notify_outputname(walletname, txid):
class NotificationsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
# The experimental syscall sandbox feature (-sandbox) is not compatible with -alertnotify,
- # -blocknotify or -walletnotify (which all invoke execve).
+ # -blocknotify, -walletnotify or -shutdownnotify (which all invoke execve).
self.disable_syscall_sandbox = True
def setup_network(self):
@@ -36,14 +39,18 @@ class NotificationsTest(BitcoinTestFramework):
self.alertnotify_dir = os.path.join(self.options.tmpdir, "alertnotify")
self.blocknotify_dir = os.path.join(self.options.tmpdir, "blocknotify")
self.walletnotify_dir = os.path.join(self.options.tmpdir, "walletnotify")
+ self.shutdownnotify_dir = os.path.join(self.options.tmpdir, "shutdownnotify")
+ self.shutdownnotify_file = os.path.join(self.shutdownnotify_dir, "shutdownnotify.txt")
os.mkdir(self.alertnotify_dir)
os.mkdir(self.blocknotify_dir)
os.mkdir(self.walletnotify_dir)
+ os.mkdir(self.shutdownnotify_dir)
# -alertnotify and -blocknotify on node0, walletnotify on node1
self.extra_args = [[
f"-alertnotify=echo > {os.path.join(self.alertnotify_dir, '%s')}",
f"-blocknotify=echo > {os.path.join(self.blocknotify_dir, '%s')}",
+ f"-shutdownnotify=echo > {self.shutdownnotify_file}",
], [
f"-walletnotify=echo %h_%b > {os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))}",
]]
@@ -159,6 +166,10 @@ class NotificationsTest(BitcoinTestFramework):
# TODO: add test for `-alertnotify` large fork notifications
+ self.log.info("test -shutdownnotify")
+ self.stop_nodes()
+ self.wait_until(lambda: os.path.isfile(self.shutdownnotify_file), timeout=10)
+
def expect_wallet_notify(self, tx_details):
self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) >= len(tx_details), timeout=10)
# Should have no more and no less files than expected
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index 9bfb79057e..d7558c830e 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 NULLDUMMY softfork.
diff --git a/test/functional/feature_posix_fs_permissions.py b/test/functional/feature_posix_fs_permissions.py
new file mode 100755
index 0000000000..c5a543e97a
--- /dev/null
+++ b/test/functional/feature_posix_fs_permissions.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 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 file system permissions for POSIX platforms.
+"""
+
+import os
+import stat
+
+from test_framework.test_framework import BitcoinTestFramework
+
+
+class PosixFsPermissionsTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_platform_not_posix()
+
+ def check_directory_permissions(self, dir):
+ mode = os.lstat(dir).st_mode
+ self.log.info(f"{stat.filemode(mode)} {dir}")
+ assert mode == (stat.S_IFDIR | stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
+
+ def check_file_permissions(self, file):
+ mode = os.lstat(file).st_mode
+ self.log.info(f"{stat.filemode(mode)} {file}")
+ assert mode == (stat.S_IFREG | stat.S_IRUSR | stat.S_IWUSR)
+
+ def run_test(self):
+ self.stop_node(0)
+ datadir = os.path.join(self.nodes[0].datadir, self.chain)
+ self.check_directory_permissions(datadir)
+ walletsdir = os.path.join(datadir, "wallets")
+ self.check_directory_permissions(walletsdir)
+ debuglog = os.path.join(datadir, "debug.log")
+ self.check_file_permissions(debuglog)
+
+
+if __name__ == '__main__':
+ PosixFsPermissionsTest().main()
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index c90852562e..662007d65e 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 bitcoind with different proxy configuration.
@@ -317,19 +317,34 @@ class ProxyTest(BitcoinTestFramework):
self.stop_node(1)
- self.log.info("Test passing invalid -proxy raises expected init error")
- self.nodes[1].extra_args = ["-proxy=abc:def"]
- msg = "Error: Invalid -proxy address or hostname: 'abc:def'"
+ self.log.info("Test passing invalid -proxy hostname raises expected init error")
+ self.nodes[1].extra_args = ["-proxy=abc..abc:23456"]
+ msg = "Error: Invalid -proxy address or hostname: 'abc..abc:23456'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
- self.log.info("Test passing invalid -onion raises expected init error")
- self.nodes[1].extra_args = ["-onion=xyz:abc"]
- msg = "Error: Invalid -onion address or hostname: 'xyz:abc'"
+ self.log.info("Test passing invalid -proxy port raises expected init error")
+ self.nodes[1].extra_args = ["-proxy=192.0.0.1:def"]
+ msg = "Error: Invalid port specified in -proxy: '192.0.0.1:def'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
- self.log.info("Test passing invalid -i2psam raises expected init error")
- self.nodes[1].extra_args = ["-i2psam=def:xyz"]
- msg = "Error: Invalid -i2psam address or hostname: 'def:xyz'"
+ self.log.info("Test passing invalid -onion hostname raises expected init error")
+ self.nodes[1].extra_args = ["-onion=xyz..xyz:23456"]
+ msg = "Error: Invalid -onion address or hostname: 'xyz..xyz:23456'"
+ self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
+
+ self.log.info("Test passing invalid -onion port raises expected init error")
+ self.nodes[1].extra_args = ["-onion=192.0.0.1:def"]
+ msg = "Error: Invalid port specified in -onion: '192.0.0.1:def'"
+ self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
+
+ self.log.info("Test passing invalid -i2psam hostname raises expected init error")
+ self.nodes[1].extra_args = ["-i2psam=def..def:23456"]
+ msg = "Error: Invalid -i2psam address or hostname: 'def..def:23456'"
+ self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
+
+ self.log.info("Test passing invalid -i2psam port raises expected init error")
+ self.nodes[1].extra_args = ["-i2psam=192.0.0.1:def"]
+ msg = "Error: Invalid port specified in -i2psam: '192.0.0.1:def'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
self.log.info("Test passing invalid -onlynet=i2p without -i2psam raises expected init error")
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 7dbeccbc09..519877ac5b 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 pruning code.
@@ -10,8 +10,11 @@ This test takes 30 mins or more (up to 2 hours)
"""
import os
-from test_framework.blocktools import create_coinbase
-from test_framework.messages import CBlock
+from test_framework.blocktools import (
+ MIN_BLOCKS_TO_KEEP,
+ create_block,
+ create_coinbase,
+)
from test_framework.script import (
CScript,
OP_NOP,
@@ -48,21 +51,7 @@ def mine_large_blocks(node, n):
previousblockhash = int(best_block["hash"], 16)
for _ in range(n):
- # Build the coinbase transaction (with large scriptPubKey)
- coinbase_tx = create_coinbase(height)
- coinbase_tx.vin[0].nSequence = 2 ** 32 - 1
- coinbase_tx.vout[0].scriptPubKey = big_script
- coinbase_tx.rehash()
-
- # Build the block
- block = CBlock()
- block.nVersion = best_block["version"]
- block.hashPrevBlock = previousblockhash
- block.nTime = mine_large_blocks.nTime
- block.nBits = int('207fffff', 16)
- block.nNonce = 0
- block.vtx = [coinbase_tx]
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(hashprev=previousblockhash, ntime=mine_large_blocks.nTime, coinbase=create_coinbase(height, script_pubkey=big_script))
block.solve()
# Submit to the node
@@ -76,6 +65,9 @@ def calc_usage(blockdir):
return sum(os.path.getsize(blockdir + f) for f in os.listdir(blockdir) if os.path.isfile(os.path.join(blockdir, f))) / (1024. * 1024.)
class PruneTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 6
@@ -92,7 +84,7 @@ class PruneTest(BitcoinTestFramework):
["-maxreceivebuffer=20000", "-prune=550"],
["-maxreceivebuffer=20000"],
["-maxreceivebuffer=20000"],
- ["-prune=550"],
+ ["-prune=550", "-blockfilterindex=1"],
]
self.rpc_timeout = 120
@@ -231,8 +223,8 @@ class PruneTest(BitcoinTestFramework):
def reorg_back(self):
# Verify that a block on the old main chain fork has been pruned away
assert_raises_rpc_error(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash)
- with self.nodes[2].assert_debug_log(expected_msgs=['block verification stopping at height', '(pruning, no data)']):
- self.nodes[2].verifychain(checklevel=4, nblocks=0)
+ with self.nodes[2].assert_debug_log(expected_msgs=['block verification stopping at height', '(no data)']):
+ assert not self.nodes[2].verifychain(checklevel=4, nblocks=0)
self.log.info(f"Will need to redownload block {self.forkheight}")
# Verify that we have enough history to reorg back to the fork point
@@ -342,7 +334,7 @@ class PruneTest(BitcoinTestFramework):
assert has_block(2), "blk00002.dat is still there, should be pruned by now"
# advance the tip so blk00002.dat and blk00003.dat can be pruned (the last 288 blocks should now be in blk00004.dat)
- self.generate(node, 288, sync_fun=self.no_op)
+ self.generate(node, MIN_BLOCKS_TO_KEEP, sync_fun=self.no_op)
prune(1000)
assert not has_block(2), "blk00002.dat is still there, should be pruned by now"
assert not has_block(3), "blk00003.dat is still there, should be pruned by now"
@@ -364,7 +356,7 @@ class PruneTest(BitcoinTestFramework):
self.connect_nodes(0, 5)
nds = [self.nodes[0], self.nodes[5]]
self.sync_blocks(nds, wait=5, timeout=300)
- self.restart_node(5, extra_args=["-prune=550"]) # restart to trigger rescan
+ self.restart_node(5, extra_args=["-prune=550", "-blockfilterindex=1"]) # restart to trigger rescan
self.log.info("Success")
def run_test(self):
@@ -480,7 +472,20 @@ class PruneTest(BitcoinTestFramework):
self.log.info("Test invalid pruning command line options")
self.test_invalid_command_line_options()
+ self.test_scanblocks_pruned()
+
self.log.info("Done")
+ def test_scanblocks_pruned(self):
+ node = self.nodes[5]
+ genesis_blockhash = node.getblockhash(0)
+ false_positive_spk = bytes.fromhex("001400000000000000000000000000000000000cadcb")
+
+ assert genesis_blockhash in node.scanblocks(
+ "start", [{"desc": f"raw({false_positive_spk.hex()})"}], 0, 0)['relevant_blocks']
+
+ assert_raises_rpc_error(-1, "Block not available (pruned data)", node.scanblocks,
+ "start", [{"desc": f"raw({false_positive_spk.hex()})"}], 0, 0, "basic", {"filter_false_positives": True})
+
if __name__ == '__main__':
PruneTest().main()
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 7603248ae5..947d2e8273 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 RBF code."""
@@ -21,6 +21,9 @@ from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
MAX_REPLACEMENT_LIMIT = 100
class ReplaceByFeeTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [
@@ -39,10 +42,6 @@ class ReplaceByFeeTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- # the pre-mined test framework chain contains coinbase outputs to the
- # MiniWallet's default address in blocks 76-100 (see method
- # BitcoinTestFramework._initialize_chain())
- self.wallet.rescan_utxos()
self.log.info("Running test simple doublespend...")
self.test_simple_doublespend()
@@ -393,12 +392,11 @@ class ReplaceByFeeTest(BitcoinTestFramework):
enough transactions off of each root UTXO to exceed the MAX_REPLACEMENT_LIMIT.
Then create a conflicting RBF replacement transaction.
"""
- normal_node = self.nodes[1]
- wallet = MiniWallet(normal_node)
- wallet.rescan_utxos()
# Clear mempools to avoid cross-node sync failure.
for node in self.nodes:
self.generate(node, 1)
+ normal_node = self.nodes[1]
+ wallet = MiniWallet(normal_node)
# This has to be chosen so that the total number of transactions can exceed
# MAX_REPLACEMENT_LIMIT without having any one tx graph run into the descendant
diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py
index 44040f426f..0f6a8fd0d2 100755
--- a/test/functional/feature_reindex.py
+++ b/test/functional/feature_reindex.py
@@ -7,9 +7,12 @@
- Start a single node and generate 3 blocks.
- Stop the node and restart it with -reindex. Verify that the node has reindexed up to block 3.
- Stop the node and restart it with -reindex-chainstate. Verify that the node has reindexed up to block 3.
+- Verify that out-of-order blocks are correctly processed, see LoadExternalBlockFile()
"""
+import os
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.p2p import MAGIC_BYTES
from test_framework.util import assert_equal
@@ -27,11 +30,58 @@ class ReindexTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getblockcount(), blockcount) # start_node is blocking on reindex
self.log.info("Success")
+ # Check that blocks can be processed out of order
+ def out_of_order(self):
+ # The previous test created 12 blocks
+ assert_equal(self.nodes[0].getblockcount(), 12)
+ self.stop_nodes()
+
+ # In this test environment, blocks will always be in order (since
+ # we're generating them rather than getting them from peers), so to
+ # test out-of-order handling, swap blocks 1 and 2 on disk.
+ blk0 = os.path.join(self.nodes[0].datadir, self.nodes[0].chain, 'blocks', 'blk00000.dat')
+ with open(blk0, 'r+b') as bf:
+ # Read at least the first few blocks (including genesis)
+ b = bf.read(2000)
+
+ # Find the offsets of blocks 2, 3, and 4 (the first 3 blocks beyond genesis)
+ # by searching for the regtest marker bytes (see pchMessageStart).
+ def find_block(b, start):
+ return b.find(MAGIC_BYTES["regtest"], start)+4
+
+ genesis_start = find_block(b, 0)
+ assert_equal(genesis_start, 4)
+ b2_start = find_block(b, genesis_start)
+ b3_start = find_block(b, b2_start)
+ b4_start = find_block(b, b3_start)
+
+ # Blocks 2 and 3 should be the same size.
+ assert_equal(b3_start-b2_start, b4_start-b3_start)
+
+ # Swap the second and third blocks (don't disturb the genesis block).
+ bf.seek(b2_start)
+ bf.write(b[b3_start:b4_start])
+ bf.write(b[b2_start:b3_start])
+
+ # The reindexing code should detect and accommodate out of order blocks.
+ with self.nodes[0].assert_debug_log([
+ 'LoadExternalBlockFile: Out of order block',
+ 'LoadExternalBlockFile: Processing out of order child',
+ ]):
+ extra_args = [["-reindex"]]
+ self.start_nodes(extra_args)
+
+ # All blocks should be accepted and processed.
+ assert_equal(self.nodes[0].getblockcount(), 12)
+
def run_test(self):
self.reindex(False)
self.reindex(True)
self.reindex(False)
self.reindex(True)
+ self.out_of_order()
+
+
if __name__ == '__main__':
ReindexTest().main()
diff --git a/test/functional/feature_remove_pruned_files_on_startup.py b/test/functional/feature_remove_pruned_files_on_startup.py
new file mode 100755
index 0000000000..ca0e5ace9f
--- /dev/null
+++ b/test/functional/feature_remove_pruned_files_on_startup.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 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 removing undeleted pruned blk files on startup."""
+
+import os
+from test_framework.test_framework import BitcoinTestFramework
+
+class FeatureRemovePrunedFilesOnStartupTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.extra_args = [["-fastprune", "-prune=1"]]
+
+ def mine_batches(self, blocks):
+ n = blocks // 250
+ for _ in range(n):
+ self.generate(self.nodes[0], 250)
+ self.generate(self.nodes[0], blocks % 250)
+ self.sync_blocks()
+
+ def run_test(self):
+ blk0 = os.path.join(self.nodes[0].datadir, self.nodes[0].chain, 'blocks', 'blk00000.dat')
+ rev0 = os.path.join(self.nodes[0].datadir, self.nodes[0].chain, 'blocks', 'rev00000.dat')
+ blk1 = os.path.join(self.nodes[0].datadir, self.nodes[0].chain, 'blocks', 'blk00001.dat')
+ rev1 = os.path.join(self.nodes[0].datadir, self.nodes[0].chain, 'blocks', 'rev00001.dat')
+ self.mine_batches(800)
+ fo1 = os.open(blk0, os.O_RDONLY)
+ fo2 = os.open(rev1, os.O_RDONLY)
+ fd1 = os.fdopen(fo1)
+ fd2 = os.fdopen(fo2)
+ self.nodes[0].pruneblockchain(600)
+
+ # Windows systems will not remove files with an open fd
+ if os.name != 'nt':
+ assert not os.path.exists(blk0)
+ assert not os.path.exists(rev0)
+ assert not os.path.exists(blk1)
+ assert not os.path.exists(rev1)
+ else:
+ assert os.path.exists(blk0)
+ assert not os.path.exists(rev0)
+ assert not os.path.exists(blk1)
+ assert os.path.exists(rev1)
+
+ # Check that the files are removed on restart once the fds are closed
+ fd1.close()
+ fd2.close()
+ self.restart_node(0)
+ assert not os.path.exists(blk0)
+ assert not os.path.exists(rev1)
+
+if __name__ == '__main__':
+ FeatureRemovePrunedFilesOnStartupTest().main()
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index 7f2a615be1..77f3e4feda 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 SegWit changeover logic."""
@@ -78,6 +78,9 @@ txs_mined = {} # txindex from txid to blockhash
class SegWitTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py
index 4c1e48af6d..b41fe378af 100755
--- a/test/functional/feature_signet.py
+++ b/test/functional/feature_signet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 basic signet functionality"""
diff --git a/test/functional/feature_startupnotify.py b/test/functional/feature_startupnotify.py
index c6aa837768..ff5272b281 100755
--- a/test/functional/feature_startupnotify.py
+++ b/test/functional/feature_startupnotify.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 -startupnotify."""
@@ -29,9 +29,14 @@ class StartupNotifyTest(BitcoinTestFramework):
self.wait_until(lambda: os.path.exists(tmpdir_file))
self.log.info("Test -startupnotify is executed once")
- with open(tmpdir_file, "r", encoding="utf8") as f:
- file_content = f.read()
- assert_equal(file_content.count(FILE_NAME), 1)
+
+ def get_count():
+ with open(tmpdir_file, "r", encoding="utf8") as f:
+ file_content = f.read()
+ return file_content.count(FILE_NAME)
+
+ self.wait_until(lambda: get_count() > 0)
+ assert_equal(get_count(), 1)
self.log.info("Test node is fully started")
assert_equal(self.nodes[0].getblockcount(), 200)
diff --git a/test/functional/feature_syscall_sandbox.py b/test/functional/feature_syscall_sandbox.py
index e430542845..2200f6c2e6 100755
--- a/test/functional/feature_syscall_sandbox.py
+++ b/test/functional/feature_syscall_sandbox.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 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 bitcoind aborts if a disallowed syscall is used when compiled with the syscall sandbox."""
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index cbb2e0338b..8ac06f570d 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 Taproot softfork (BIPs 340-342)
@@ -96,7 +96,14 @@ from test_framework.util import (
assert_equal,
random_bytes,
)
-from test_framework.key import generate_privkey, compute_xonly_pubkey, sign_schnorr, tweak_add_privkey, ECKey
+from test_framework.key import (
+ generate_privkey,
+ compute_xonly_pubkey,
+ sign_schnorr,
+ tweak_add_privkey,
+ ECKey,
+ SECP256K1
+)
from test_framework.address import (
hash160,
program_to_witness,
@@ -661,6 +668,44 @@ def spenders_taproot_active():
# Test with signature with bit flipped.
add_spender(spenders, "sig/bitflip", tap=tap, key=secs[0], failure={"signature": bitflipper(default_signature)}, **ERR_SIG_SCHNORR)
+ # == Test involving an internal public key not on the curve ==
+
+ # X-only public keys are 32 bytes, but not every 32-byte array is a valid public key; only
+ # around 50% of them are. This does not affect users using correct software; these "keys" have
+ # no corresponding private key, and thus will never appear as output of key
+ # generation/derivation/tweaking.
+ #
+ # Using an invalid public key as P2TR output key makes the UTXO unspendable. Revealing an
+ # invalid public key as internal key in a P2TR script path spend also makes the spend invalid.
+ # These conditions are explicitly spelled out in BIP341.
+ #
+ # It is however hard to create test vectors for this, because it involves "guessing" how a
+ # hypothetical incorrect implementation deals with an obviously-invalid condition, and making
+ # sure that guessed behavior (accepting it in certain condition) doesn't occur.
+ #
+ # The test case added here tries to detect a very specific bug a verifier could have: if they
+ # don't verify whether or not a revealed internal public key in a script path spend is valid,
+ # and (correctly) implement output_key == tweak(internal_key, tweakval) but (incorrectly) treat
+ # tweak(invalid_key, tweakval) as equal the public key corresponding to private key tweakval.
+ # This may seem like a far-fetched edge condition to test for, but in fact, the BIP341 wallet
+ # pseudocode did exactly that (but obviously only triggerable by someone invoking the tweaking
+ # function with an invalid public key, which shouldn't happen).
+
+ # Generate an invalid public key
+ while True:
+ invalid_pub = random_bytes(32)
+ if not SECP256K1.is_x_coord(int.from_bytes(invalid_pub, 'big')):
+ break
+
+ # Implement a test case that detects validation logic which maps invalid public keys to the
+ # point at infinity in the tweaking logic.
+ tap = taproot_construct(invalid_pub, [("true", CScript([OP_1]))], treat_internal_as_infinity=True)
+ add_spender(spenders, "output/invalid_x", tap=tap, key_tweaked=tap.tweak, failure={"leaf": "true", "inputs": []}, **ERR_WITNESS_PROGRAM_MISMATCH)
+
+ # Do the same thing without invalid point, to make sure there is no mistake in the test logic.
+ tap = taproot_construct(pubs[0], [("true", CScript([OP_1]))])
+ add_spender(spenders, "output/invalid_x_mock", tap=tap, key=secs[0], leaf="true", inputs=[])
+
# == Tests for signature hashing ==
# Run all tests once with no annex, and once with a valid random annex.
@@ -705,7 +750,7 @@ def spenders_taproot_active():
# Reusing the scripts above, test that various features affect the sighash.
add_spender(spenders, "sighash/annex", tap=tap, leaf="pk_codesep", key=secs[1], hashtype=hashtype, standard=False, **SINGLE_SIG, annex=bytes([ANNEX_TAG]), failure={"sighash": override(default_sighash, annex=None)}, **ERR_SIG_SCHNORR)
add_spender(spenders, "sighash/script", tap=tap, leaf="pk_codesep", key=secs[1], **common, **SINGLE_SIG, failure={"sighash": override(default_sighash, script_taproot=tap.leaves["codesep_pk"].script)}, **ERR_SIG_SCHNORR)
- add_spender(spenders, "sighash/leafver", tap=tap, leaf="pk_codesep", key=secs[1], **common, **SINGLE_SIG, failure={"sighash": override(default_sighash, leafversion=random.choice([x & 0xFE for x in range(0x100) if x & 0xFE != 0xC0]))}, **ERR_SIG_SCHNORR)
+ add_spender(spenders, "sighash/leafver", tap=tap, leaf="pk_codesep", key=secs[1], **common, **SINGLE_SIG, failure={"sighash": override(default_sighash, leafversion=random.choice([x & 0xFE for x in range(0x100) if x & 0xFE != LEAF_VERSION_TAPSCRIPT]))}, **ERR_SIG_SCHNORR)
add_spender(spenders, "sighash/scriptpath", tap=tap, leaf="pk_codesep", key=secs[1], **common, **SINGLE_SIG, failure={"sighash": override(default_sighash, leaf=None)}, **ERR_SIG_SCHNORR)
add_spender(spenders, "sighash/keypath", tap=tap, key=secs[0], **common, failure={"sighash": override(default_sighash, leaf="pk_codesep")}, **ERR_SIG_SCHNORR)
@@ -1229,6 +1274,7 @@ UTXOData = namedtuple('UTXOData', 'outpoint,output,spender')
class TaprootTest(BitcoinTestFramework):
def add_options(self, parser):
+ self.add_wallet_options(parser)
parser.add_argument("--dumptests", dest="dump_tests", default=False, action="store_true",
help="Dump generated test cases to directory set by TEST_DUMP_DIR environment variable")
@@ -1246,7 +1292,7 @@ class TaprootTest(BitcoinTestFramework):
# It is not impossible to fit enough tapscript sigops to hit the old 80k limit without
# busting txin-level limits. We simply have to account for the p2pk outputs in all
# transactions.
- extra_output_script = CScript([OP_CHECKSIG]*((MAX_BLOCK_SIGOPS_WEIGHT - sigops_weight) // WITNESS_SCALE_FACTOR))
+ extra_output_script = CScript(bytes([OP_CHECKSIG]*((MAX_BLOCK_SIGOPS_WEIGHT - sigops_weight) // WITNESS_SCALE_FACTOR)))
coinbase_tx = create_coinbase(self.lastblockheight + 1, pubkey=cb_pubkey, extra_output_script=extra_output_script, fees=fees)
block = create_block(self.tip, coinbase_tx, self.lastblocktime + 1, txlist=txs)
@@ -1509,12 +1555,16 @@ class TaprootTest(BitcoinTestFramework):
script_lists = [
None,
- [("0", CScript([pubs[50], OP_CHECKSIG]), 0xc0)],
- [("0", CScript([pubs[51], OP_CHECKSIG]), 0xc0)],
- [("0", CScript([pubs[52], OP_CHECKSIG]), 0xc0), ("1", CScript([b"BIP341"]), VALID_LEAF_VERS[pubs[99][0] % 41])],
- [("0", CScript([pubs[53], OP_CHECKSIG]), 0xc0), ("1", CScript([b"Taproot"]), VALID_LEAF_VERS[pubs[99][1] % 41])],
- [("0", CScript([pubs[54], OP_CHECKSIG]), 0xc0), [("1", CScript([pubs[55], OP_CHECKSIG]), 0xc0), ("2", CScript([pubs[56], OP_CHECKSIG]), 0xc0)]],
- [("0", CScript([pubs[57], OP_CHECKSIG]), 0xc0), [("1", CScript([pubs[58], OP_CHECKSIG]), 0xc0), ("2", CScript([pubs[59], OP_CHECKSIG]), 0xc0)]],
+ [("0", CScript([pubs[50], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT)],
+ [("0", CScript([pubs[51], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT)],
+ [("0", CScript([pubs[52], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT), ("1", CScript([b"BIP341"]), VALID_LEAF_VERS[pubs[99][0] % 41])],
+ [("0", CScript([pubs[53], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT), ("1", CScript([b"Taproot"]), VALID_LEAF_VERS[pubs[99][1] % 41])],
+ [("0", CScript([pubs[54], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT),
+ [("1", CScript([pubs[55], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT), ("2", CScript([pubs[56], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT)]
+ ],
+ [("0", CScript([pubs[57], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT),
+ [("1", CScript([pubs[58], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT), ("2", CScript([pubs[59], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT)]
+ ],
]
taps = [taproot_construct(inner_keys[i], script_lists[i]) for i in range(len(inner_keys))]
diff --git a/test/functional/feature_txindex_compatibility.py b/test/functional/feature_txindex_compatibility.py
index 20b023d82c..48fefaa0ba 100755
--- a/test/functional/feature_txindex_compatibility.py
+++ b/test/functional/feature_txindex_compatibility.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 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 that legacy txindex will be disabled on upgrade.
@@ -14,7 +14,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.wallet import MiniWallet
-class MempoolCompatibilityTest(BitcoinTestFramework):
+class TxindexCompatibilityTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 3
self.extra_args = [
@@ -33,7 +33,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
versions=[
160300, # Last release with legacy txindex
None, # For MiniWallet, without migration code
- 200100, # Any release with migration code (0.17.x - 22.x)
+ 220000, # Last release with migration code (0.17.x - 22.x)
],
)
self.start_nodes()
@@ -42,7 +42,6 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
def run_test(self):
mini_wallet = MiniWallet(self.nodes[1])
- mini_wallet.rescan_utxos()
spend_utxo = mini_wallet.get_utxo()
mini_wallet.send_self_transfer(from_node=self.nodes[1], utxo_to_spend=spend_utxo)
self.generate(self.nodes[1], 1)
@@ -89,4 +88,4 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
if __name__ == "__main__":
- MempoolCompatibilityTest().main()
+ TxindexCompatibilityTest().main()
diff --git a/test/functional/feature_utxo_set_hash.py b/test/functional/feature_utxo_set_hash.py
index 4d486bc6f4..0f510ced89 100755
--- a/test/functional/feature_utxo_set_hash.py
+++ b/test/functional/feature_utxo_set_hash.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 UTXO set hash value calculation in gettxoutsetinfo."""
diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py
index 1572463308..0a9e1d4448 100755
--- a/test/functional/feature_versionbits_warning.py
+++ b/test/functional/feature_versionbits_warning.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 version bits warning system.
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index db5564ac50..25ea557217 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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-cli"""
@@ -66,11 +66,12 @@ def cli_get_info_string_to_dict(cli_get_info_string):
class TestBitcoinCli(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
- if self.is_specified_wallet_compiled():
- self.requires_wallet = True
def skip_test_if_missing_module(self):
self.skip_if_no_cli()
@@ -84,6 +85,15 @@ class TestBitcoinCli(BitcoinTestFramework):
rpc_response = self.nodes[0].getblockchaininfo()
assert_equal(cli_response, rpc_response)
+ self.log.info("Test named arguments")
+ assert_equal(self.nodes[0].cli.echo(0, 1, arg3=3, arg5=5), ['0', '1', None, '3', None, '5'])
+ assert_raises_rpc_error(-8, "Parameter arg1 specified twice both as positional and named argument", self.nodes[0].cli.echo, 0, 1, arg1=1)
+ assert_raises_rpc_error(-8, "Parameter arg1 specified twice both as positional and named argument", self.nodes[0].cli.echo, 0, None, 2, arg1=1)
+
+ self.log.info("Test that later cli named arguments values silently overwrite earlier ones")
+ assert_equal(self.nodes[0].cli("-named", "echo", "arg0=0", "arg1=1", "arg2=2", "arg1=3").send_cli(), ['0', '3', '2'])
+ assert_raises_rpc_error(-8, "Parameter args specified multiple times", self.nodes[0].cli("-named", "echo", "args=[0,1,2,3]", "4", "5", "6", ).send_cli)
+
user, password = get_auth_cookie(self.nodes[0].datadir, self.chain)
self.log.info("Test -stdinrpcpass option")
@@ -114,6 +124,7 @@ class TestBitcoinCli(BitcoinTestFramework):
self.log.info("Test -getinfo returns expected network and blockchain info")
if self.is_specified_wallet_compiled():
+ self.import_deterministic_coinbase_privkeys()
self.nodes[0].encryptwallet(password)
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index 610a28c56b..aafee7e87c 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 REST API."""
@@ -96,7 +96,6 @@ class RESTTest (BitcoinTestFramework):
def run_test(self):
self.url = urllib.parse.urlparse(self.nodes[0].url)
self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
self.log.info("Broadcast test transaction and sync nodes")
txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=int(0.1 * COIN))
@@ -348,6 +347,34 @@ class RESTTest (BitcoinTestFramework):
assert_equal(json_obj[tx]['spentby'], txs[i + 1:i + 2])
assert_equal(json_obj[tx]['depends'], txs[i - 1:i])
+ # Check the mempool response for explicit parameters
+ json_obj = self.test_rest_request("/mempool/contents", query_params={"verbose": "true", "mempool_sequence": "false"})
+ assert_equal(json_obj, raw_mempool_verbose)
+
+ # Check the mempool response for not verbose
+ json_obj = self.test_rest_request("/mempool/contents", query_params={"verbose": "false"})
+ raw_mempool = self.nodes[0].getrawmempool(verbose=False)
+
+ assert_equal(json_obj, raw_mempool)
+
+ # Check the mempool response for sequence
+ json_obj = self.test_rest_request("/mempool/contents", query_params={"verbose": "false", "mempool_sequence": "true"})
+ raw_mempool = self.nodes[0].getrawmempool(verbose=False, mempool_sequence=True)
+
+ assert_equal(json_obj, raw_mempool)
+
+ # Check for error response if verbose=true and mempool_sequence=true
+ resp = self.test_rest_request("/mempool/contents", ret_type=RetType.OBJ, status=400, query_params={"verbose": "true", "mempool_sequence": "true"})
+ assert_equal(resp.read().decode('utf-8').strip(), 'Verbose results cannot contain mempool sequence values. (hint: set "verbose=false")')
+
+ # Check for error response if verbose is not "true" or "false"
+ resp = self.test_rest_request("/mempool/contents", ret_type=RetType.OBJ, status=400, query_params={"verbose": "TRUE"})
+ assert_equal(resp.read().decode('utf-8').strip(), 'The "verbose" query parameter must be either "true" or "false".')
+
+ # Check for error response if mempool_sequence is not "true" or "false"
+ resp = self.test_rest_request("/mempool/contents", ret_type=RetType.OBJ, status=400, query_params={"verbose": "false", "mempool_sequence": "TRUE"})
+ assert_equal(resp.read().decode('utf-8').strip(), 'The "mempool_sequence" query parameter must be either "true" or "false".')
+
# Now mine the transactions
newblockhash = self.generate(self.nodes[1], 1)
@@ -387,6 +414,17 @@ class RESTTest (BitcoinTestFramework):
assert_equal(self.test_rest_request(f"/headers/{bb_hash}", query_params={"count": 1}), self.test_rest_request(f"/headers/1/{bb_hash}"))
assert_equal(self.test_rest_request(f"/blockfilterheaders/basic/{bb_hash}", query_params={"count": 1}), self.test_rest_request(f"/blockfilterheaders/basic/5/{bb_hash}"))
+ self.log.info("Test the /deploymentinfo URI")
+
+ deployment_info = self.nodes[0].getdeploymentinfo()
+ assert_equal(deployment_info, self.test_rest_request('/deploymentinfo'))
+
+ non_existing_blockhash = '42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4'
+ resp = self.test_rest_request(f'/deploymentinfo/{non_existing_blockhash}', ret_type=RetType.OBJ, status=400)
+ assert_equal(resp.read().decode('utf-8').rstrip(), "Block not found")
+
+ resp = self.test_rest_request(f"/deploymentinfo/{INVALID_PARAM}", ret_type=RetType.OBJ, status=400)
+ assert_equal(resp.read().decode('utf-8').rstrip(), f"Invalid hash: {INVALID_PARAM}")
if __name__ == '__main__':
RESTTest().main()
diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py
index 48082f3a17..3725c89719 100755
--- a/test/functional/interface_rpc.py
+++ b/test/functional/interface_rpc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests some generic aspects of the RPC interface."""
@@ -25,7 +25,7 @@ def expect_http_status(expected_http_status, expected_rpc_code,
def test_work_queue_getblock(node, got_exceeded_error):
while not got_exceeded_error:
try:
- node.cli('getrpcinfo').send_cli()
+ node.cli("waitfornewblock", "500").send_cli()
except subprocess.CalledProcessError as e:
assert_equal(e.output, 'error: Server response: Work queue depth exceeded\n')
got_exceeded_error.append(True)
diff --git a/test/functional/interface_usdt_coinselection.py b/test/functional/interface_usdt_coinselection.py
index ef32feda99..a3c830bb51 100755
--- a/test/functional/interface_usdt_coinselection.py
+++ b/test/functional/interface_usdt_coinselection.py
@@ -97,6 +97,9 @@ int trace_aps_create_tx(struct pt_regs *ctx) {
class CoinSelectionTracepointTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py
index 2280de1479..23785b1e8a 100755
--- a/test/functional/interface_usdt_utxocache.py
+++ b/test/functional/interface_usdt_utxocache.py
@@ -144,7 +144,6 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- self.generate(self.wallet, 101)
self.test_uncache()
self.test_add_spent()
@@ -357,8 +356,8 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
"size": event.size
})
# sanity checks only
- assert(event.memory > 0)
- assert(event.duration > 0)
+ assert event.memory > 0
+ assert event.duration > 0
handle_flush_succeeds += 1
bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py
index 8953dd023b..4323aef771 100755
--- a/test/functional/interface_usdt_validation.py
+++ b/test/functional/interface_usdt_validation.py
@@ -112,7 +112,7 @@ class ValidationTracepointTest(BitcoinTestFramework):
assert_equal(len([tx["vin"] for tx in block["tx"]]), event.inputs)
assert_equal(0, event.sigops) # no sigops in coinbase tx
# only plausibility checks
- assert(event.duration > 0)
+ assert event.duration > 0
del expected_blocks[block_hash]
blocks_checked += 1
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index 7d8d10589b..2f41f9aa53 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 ZMQ notification interface."""
@@ -22,6 +22,7 @@ from test_framework.messages import (
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
+ p2p_port,
)
from test_framework.wallet import (
MiniWallet,
@@ -106,6 +107,7 @@ class ZMQTest (BitcoinTestFramework):
# This test isn't testing txn relay/timing, so set whitelist on the
# peers for instant txn relay. This speeds up the test run time 2-3x.
self.extra_args = [["-whitelist=noban@127.0.0.1"]] * self.num_nodes
+ self.zmq_port_base = p2p_port(self.num_nodes + 1)
def skip_test_if_missing_module(self):
self.skip_if_no_py3_zmq()
@@ -179,7 +181,7 @@ class ZMQTest (BitcoinTestFramework):
# Invalid zmq arguments don't take down the node, see #17185.
self.restart_node(0, ["-zmqpubrawtx=foo", "-zmqpubhashtx=bar"])
- address = 'tcp://127.0.0.1:28332'
+ address = f"tcp://127.0.0.1:{self.zmq_port_base}"
subs = self.setup_zmq_test([(topic, address) for topic in ["hashblock", "hashtx", "rawblock", "rawtx"]])
hashblock = subs[0]
@@ -213,7 +215,6 @@ class ZMQTest (BitcoinTestFramework):
assert_equal([txid.hex()], self.nodes[1].getblock(hash)["tx"])
- self.wallet.rescan_utxos()
self.log.info("Wait for tx from second node")
payment_tx = self.wallet.send_self_transfer(from_node=self.nodes[1])
payment_txid = payment_tx['txid']
@@ -246,7 +247,7 @@ class ZMQTest (BitcoinTestFramework):
def test_reorg(self):
- address = 'tcp://127.0.0.1:28333'
+ address = f"tcp://127.0.0.1:{self.zmq_port_base}"
# Should only notify the tip if a reorg occurs
hashblock, hashtx = self.setup_zmq_test(
@@ -300,7 +301,7 @@ class ZMQTest (BitcoinTestFramework):
<32-byte hash>A<8-byte LE uint> : Transactionhash added mempool
"""
self.log.info("Testing 'sequence' publisher")
- [seq] = self.setup_zmq_test([("sequence", "tcp://127.0.0.1:28333")])
+ [seq] = self.setup_zmq_test([("sequence", f"tcp://127.0.0.1:{self.zmq_port_base}")])
self.disconnect_nodes(0, 1)
# Mempool sequence number starts at 1
@@ -444,7 +445,7 @@ class ZMQTest (BitcoinTestFramework):
"""
self.log.info("Testing 'mempool sync' usage of sequence notifier")
- [seq] = self.setup_zmq_test([("sequence", "tcp://127.0.0.1:28333")])
+ [seq] = self.setup_zmq_test([("sequence", f"tcp://127.0.0.1:{self.zmq_port_base}")])
# In-memory counter, should always start at 1
next_mempool_seq = self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"]
@@ -549,8 +550,8 @@ class ZMQTest (BitcoinTestFramework):
# chain lengths on node0 and node1; for this test we only need node0, so
# we can disable syncing blocks on the setup)
subscribers = self.setup_zmq_test([
- ("hashblock", "tcp://127.0.0.1:28334"),
- ("hashblock", "tcp://127.0.0.1:28335"),
+ ("hashblock", f"tcp://127.0.0.1:{self.zmq_port_base + 1}"),
+ ("hashblock", f"tcp://127.0.0.1:{self.zmq_port_base + 2}"),
], sync_blocks=False)
# Generate 1 block in nodes[0] and receive all notifications
@@ -567,7 +568,7 @@ class ZMQTest (BitcoinTestFramework):
self.log.info("Testing IPv6")
# Set up subscriber using IPv6 loopback address
subscribers = self.setup_zmq_test([
- ("hashblock", "tcp://[::1]:28332")
+ ("hashblock", f"tcp://[::1]:{self.zmq_port_base}")
], ipv6=True)
# Generate 1 block in nodes[0]
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 02ec18140c..362b407062 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 mempool acceptance of raw transactions."""
@@ -14,7 +14,9 @@ from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
COIN,
COutPoint,
+ CTransaction,
CTxIn,
+ CTxInWitness,
CTxOut,
MAX_BLOCK_WEIGHT,
MAX_MONEY,
@@ -26,13 +28,19 @@ from test_framework.script import (
OP_0,
OP_HASH160,
OP_RETURN,
+ OP_TRUE,
)
from test_framework.script_util import (
+ DUMMY_MIN_OP_RETURN_SCRIPT,
keys_to_multisig_script,
+ MIN_PADDING,
+ MIN_STANDARD_TX_NONWITNESS_SIZE,
script_to_p2sh_script,
+ script_to_p2wsh_script,
)
from test_framework.util import (
assert_equal,
+ assert_greater_than,
assert_raises_rpc_error,
)
from test_framework.wallet import MiniWallet
@@ -50,14 +58,17 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
"""Wrapper to check result of testmempoolaccept on node_0's mempool"""
result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
for r in result_test:
- r.pop('wtxid') # Skip check for now
+ # Skip these checks for now
+ r.pop('wtxid')
+ if "fees" in r:
+ r["fees"].pop("effective-feerate")
+ r["fees"].pop("effective-includes")
assert_equal(result_expected, result_test)
assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size) # Must not change mempool state
def run_test(self):
node = self.nodes[0]
self.wallet = MiniWallet(node)
- self.wallet.rescan_utxos()
self.log.info('Start with empty mempool, and 200 blocks')
self.mempool_size = 0
@@ -333,6 +344,35 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
maxfeerate=0,
)
+ # Prep for tiny-tx tests with wsh(OP_TRUE) output
+ seed_tx = self.wallet.send_to(from_node=node, scriptPubKey=script_to_p2wsh_script(CScript([OP_TRUE])), amount=COIN)
+ self.generate(node, 1)
+
+ self.log.info('A tiny transaction(in non-witness bytes) that is disallowed')
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int(seed_tx[0], 16), seed_tx[1]), b"", SEQUENCE_FINAL))
+ tx.wit.vtxinwit = [CTxInWitness()]
+ tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
+ tx.vout.append(CTxOut(0, CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 2)))))
+ # Note it's only non-witness size that matters!
+ assert_equal(len(tx.serialize_without_witness()), 64)
+ assert_equal(MIN_STANDARD_TX_NONWITNESS_SIZE - 1, 64)
+ assert_greater_than(len(tx.serialize()), 64)
+
+ self.check_mempool_result(
+ result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'tx-size-small'}],
+ rawtxs=[tx.serialize().hex()],
+ maxfeerate=0,
+ )
+
+ self.log.info('Minimally-small transaction(in non-witness bytes) that is allowed')
+ tx.vout[0] = CTxOut(COIN - 1000, DUMMY_MIN_OP_RETURN_SCRIPT)
+ assert_equal(len(tx.serialize_without_witness()), MIN_STANDARD_TX_NONWITNESS_SIZE)
+ self.check_mempool_result(
+ result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}],
+ rawtxs=[tx.serialize().hex()],
+ maxfeerate=0,
+ )
if __name__ == '__main__':
MempoolAcceptanceTest().main()
diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py
index c545a7f68d..a7bdc49695 100755
--- a/test/functional/mempool_compatibility.py
+++ b/test/functional/mempool_compatibility.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 that mempool.dat is both backward and forward compatible between versions
@@ -7,7 +7,7 @@
NOTE: The test is designed to prevent cases when compatibility is broken accidentally.
In case we need to break mempool compatibility we can continue to use the test by just bumping the version number.
-The previous release v0.19.1 is required by this test, see test/README.md.
+Previous releases are required by this test, see test/README.md.
"""
import os
@@ -23,23 +23,22 @@ from test_framework.wallet import (
class MempoolCompatibilityTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.wallet_names = [None]
def skip_test_if_missing_module(self):
self.skip_if_no_previous_releases()
def setup_network(self):
self.add_nodes(self.num_nodes, versions=[
- 190100, # oldest version with getmempoolinfo.loaded (used to avoid intermittent issues)
+ 200100, # Last release with previous mempool format
None,
])
self.start_nodes()
- self.import_deterministic_coinbase_privkeys()
def run_test(self):
self.log.info("Test that mempool.dat is compatible between versions")
old_node, new_node = self.nodes
+ assert "unbroadcastcount" not in old_node.getmempoolinfo()
new_wallet = MiniWallet(new_node, mode=MiniWalletMode.RAW_P2PK)
self.generate(new_wallet, 1, sync_fun=self.no_op)
self.generate(new_node, COINBASE_MATURITY, sync_fun=self.no_op)
@@ -48,11 +47,10 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
# unbroadcasted_tx won't pass old_node's `MemPoolAccept::PreChecks`.
self.connect_nodes(0, 1)
self.sync_blocks()
- recipient = old_node.getnewaddress()
self.stop_node(1)
self.log.info("Add a transaction to mempool on old node and shutdown")
- old_tx_hash = old_node.sendtoaddress(recipient, 0.0001)
+ old_tx_hash = new_wallet.send_self_transfer(from_node=old_node)["txid"]
assert old_tx_hash in old_node.getrawmempool()
self.stop_node(0)
diff --git a/test/functional/mempool_datacarrier.py b/test/functional/mempool_datacarrier.py
index 13df564a37..c370d8fa91 100755
--- a/test/functional/mempool_datacarrier.py
+++ b/test/functional/mempool_datacarrier.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 datacarrier functionality"""
@@ -44,7 +44,6 @@ class DataCarrierTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
# By default, only 80 bytes are used for data (+1 for OP_RETURN, +2 for the pushdata opcodes).
default_size_data = random_bytes(MAX_OP_RETURN_RELAY - 3)
diff --git a/test/functional/mempool_dust.py b/test/functional/mempool_dust.py
new file mode 100755
index 0000000000..41a26e82da
--- /dev/null
+++ b/test/functional/mempool_dust.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 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 dust limit mempool policy (`-dustrelayfee` parameter)"""
+from decimal import Decimal
+
+from test_framework.key import ECKey
+from test_framework.messages import (
+ COIN,
+ CTxOut,
+)
+from test_framework.script import (
+ CScript,
+ OP_RETURN,
+ OP_TRUE,
+)
+from test_framework.script_util import (
+ key_to_p2pk_script,
+ key_to_p2pkh_script,
+ key_to_p2wpkh_script,
+ keys_to_multisig_script,
+ output_key_to_p2tr_script,
+ program_to_witness_script,
+ script_to_p2sh_script,
+ script_to_p2wsh_script,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.test_node import TestNode
+from test_framework.util import (
+ assert_equal,
+ get_fee,
+)
+from test_framework.wallet import MiniWallet
+
+
+DUST_RELAY_TX_FEE = 3000 # default setting [sat/kvB]
+
+
+class DustRelayFeeTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def test_dust_output(self, node: TestNode, dust_relay_fee: Decimal,
+ output_script: CScript, type_desc: str) -> None:
+ # determine dust threshold (see `GetDustThreshold`)
+ if output_script[0] == OP_RETURN:
+ dust_threshold = 0
+ else:
+ tx_size = len(CTxOut(nValue=0, scriptPubKey=output_script).serialize())
+ tx_size += 67 if output_script.IsWitnessProgram() else 148
+ dust_threshold = int(get_fee(tx_size, dust_relay_fee) * COIN)
+ self.log.info(f"-> Test {type_desc} output (size {len(output_script)}, limit {dust_threshold})")
+
+ # amount right on the dust threshold should pass
+ tx = self.wallet.create_self_transfer()["tx"]
+ tx.vout.append(CTxOut(nValue=dust_threshold, scriptPubKey=output_script))
+ tx.vout[0].nValue -= dust_threshold # keep total output value constant
+ tx_good_hex = tx.serialize().hex()
+ res = node.testmempoolaccept([tx_good_hex])[0]
+ assert_equal(res['allowed'], True)
+
+ # amount just below the dust threshold should fail
+ if dust_threshold > 0:
+ tx.vout[1].nValue -= 1
+ res = node.testmempoolaccept([tx.serialize().hex()])[0]
+ assert_equal(res['allowed'], False)
+ assert_equal(res['reject-reason'], 'dust')
+
+ # finally send the transaction to avoid running out of MiniWallet UTXOs
+ self.wallet.sendrawtransaction(from_node=node, tx_hex=tx_good_hex)
+
+ def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
+
+ # prepare output scripts of each standard type
+ key = ECKey()
+ key.generate(compressed=False)
+ uncompressed_pubkey = key.get_pubkey().get_bytes()
+ key.generate(compressed=True)
+ pubkey = key.get_pubkey().get_bytes()
+
+ output_scripts = (
+ (key_to_p2pk_script(uncompressed_pubkey), "P2PK (uncompressed)"),
+ (key_to_p2pk_script(pubkey), "P2PK (compressed)"),
+ (key_to_p2pkh_script(pubkey), "P2PKH"),
+ (script_to_p2sh_script(CScript([OP_TRUE])), "P2SH"),
+ (key_to_p2wpkh_script(pubkey), "P2WPKH"),
+ (script_to_p2wsh_script(CScript([OP_TRUE])), "P2WSH"),
+ (output_key_to_p2tr_script(pubkey[1:]), "P2TR"),
+ # witness programs for segwitv2+ can be between 2 and 40 bytes
+ (program_to_witness_script(2, b'\x66' * 2), "P2?? (future witness version 2)"),
+ (program_to_witness_script(16, b'\x77' * 40), "P2?? (future witness version 16)"),
+ # largest possible output script considered standard
+ (keys_to_multisig_script([uncompressed_pubkey]*3), "bare multisig (m-of-3)"),
+ (CScript([OP_RETURN, b'superimportanthash']), "null data (OP_RETURN)"),
+ )
+
+ # test default (no parameter), disabled (=0) and a bunch of arbitrary dust fee rates [sat/kvB]
+ for dustfee_sat_kvb in (DUST_RELAY_TX_FEE, 0, 1, 66, 500, 1337, 12345, 21212, 333333):
+ dustfee_btc_kvb = dustfee_sat_kvb / Decimal(COIN)
+ if dustfee_sat_kvb == DUST_RELAY_TX_FEE:
+ self.log.info(f"Test default dust limit setting ({dustfee_sat_kvb} sat/kvB)...")
+ else:
+ dust_parameter = f"-dustrelayfee={dustfee_btc_kvb:.8f}"
+ self.log.info(f"Test dust limit setting {dust_parameter} ({dustfee_sat_kvb} sat/kvB)...")
+ self.restart_node(0, extra_args=[dust_parameter])
+
+ for output_script, description in output_scripts:
+ self.test_dust_output(self.nodes[0], dustfee_btc_kvb, output_script, description)
+ self.generate(self.nodes[0], 1)
+
+
+if __name__ == '__main__':
+ DustRelayFeeTest().main()
diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py
index 21721177e6..15a5f765df 100755
--- a/test/functional/mempool_expiry.py
+++ b/test/functional/mempool_expiry.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests that a mempool transaction expires after a given timeout and that its
@@ -12,7 +12,6 @@ definable expiry timeout via the '-mempoolexpiry=<n>' command line argument
from datetime import timedelta
-from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import DEFAULT_MEMPOOL_EXPIRY_HOURS
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -27,17 +26,11 @@ CUSTOM_MEMPOOL_EXPIRY = 10 # hours
class MempoolExpiryTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.setup_clean_chain = True
def test_transaction_expiry(self, timeout):
"""Tests that a transaction expires after the expiry timeout and its
children are removed as well."""
node = self.nodes[0]
- self.wallet = MiniWallet(node)
-
- # Add enough mature utxos to the wallet so that all txs spend confirmed coins.
- self.generate(self.wallet, 4)
- self.generate(node, COINBASE_MATURITY)
# Send a parent transaction that will expire.
parent_txid = self.wallet.send_self_transfer(from_node=node)['txid']
@@ -97,6 +90,8 @@ class MempoolExpiryTest(BitcoinTestFramework):
assert_equal(half_expiry_time, node.getmempoolentry(independent_txid)['time'])
def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
+
self.log.info('Test default mempool expiry timeout of %d hours.' %
DEFAULT_MEMPOOL_EXPIRY_HOURS)
self.test_transaction_expiry(DEFAULT_MEMPOOL_EXPIRY_HOURS)
diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py
index 7080662b49..d38a37f952 100755
--- a/test/functional/mempool_limit.py
+++ b/test/functional/mempool_limit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 mempool limiting together/eviction with the wallet."""
@@ -25,7 +25,6 @@ class MempoolLimitTest(BitcoinTestFramework):
self.extra_args = [[
"-datacarriersize=100000",
"-maxmempool=5",
- "-spendzeroconfchange=0",
]]
self.supports_cli = False
diff --git a/test/functional/mempool_package_limits.py b/test/functional/mempool_package_limits.py
index 1f12e93982..63f5a3e3d3 100755
--- a/test/functional/mempool_package_limits.py
+++ b/test/functional/mempool_package_limits.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 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 logic for limiting mempool and package ancestors/descendants."""
@@ -45,7 +45,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
assert_equal(0, node.getmempoolinfo()["size"])
chain_hex = []
- chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=mempool_count)
+ chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=mempool_count)[-1]["new_utxo"]
# in-package transactions
for _ in range(package_count):
tx = self.wallet.create_self_transfer(utxo_to_spend=chaintip_utxo)
@@ -100,13 +100,13 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
package_hex = []
# Chain A (M2a... M12a)
- chain_a_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=11, utxo_to_spend=m1_utxos[0])
+ chain_a_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=11, utxo_to_spend=m1_utxos[0])[-1]["new_utxo"]
# Pa
pa_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_a_tip_utxo)["hex"]
package_hex.append(pa_hex)
# Chain B (M2b... M13b)
- chain_b_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12, utxo_to_spend=m1_utxos[1])
+ chain_b_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12, utxo_to_spend=m1_utxos[1])[-1]["new_utxo"]
# Pb
pb_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_b_tip_utxo)["hex"]
package_hex.append(pb_hex)
@@ -145,7 +145,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']
# Chain M2...M24
- self.wallet.send_self_transfer_chain(from_node=node, chain_length=23, utxo_to_spend=m1_utxos[0])
+ self.wallet.send_self_transfer_chain(from_node=node, chain_length=23, utxo_to_spend=m1_utxos[0])[-1]["new_utxo"]
# P1
p1_tx = self.wallet.create_self_transfer(utxo_to_spend=m1_utxos[1])
@@ -191,7 +191,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
# Two chains of 13 transactions each
for _ in range(2):
- chain_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)
+ chain_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)[-1]["new_utxo"]
# Save the 13th transaction for the package
tx = self.wallet.create_self_transfer(utxo_to_spend=chain_tip_utxo)
package_hex.append(tx["hex"])
@@ -234,7 +234,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
self.log.info("Check that in-mempool and in-package ancestors are calculated properly in packages")
# Two chains of 12 transactions each
for _ in range(2):
- chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)
+ chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)[-1]["new_utxo"]
# last 2 transactions will be the parents of Pc
pc_parent_utxos.append(chaintip_utxo)
diff --git a/test/functional/mempool_package_onemore.py b/test/functional/mempool_package_onemore.py
index 9a981bd5a5..921c190668 100755
--- a/test/functional/mempool_package_onemore.py
+++ b/test/functional/mempool_package_onemore.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 descendant package tracking carve-out allowing one final transaction in
@@ -31,7 +31,6 @@ class MempoolPackagesTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
# DEFAULT_ANCESTOR_LIMIT transactions off a confirmed tx should be fine
chain = []
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index def0b1fce4..0387282862 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -1,12 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 descendant package tracking code."""
from decimal import Decimal
-from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import (
COIN,
DEFAULT_ANCESTOR_LIMIT,
@@ -17,9 +16,8 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
- chain_transaction,
)
-
+from test_framework.wallet import MiniWallet
# custom limits for node1
CUSTOM_ANCESTOR_LIMIT = 5
@@ -28,6 +26,9 @@ assert CUSTOM_DESCENDANT_LIMIT >= CUSTOM_ANCESTOR_LIMIT
class MempoolPackagesTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [
@@ -42,43 +43,33 @@ class MempoolPackagesTest(BitcoinTestFramework):
],
]
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def run_test(self):
- # Mine some blocks and have them mature.
+ self.wallet = MiniWallet(self.nodes[0])
+ self.wallet.rescan_utxos()
+
+ if self.is_specified_wallet_compiled():
+ self.nodes[0].createwallet("watch_wallet", disable_private_keys=True)
+ self.nodes[0].importaddress(self.wallet.get_address())
+
peer_inv_store = self.nodes[0].add_p2p_connection(P2PTxInvStore()) # keep track of invs
- self.generate(self.nodes[0], COINBASE_MATURITY + 1)
- utxo = self.nodes[0].listunspent(10)
- txid = utxo[0]['txid']
- vout = utxo[0]['vout']
- value = utxo[0]['amount']
- assert 'ancestorcount' not in utxo[0]
- assert 'ancestorsize' not in utxo[0]
- assert 'ancestorfees' not in utxo[0]
-
- fee = Decimal("0.0001")
+
# DEFAULT_ANCESTOR_LIMIT transactions off a confirmed tx should be fine
- chain = []
- witness_chain = []
+ chain = self.wallet.create_self_transfer_chain(chain_length=DEFAULT_ANCESTOR_LIMIT)
+ witness_chain = [t["wtxid"] for t in chain]
ancestor_vsize = 0
ancestor_fees = Decimal(0)
- for i in range(DEFAULT_ANCESTOR_LIMIT):
- (txid, sent_value) = chain_transaction(self.nodes[0], [txid], [0], value, fee, 1)
- value = sent_value
- chain.append(txid)
- # We need the wtxids to check P2P announcements
- witnesstx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
- witness_chain.append(witnesstx['hash'])
+ for i, t in enumerate(chain):
+ ancestor_vsize += t["tx"].get_vsize()
+ ancestor_fees += t["fee"]
+ self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=t["hex"])
# Check that listunspent ancestor{count, size, fees} yield the correct results
- wallet_unspent = self.nodes[0].listunspent(minconf=0)
- this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info['txid'] == txid)
- assert_equal(this_unspent['ancestorcount'], i + 1)
- ancestor_vsize += self.nodes[0].getrawtransaction(txid=txid, verbose=True)['vsize']
- assert_equal(this_unspent['ancestorsize'], ancestor_vsize)
- ancestor_fees -= self.nodes[0].gettransaction(txid=txid)['fee']
- assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN)
+ if self.is_specified_wallet_compiled():
+ wallet_unspent = self.nodes[0].listunspent(minconf=0)
+ this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info["txid"] == t["txid"])
+ assert_equal(this_unspent['ancestorcount'], i + 1)
+ assert_equal(this_unspent['ancestorsize'], ancestor_vsize)
+ assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN)
# Wait until mempool transactions have passed initial broadcast (sent inv and received getdata)
# Otherwise, getrawmempool may be inconsistent with getmempoolentry if unbroadcast changes in between
@@ -96,15 +87,20 @@ class MempoolPackagesTest(BitcoinTestFramework):
ancestor_count = DEFAULT_ANCESTOR_LIMIT
assert_equal(ancestor_fees, sum([mempool[tx]['fees']['base'] for tx in mempool]))
+ # Adding one more transaction on to the chain should fail.
+ next_hop = self.wallet.create_self_transfer(utxo_to_spend=chain[-1]["new_utxo"])["hex"]
+ assert_raises_rpc_error(-26, "too-long-mempool-chain", lambda: self.nodes[0].sendrawtransaction(next_hop))
+
descendants = []
- ancestors = list(chain)
+ ancestors = [t["txid"] for t in chain]
+ chain = [t["txid"] for t in chain]
for x in reversed(chain):
# Check that getmempoolentry is consistent with getrawmempool
entry = self.nodes[0].getmempoolentry(x)
assert_equal(entry, mempool[x])
# Check that gettxspendingprevout is consistent with getrawmempool
- witnesstx = self.nodes[0].gettransaction(txid=x, verbose=True)['decoded']
+ witnesstx = self.nodes[0].getrawtransaction(txid=x, verbose=True)
for tx_in in witnesstx["vin"]:
spending_result = self.nodes[0].gettxspendingprevout([ {'txid' : tx_in["txid"], 'vout' : tx_in["vout"]} ])
assert_equal(spending_result, [ {'txid' : tx_in["txid"], 'vout' : tx_in["vout"], 'spendingtxid' : x} ])
@@ -190,9 +186,6 @@ class MempoolPackagesTest(BitcoinTestFramework):
descendant_fees += entry['fees']['base']
assert_equal(entry['fees']['descendant'], descendant_fees + Decimal('0.00001'))
- # Adding one more transaction on to the chain should fail.
- assert_raises_rpc_error(-26, "too-long-mempool-chain", chain_transaction, self.nodes[0], [txid], [vout], value, fee, 1)
-
# Check that prioritising a tx before it's added to the mempool works
# First clear the mempool by mining a block.
self.generate(self.nodes[0], 1)
@@ -229,28 +222,23 @@ class MempoolPackagesTest(BitcoinTestFramework):
# TODO: test ancestor size limits
# Now test descendant chain limits
- txid = utxo[1]['txid']
- value = utxo[1]['amount']
- vout = utxo[1]['vout']
- transaction_package = []
tx_children = []
# First create one parent tx with 10 children
- (txid, sent_value) = chain_transaction(self.nodes[0], [txid], [vout], value, fee, 10)
- parent_transaction = txid
- for i in range(10):
- transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value})
+ tx_with_children = self.wallet.send_self_transfer_multi(from_node=self.nodes[0], num_outputs=10)
+ parent_transaction = tx_with_children["txid"]
+ transaction_package = tx_with_children["new_utxos"]
# Sign and send up to MAX_DESCENDANT transactions chained off the parent tx
chain = [] # save sent txs for the purpose of checking node1's mempool later (see below)
for _ in range(DEFAULT_DESCENDANT_LIMIT - 1):
utxo = transaction_package.pop(0)
- (txid, sent_value) = chain_transaction(self.nodes[0], [utxo['txid']], [utxo['vout']], utxo['amount'], fee, 10)
+ new_tx = self.wallet.send_self_transfer_multi(from_node=self.nodes[0], num_outputs=10, utxos_to_spend=[utxo])
+ txid = new_tx["txid"]
chain.append(txid)
if utxo['txid'] is parent_transaction:
tx_children.append(txid)
- for j in range(10):
- transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})
+ transaction_package.extend(new_tx["new_utxos"])
mempool = self.nodes[0].getrawmempool(True)
assert_equal(mempool[parent_transaction]['descendantcount'], DEFAULT_DESCENDANT_LIMIT)
@@ -260,8 +248,8 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(mempool[child]['depends'], [parent_transaction])
# Sending one more chained transaction will fail
- utxo = transaction_package.pop(0)
- assert_raises_rpc_error(-26, "too-long-mempool-chain", chain_transaction, self.nodes[0], [utxo['txid']], [utxo['vout']], utxo['amount'], fee, 10)
+ next_hop = self.wallet.create_self_transfer(utxo_to_spend=transaction_package.pop(0))["hex"]
+ assert_raises_rpc_error(-26, "too-long-mempool-chain", lambda: self.nodes[0].sendrawtransaction(next_hop))
# Check that node1's mempool is as expected, containing:
# - txs from previous ancestor test (-> custom ancestor limit)
@@ -301,42 +289,19 @@ class MempoolPackagesTest(BitcoinTestFramework):
# last block.
# Create tx0 with 2 outputs
- utxo = self.nodes[0].listunspent()
- txid = utxo[0]['txid']
- value = utxo[0]['amount']
- vout = utxo[0]['vout']
-
- send_value = (value - fee) / 2
- inputs = [ {'txid' : txid, 'vout' : vout} ]
- outputs = {}
- for _ in range(2):
- outputs[self.nodes[0].getnewaddress()] = send_value
- rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
- signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx)
- txid = self.nodes[0].sendrawtransaction(signedtx['hex'])
- tx0_id = txid
- value = send_value
+ tx0 = self.wallet.send_self_transfer_multi(from_node=self.nodes[0], num_outputs=2)
# Create tx1
- tx1_id, _ = chain_transaction(self.nodes[0], [tx0_id], [0], value, fee, 1)
+ tx1 = self.wallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=tx0["new_utxos"][0])
# Create tx2-7
- vout = 1
- txid = tx0_id
- for _ in range(6):
- (txid, sent_value) = chain_transaction(self.nodes[0], [txid], [vout], value, fee, 1)
- vout = 0
- value = sent_value
+ tx7 = self.wallet.send_self_transfer_chain(from_node=self.nodes[0], utxo_to_spend=tx0["new_utxos"][1], chain_length=6)[-1]
# Mine these in a block
self.generate(self.nodes[0], 1)
# Now generate tx8, with a big fee
- inputs = [ {'txid' : tx1_id, 'vout': 0}, {'txid' : txid, 'vout': 0} ]
- outputs = { self.nodes[0].getnewaddress() : send_value + value - 4*fee }
- rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
- signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx)
- txid = self.nodes[0].sendrawtransaction(signedtx['hex'])
+ self.wallet.send_self_transfer_multi(from_node=self.nodes[0], utxos_to_spend=[tx1["new_utxo"], tx7["new_utxo"]], fee_per_output=40000)
self.sync_mempools()
# Now try to disconnect the tip on each node...
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
index b6fa7fbd91..f818801136 100755
--- a/test/functional/mempool_persist.py
+++ b/test/functional/mempool_persist.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 mempool persistence.
@@ -50,13 +50,15 @@ from test_framework.wallet import MiniWallet
class MempoolPersistTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
def set_test_params(self):
self.num_nodes = 3
self.extra_args = [[], ["-persistmempool=0"], []]
def run_test(self):
self.mini_wallet = MiniWallet(self.nodes[2])
- self.mini_wallet.rescan_utxos()
if self.is_sqlite_compiled():
self.nodes[2].createwallet(
wallet_name="watch",
diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py
index 47ff520713..3a5bc1ebcd 100755
--- a/test/functional/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 mempool re-org scenarios.
@@ -31,7 +31,6 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
self.log.info("Add 4 coinbase utxos to the miniwallet")
# Block 76 contains the first spendable coinbase txs.
first_block = 76
- wallet.rescan_utxos()
# Three scenarios for re-orging coinbase spends in the memory pool:
# 1. Direct coinbase spend : spend_1
diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py
index 3e610d02ac..c10052372d 100755
--- a/test/functional/mempool_resurrect.py
+++ b/test/functional/mempool_resurrect.py
@@ -4,7 +4,6 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test resurrection of mined transactions when the blockchain is re-organized."""
-from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.wallet import MiniWallet
@@ -13,16 +12,11 @@ from test_framework.wallet import MiniWallet
class MempoolCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.setup_clean_chain = True
def run_test(self):
node = self.nodes[0]
wallet = MiniWallet(node)
- # Add enough mature utxos to the wallet so that all txs spend confirmed coins
- self.generate(wallet, 3)
- self.generate(node, COINBASE_MATURITY)
-
# Spend block 1/2/3's coinbase transactions
# Mine a block
# Create three more transactions, spending the spends
diff --git a/test/functional/mempool_sigoplimit.py b/test/functional/mempool_sigoplimit.py
new file mode 100755
index 0000000000..b178b9feda
--- /dev/null
+++ b/test/functional/mempool_sigoplimit.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023 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 sigop limit mempool policy (`-bytespersigop` parameter)"""
+from math import ceil
+
+from test_framework.messages import (
+ COutPoint,
+ CTransaction,
+ CTxIn,
+ CTxInWitness,
+ CTxOut,
+ WITNESS_SCALE_FACTOR,
+ tx_from_hex,
+)
+from test_framework.script import (
+ CScript,
+ OP_CHECKMULTISIG,
+ OP_CHECKSIG,
+ OP_ENDIF,
+ OP_FALSE,
+ OP_IF,
+ OP_RETURN,
+ OP_TRUE,
+)
+from test_framework.script_util import (
+ script_to_p2wsh_script,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_greater_than,
+ assert_greater_than_or_equal,
+)
+from test_framework.wallet import MiniWallet
+
+
+DEFAULT_BYTES_PER_SIGOP = 20 # default setting
+
+
+class BytesPerSigOpTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ # allow large datacarrier output to pad transactions
+ self.extra_args = [['-datacarriersize=100000']]
+
+ def create_p2wsh_spending_tx(self, witness_script, output_script):
+ """Create a 1-input-1-output P2WSH spending transaction with only the
+ witness script in the witness stack and the given output script."""
+ # create P2WSH address and fund it via MiniWallet first
+ txid, vout = self.wallet.send_to(
+ from_node=self.nodes[0],
+ scriptPubKey=script_to_p2wsh_script(witness_script),
+ amount=1000000,
+ )
+
+ # create spending transaction
+ tx = CTransaction()
+ tx.vin = [CTxIn(COutPoint(int(txid, 16), vout))]
+ tx.wit.vtxinwit = [CTxInWitness()]
+ tx.wit.vtxinwit[0].scriptWitness.stack = [bytes(witness_script)]
+ tx.vout = [CTxOut(500000, output_script)]
+ return tx
+
+ def test_sigops_limit(self, bytes_per_sigop, num_sigops):
+ sigop_equivalent_vsize = ceil(num_sigops * bytes_per_sigop / WITNESS_SCALE_FACTOR)
+ self.log.info(f"- {num_sigops} sigops (equivalent size of {sigop_equivalent_vsize} vbytes)")
+
+ # create a template tx with the specified sigop cost in the witness script
+ # (note that the sigops count even though being in a branch that's not executed)
+ num_multisigops = num_sigops // 20
+ num_singlesigops = num_sigops % 20
+ witness_script = CScript(
+ [OP_FALSE, OP_IF] +
+ [OP_CHECKMULTISIG]*num_multisigops +
+ [OP_CHECKSIG]*num_singlesigops +
+ [OP_ENDIF, OP_TRUE]
+ )
+ # use a 256-byte data-push as lower bound in the output script, in order
+ # to avoid having to compensate for tx size changes caused by varying
+ # length serialization sizes (both for scriptPubKey and data-push lengths)
+ tx = self.create_p2wsh_spending_tx(witness_script, CScript([OP_RETURN, b'X'*256]))
+
+ # bump the tx to reach the sigop-limit equivalent size by padding the datacarrier output
+ assert_greater_than_or_equal(sigop_equivalent_vsize, tx.get_vsize())
+ vsize_to_pad = sigop_equivalent_vsize - tx.get_vsize()
+ tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'X'*(256+vsize_to_pad)])
+ assert_equal(sigop_equivalent_vsize, tx.get_vsize())
+
+ res = self.nodes[0].testmempoolaccept([tx.serialize().hex()])[0]
+ assert_equal(res['allowed'], True)
+ assert_equal(res['vsize'], sigop_equivalent_vsize)
+
+ # increase the tx's vsize to be right above the sigop-limit equivalent size
+ # => tx's vsize in mempool should also grow accordingly
+ tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'X'*(256+vsize_to_pad+1)])
+ res = self.nodes[0].testmempoolaccept([tx.serialize().hex()])[0]
+ assert_equal(res['allowed'], True)
+ assert_equal(res['vsize'], sigop_equivalent_vsize+1)
+
+ # decrease the tx's vsize to be right below the sigop-limit equivalent size
+ # => tx's vsize in mempool should stick at the sigop-limit equivalent
+ # bytes level, as it is higher than the tx's serialized vsize
+ # (the maximum of both is taken)
+ tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'X'*(256+vsize_to_pad-1)])
+ res = self.nodes[0].testmempoolaccept([tx.serialize().hex()])[0]
+ assert_equal(res['allowed'], True)
+ assert_equal(res['vsize'], sigop_equivalent_vsize)
+
+ # check that the ancestor and descendant size calculations in the mempool
+ # also use the same max(sigop_equivalent_vsize, serialized_vsize) logic
+ # (to keep it simple, we only test the case here where the sigop vsize
+ # is much larger than the serialized vsize, i.e. we create a small child
+ # tx by getting rid of the large padding output)
+ tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'test123'])
+ assert_greater_than(sigop_equivalent_vsize, tx.get_vsize())
+ self.nodes[0].sendrawtransaction(hexstring=tx.serialize().hex(), maxburnamount='1.0')
+
+ # fetch parent tx, which doesn't contain any sigops
+ parent_txid = tx.vin[0].prevout.hash.to_bytes(32, 'big').hex()
+ parent_tx = tx_from_hex(self.nodes[0].getrawtransaction(txid=parent_txid))
+
+ entry_child = self.nodes[0].getmempoolentry(tx.rehash())
+ assert_equal(entry_child['descendantcount'], 1)
+ assert_equal(entry_child['descendantsize'], sigop_equivalent_vsize)
+ assert_equal(entry_child['ancestorcount'], 2)
+ assert_equal(entry_child['ancestorsize'], sigop_equivalent_vsize + parent_tx.get_vsize())
+
+ entry_parent = self.nodes[0].getmempoolentry(parent_tx.rehash())
+ assert_equal(entry_parent['ancestorcount'], 1)
+ assert_equal(entry_parent['ancestorsize'], parent_tx.get_vsize())
+ assert_equal(entry_parent['descendantcount'], 2)
+ assert_equal(entry_parent['descendantsize'], parent_tx.get_vsize() + sigop_equivalent_vsize)
+
+ def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
+
+ for bytes_per_sigop in (DEFAULT_BYTES_PER_SIGOP, 43, 81, 165, 327, 649, 1072):
+ if bytes_per_sigop == DEFAULT_BYTES_PER_SIGOP:
+ self.log.info(f"Test default sigops limit setting ({bytes_per_sigop} bytes per sigop)...")
+ else:
+ bytespersigop_parameter = f"-bytespersigop={bytes_per_sigop}"
+ self.log.info(f"Test sigops limit setting {bytespersigop_parameter}...")
+ self.restart_node(0, extra_args=[bytespersigop_parameter] + self.extra_args[0])
+
+ for num_sigops in (69, 101, 142, 183, 222):
+ self.test_sigops_limit(bytes_per_sigop, num_sigops)
+
+ self.generate(self.wallet, 1)
+
+
+if __name__ == '__main__':
+ BytesPerSigOpTest().main()
diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py
index 3585871350..a7cb2ba602 100755
--- a/test/functional/mempool_spend_coinbase.py
+++ b/test/functional/mempool_spend_coinbase.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 spending coinbase transactions.
@@ -28,7 +28,6 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
chain_height = 198
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(chain_height + 1))
assert_equal(chain_height, self.nodes[0].getblockcount())
- wallet.rescan_utxos()
# Coinbase at height chain_height-100+1 ok in mempool, should
# get mined. Coinbase at height chain_height-100+2 is
diff --git a/test/functional/mempool_unbroadcast.py b/test/functional/mempool_unbroadcast.py
index 7587adc257..12de750731 100755
--- a/test/functional/mempool_unbroadcast.py
+++ b/test/functional/mempool_unbroadcast.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 that the mempool ensures transaction delivery by periodically sending
@@ -15,14 +15,14 @@ from test_framework.wallet import MiniWallet
MAX_INITIAL_BROADCAST_DELAY = 15 * 60 # 15 minutes in seconds
class MempoolUnbroadcastTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
- if self.is_wallet_compiled():
- self.requires_wallet = True
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
self.test_broadcast()
self.test_txn_removal()
@@ -35,6 +35,7 @@ class MempoolUnbroadcastTest(BitcoinTestFramework):
self.log.info("Generate transactions that only node 0 knows about")
if self.is_wallet_compiled():
+ self.import_deterministic_coinbase_privkeys()
# generate a wallet txn
addr = node.getnewaddress()
wallet_tx_hsh = node.sendtoaddress(addr, 0.0001)
diff --git a/test/functional/mempool_updatefromblock.py b/test/functional/mempool_updatefromblock.py
index f97c2223a6..8350e9c91e 100755
--- a/test/functional/mempool_updatefromblock.py
+++ b/test/functional/mempool_updatefromblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 mempool descendants/ancestors information update.
@@ -7,14 +7,12 @@
Test mempool update of transaction descendants/ancestors information (count, size)
when transactions have been re-added from a disconnected block to the mempool.
"""
+from math import ceil
import time
-from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
-from test_framework.address import key_to_p2pkh
-from test_framework.wallet_util import bytes_to_wif
-from test_framework.key import ECKey
+from test_framework.wallet import MiniWallet
class MempoolUpdateFromBlockTest(BitcoinTestFramework):
@@ -22,15 +20,7 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [['-limitdescendantsize=1000', '-limitancestorsize=1000', '-limitancestorcount=100']]
- def get_new_address(self):
- key = ECKey()
- key.generate()
- pubkey = key.get_pubkey().get_bytes()
- address = key_to_p2pkh(pubkey)
- self.priv_keys.append(bytes_to_wif(key.get_bytes()))
- return address
-
- def transaction_graph_test(self, size, n_tx_to_mine=None, start_input_txid='', end_address='', fee=Decimal(0.00100000)):
+ def transaction_graph_test(self, size, n_tx_to_mine=None, fee=100_000):
"""Create an acyclic tournament (a type of directed graph) of transactions and use it for testing.
Keyword arguments:
@@ -45,14 +35,7 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
More details: https://en.wikipedia.org/wiki/Tournament_(graph_theory)
"""
-
- self.priv_keys = [self.nodes[0].get_deterministic_priv_key().key]
- if not start_input_txid:
- start_input_txid = self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0]
-
- if not end_address:
- end_address = self.get_new_address()
-
+ wallet = MiniWallet(self.nodes[0])
first_block_hash = ''
tx_id = []
tx_size = []
@@ -61,41 +44,31 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
self.log.debug('Preparing transaction #{}...'.format(i))
# Prepare inputs.
if i == 0:
- inputs = [{'txid': start_input_txid, 'vout': 0}]
- inputs_value = self.nodes[0].gettxout(start_input_txid, 0)['value']
+ inputs = [wallet.get_utxo()] # let MiniWallet provide a start UTXO
else:
inputs = []
- inputs_value = 0
for j, tx in enumerate(tx_id[0:i]):
# Transaction tx[K] is a child of each of previous transactions tx[0]..tx[K-1] at their output K-1.
vout = i - j - 1
- inputs.append({'txid': tx_id[j], 'vout': vout})
- inputs_value += self.nodes[0].gettxout(tx, vout)['value']
-
- self.log.debug('inputs={}'.format(inputs))
- self.log.debug('inputs_value={}'.format(inputs_value))
+ inputs.append(wallet.get_utxo(txid=tx_id[j], vout=vout))
# Prepare outputs.
tx_count = i + 1
if tx_count < size:
# Transaction tx[K] is an ancestor of each of subsequent transactions tx[K+1]..tx[N-1].
n_outputs = size - tx_count
- output_value = ((inputs_value - fee) / Decimal(n_outputs)).quantize(Decimal('0.00000001'))
- outputs = {}
- for _ in range(n_outputs):
- outputs[self.get_new_address()] = output_value
else:
- output_value = (inputs_value - fee).quantize(Decimal('0.00000001'))
- outputs = {end_address: output_value}
-
- self.log.debug('output_value={}'.format(output_value))
- self.log.debug('outputs={}'.format(outputs))
+ n_outputs = 1
# Create a new transaction.
- unsigned_raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
- signed_raw_tx = self.nodes[0].signrawtransactionwithkey(unsigned_raw_tx, self.priv_keys)
- tx_id.append(self.nodes[0].sendrawtransaction(signed_raw_tx['hex']))
- tx_size.append(self.nodes[0].getmempoolentry(tx_id[-1])['vsize'])
+ new_tx = wallet.send_self_transfer_multi(
+ from_node=self.nodes[0],
+ utxos_to_spend=inputs,
+ num_outputs=n_outputs,
+ fee_per_output=ceil(fee / n_outputs)
+ )
+ tx_id.append(new_tx['txid'])
+ tx_size.append(new_tx['tx'].get_vsize())
if tx_count in n_tx_to_mine:
# The created transactions are mined into blocks by batches.
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index 9c64bb1945..332099516c 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 mining RPCs
@@ -200,7 +200,7 @@ class MiningTest(BitcoinTestFramework):
self.log.info("getblocktemplate: Test bad timestamps")
bad_block = copy.deepcopy(block)
- bad_block.nTime = 2**31 - 1
+ bad_block.nTime = 2**32 - 1
assert_template(node, bad_block, 'time-too-new')
assert_submitblock(bad_block, 'time-too-new', 'time-too-new')
bad_block.nTime = 0
diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py
index e928ee4936..53182eb79e 100755
--- a/test/functional/mining_getblocktemplate_longpoll.py
+++ b/test/functional/mining_getblocktemplate_longpoll.py
@@ -4,11 +4,9 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test longpolling with getblocktemplate."""
-from decimal import Decimal
import random
import threading
-from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import get_rpc_proxy
from test_framework.wallet import MiniWallet
@@ -48,9 +46,9 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
thr.join(5) # wait 5 seconds or until thread exits
assert thr.is_alive()
- miniwallets = [MiniWallet(node) for node in self.nodes]
+ self.miniwallet = MiniWallet(self.nodes[0])
self.log.info("Test that longpoll will terminate if another node generates a block")
- self.generate(miniwallets[1], 1) # generate a block on another node
+ self.generate(self.nodes[1], 1) # generate a block on another node
# check that thread will exit now that new transaction entered mempool
thr.join(5) # wait 5 seconds or until thread exits
assert not thr.is_alive()
@@ -58,21 +56,15 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
self.log.info("Test that longpoll will terminate if we generate a block ourselves")
thr = LongpollThread(self.nodes[0])
thr.start()
- self.generate(miniwallets[0], 1) # generate a block on own node
+ self.generate(self.nodes[0], 1) # generate a block on own node
thr.join(5) # wait 5 seconds or until thread exits
assert not thr.is_alive()
- # Add enough mature utxos to the wallets, so that all txs spend confirmed coins
- self.generate(self.nodes[0], COINBASE_MATURITY)
-
self.log.info("Test that introducing a new transaction into the mempool will terminate the longpoll")
thr = LongpollThread(self.nodes[0])
thr.start()
- # generate a random transaction and submit it
- min_relay_fee = self.nodes[0].getnetworkinfo()["relayfee"]
- fee_rate = min_relay_fee + Decimal('0.00000010') * random.randint(0,20)
- miniwallets[0].send_self_transfer(from_node=random.choice(self.nodes),
- fee_rate=fee_rate)
+ # generate a transaction and submit it
+ self.miniwallet.send_self_transfer(from_node=random.choice(self.nodes))
# after one minute, every 10 seconds the mempool is probed, so in 80 seconds it should have returned
thr.join(60 + 20)
assert not thr.is_alive()
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index 581cf5896e..a4481c15a0 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 prioritisetransaction mining RPC."""
@@ -106,7 +106,6 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
# Test `prioritisetransaction` required parameters
assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction)
diff --git a/test/functional/mocks/invalid_signer.py b/test/functional/mocks/invalid_signer.py
index 14f9fed72e..7bfa9051ac 100755
--- a/test/functional/mocks/invalid_signer.py
+++ b/test/functional/mocks/invalid_signer.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,7 +10,7 @@ import json
def perform_pre_checks():
mock_result_path = os.path.join(os.getcwd(), "mock_result")
- if(os.path.isfile(mock_result_path)):
+ if os.path.isfile(mock_result_path):
with open(mock_result_path, "r", encoding="utf8") as f:
mock_result = f.read()
if mock_result[0]:
diff --git a/test/functional/mocks/signer.py b/test/functional/mocks/signer.py
index c5a8f7b1e9..5f4fad6380 100755
--- a/test/functional/mocks/signer.py
+++ b/test/functional/mocks/signer.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,7 +10,7 @@ import json
def perform_pre_checks():
mock_result_path = os.path.join(os.getcwd(), "mock_result")
- if(os.path.isfile(mock_result_path)):
+ if os.path.isfile(mock_result_path):
with open(mock_result_path, "r", encoding="utf8") as f:
mock_result = f.read()
if mock_result[0]:
@@ -27,12 +27,15 @@ def getdescriptors(args):
"receive": [
"pkh([00000001/44'/1'/" + args.account + "']" + xpub + "/0/*)#vt6w3l3j",
"sh(wpkh([00000001/49'/1'/" + args.account + "']" + xpub + "/0/*))#r0grqw5x",
- "wpkh([00000001/84'/1'/" + args.account + "']" + xpub + "/0/*)#x30uthjs"
+ "wpkh([00000001/84'/1'/" + args.account + "']" + xpub + "/0/*)#x30uthjs",
+ "tr([00000001/86'/1'/" + args.account + "']" + xpub + "/0/*)#sng9rd4t"
],
"internal": [
"pkh([00000001/44'/1'/" + args.account + "']" + xpub + "/1/*)#all0v2p2",
"sh(wpkh([00000001/49'/1'/" + args.account + "']" + xpub + "/1/*))#kwx4c3pe",
- "wpkh([00000001/84'/1'/" + args.account + "']" + xpub + "/1/*)#h92akzzg"
+ "wpkh([00000001/84'/1'/" + args.account + "']" + xpub + "/1/*)#h92akzzg",
+ "tr([00000001/86'/1'/" + args.account + "']" + xpub + "/1/*)#p8dy7c9n"
+
]
}))
@@ -44,7 +47,8 @@ def displayaddress(args):
return sys.stdout.write(json.dumps({"error": "Unexpected fingerprint", "fingerprint": args.fingerprint}))
expected_desc = [
- "wpkh([00000001/84'/1'/0'/0/0]02c97dc3f4420402e01a113984311bf4a1b8de376cac0bdcfaf1b3ac81f13433c7)#0yneg42r"
+ "wpkh([00000001/84'/1'/0'/0/0]02c97dc3f4420402e01a113984311bf4a1b8de376cac0bdcfaf1b3ac81f13433c7)#0yneg42r",
+ "tr([00000001/86'/1'/0'/0/0]c97dc3f4420402e01a113984311bf4a1b8de376cac0bdcfaf1b3ac81f13433c7)#4vdj9jqk",
]
if args.desc not in expected_desc:
return sys.stdout.write(json.dumps({"error": "Unexpected descriptor", "desc": args.desc}))
diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py
index e2e9b6dcb2..e002a520c6 100755
--- a/test/functional/p2p_addr_relay.py
+++ b/test/functional/p2p_addr_relay.py
@@ -49,7 +49,7 @@ class AddrReceiver(P2PInterface):
def on_addr(self, message):
for addr in message.addrs:
self.num_ipv4_received += 1
- if(self.test_addr_contents):
+ if self.test_addr_contents:
# relay_tests checks the content of the addr messages match
# expectations based on the message creation in setup_addr_msg
assert_equal(addr.nServices, 9)
diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py
index ef12b5f6b7..2da9037a69 100755
--- a/test/functional/p2p_blockfilters.py
+++ b/test/functional/p2p_blockfilters.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests NODE_COMPACT_FILTERS (BIP 157/158).
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
index 8ac38bff3a..110a1bd03f 100755
--- a/test/functional/p2p_blocksonly.py
+++ b/test/functional/p2p_blocksonly.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 p2p blocksonly mode & block-relay-only connections."""
@@ -20,8 +20,6 @@ class P2PBlocksOnly(BitcoinTestFramework):
def run_test(self):
self.miniwallet = MiniWallet(self.nodes[0])
- # Add enough mature utxos to the wallet, so that all txs spend confirmed coins
- self.miniwallet.rescan_utxos()
self.blocksonly_mode_tests()
self.blocks_relay_conn_tests()
@@ -57,6 +55,7 @@ class P2PBlocksOnly(BitcoinTestFramework):
second_peer = self.nodes[0].add_p2p_connection(P2PInterface())
peer_1_info = self.nodes[0].getpeerinfo()[0]
assert_equal(peer_1_info['permissions'], ['relay'])
+ assert_equal(first_peer.relay, 1)
peer_2_info = self.nodes[0].getpeerinfo()[1]
assert_equal(peer_2_info['permissions'], ['relay'])
assert_equal(self.nodes[0].testmempoolaccept([tx_hex])[0]['allowed'], True)
@@ -103,7 +102,7 @@ class P2PBlocksOnly(BitcoinTestFramework):
self.nodes[0].setmocktime(int(time.time()) + 60)
conn.sync_send_with_ping()
- assert(int(txid, 16) not in conn.get_invs())
+ assert int(txid, 16) not in conn.get_invs()
def check_p2p_inv_violation(self, peer):
self.log.info("Check that tx-invs from P2P are rejected and result in disconnect")
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 3cbb948e3c..23eeea50bc 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 compact blocks (BIP 152)."""
diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py
index 7284ecde83..394009f30f 100755
--- a/test/functional/p2p_disconnect_ban.py
+++ b/test/functional/p2p_disconnect_ban.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 disconnect and ban behavior"""
@@ -46,6 +46,9 @@ class DisconnectBanTest(BitcoinTestFramework):
assert_raises_rpc_error(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add")
assert_equal(len(self.nodes[1].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24
+ self.log.info("setban: fail to ban with past absolute timestamp")
+ assert_raises_rpc_error(-8, "Error: Absolute timestamp is in the past", self.nodes[1].setban, "127.27.0.1", "add", 123, True)
+
self.log.info("setban remove: fail to unban a non-banned subnet")
assert_raises_rpc_error(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove")
assert_equal(len(self.nodes[1].listbanned()), 1)
@@ -66,9 +69,13 @@ class DisconnectBanTest(BitcoinTestFramework):
self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds
listBeforeShutdown = self.nodes[1].listbanned()
assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address'])
+
+ self.log.info("setban: test banning with absolute timestamp")
+ self.nodes[1].setban("192.168.0.2", "add", old_time + 120, True)
+
# Move time forward by 3 seconds so the third ban has expired
self.nodes[1].setmocktime(old_time + 3)
- assert_equal(len(self.nodes[1].listbanned()), 3)
+ assert_equal(len(self.nodes[1].listbanned()), 4)
self.log.info("Test ban_duration and time_remaining")
for ban in self.nodes[1].listbanned():
@@ -78,13 +85,17 @@ class DisconnectBanTest(BitcoinTestFramework):
elif ban["address"] == "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19":
assert_equal(ban["ban_duration"], 1000)
assert_equal(ban["time_remaining"], 997)
+ elif ban["address"] == "192.168.0.2/32":
+ assert_equal(ban["ban_duration"], 120)
+ assert_equal(ban["time_remaining"], 117)
self.restart_node(1)
listAfterShutdown = self.nodes[1].listbanned()
assert_equal("127.0.0.0/24", listAfterShutdown[0]['address'])
assert_equal("127.0.0.0/32", listAfterShutdown[1]['address'])
- assert_equal("/19" in listAfterShutdown[2]['address'], True)
+ assert_equal("192.168.0.2/32", listAfterShutdown[2]['address'])
+ assert_equal("/19" in listAfterShutdown[3]['address'], True)
# Clear ban lists
self.nodes[1].clearbanned()
@@ -96,7 +107,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("disconnectnode: fail to disconnect when calling with address and nodeid")
address1 = self.nodes[0].getpeerinfo()[0]['addr']
- node1 = self.nodes[0].getpeerinfo()[0]['addr']
+ node1 = self.nodes[0].getpeerinfo()[0]["id"]
assert_raises_rpc_error(-32602, "Only one of address and nodeid should be provided.", self.nodes[0].disconnectnode, address=address1, nodeid=node1)
self.log.info("disconnectnode: fail to disconnect when calling with junk address")
@@ -105,7 +116,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("disconnectnode: successfully disconnect node by address")
address1 = self.nodes[0].getpeerinfo()[0]['addr']
self.nodes[0].disconnectnode(address=address1)
- self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
+ self.wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 1, timeout=10)
assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
self.log.info("disconnectnode: successfully reconnect node")
@@ -116,7 +127,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("disconnectnode: successfully disconnect node by node id")
id1 = self.nodes[0].getpeerinfo()[0]['id']
self.nodes[0].disconnectnode(nodeid=id1)
- self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
+ self.wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 1, timeout=10)
assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1]
if __name__ == '__main__':
diff --git a/test/functional/p2p_dos_header_tree.py b/test/functional/p2p_dos_header_tree.py
index 7e26994511..4b4346af49 100755
--- a/test/functional/p2p_dos_header_tree.py
+++ b/test/functional/p2p_dos_header_tree.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 that we reject low difficulty headers to prevent our block tree from filling up with useless bloat"""
@@ -22,7 +22,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.chain = 'testnet3' # Use testnet chain because it has an early checkpoint
self.num_nodes = 2
- self.extra_args = [["-minimumchainwork=0x0"], ["-minimumchainwork=0x0"]]
+ self.extra_args = [["-minimumchainwork=0x0", '-prune=550']] * self.num_nodes
def add_options(self, parser):
parser.add_argument(
@@ -63,7 +63,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
self.log.info("Feed all fork headers (succeeds without checkpoint)")
# On node 0 it succeeds because checkpoints are disabled
- self.restart_node(0, extra_args=['-nocheckpoints', "-minimumchainwork=0x0"])
+ self.restart_node(0, extra_args=['-nocheckpoints', "-minimumchainwork=0x0", '-prune=550'])
peer_no_checkpoint = self.nodes[0].add_p2p_connection(P2PInterface())
peer_no_checkpoint.send_and_ping(msg_headers(self.headers_fork))
assert {
diff --git a/test/functional/p2p_eviction.py b/test/functional/p2p_eviction.py
index 1f4797a89d..8b31dfa549 100755
--- a/test/functional/p2p_eviction.py
+++ b/test/functional/p2p_eviction.py
@@ -12,22 +12,23 @@ address/netgroup since in the current framework, all peers are connecting from
the same local address. See Issue #14210 for more info.
Therefore, this test is limited to the remaining protection criteria.
"""
-
import time
from test_framework.blocktools import (
- COINBASE_MATURITY,
create_block,
create_coinbase,
)
from test_framework.messages import (
msg_pong,
msg_tx,
- tx_from_hex,
)
-from test_framework.p2p import P2PDataStore, P2PInterface
+from test_framework.p2p import (
+ P2PDataStore,
+ P2PInterface,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
+from test_framework.wallet import MiniWallet
class SlowP2PDataStore(P2PDataStore):
@@ -35,14 +36,15 @@ class SlowP2PDataStore(P2PDataStore):
time.sleep(0.1)
self.send_message(msg_pong(message.nonce))
+
class SlowP2PInterface(P2PInterface):
def on_ping(self, message):
time.sleep(0.1)
self.send_message(msg_pong(message.nonce))
+
class P2PEvict(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = True
self.num_nodes = 1
# The choice of maxconnections=32 results in a maximum of 21 inbound connections
# (32 - 10 outbound - 1 feeler). 20 inbound peers are protected from eviction:
@@ -53,7 +55,7 @@ class P2PEvict(BitcoinTestFramework):
protected_peers = set() # peers that we expect to be protected from eviction
current_peer = -1
node = self.nodes[0]
- self.generatetoaddress(node, COINBASE_MATURITY + 1, node.get_deterministic_priv_key().address)
+ self.wallet = MiniWallet(node)
self.log.info("Create 4 peers and protect them from eviction by sending us a block")
for _ in range(4):
@@ -79,21 +81,8 @@ class P2PEvict(BitcoinTestFramework):
current_peer += 1
txpeer.sync_with_ping()
- prevtx = node.getblock(node.getblockhash(i + 1), 2)['tx'][0]
- rawtx = node.createrawtransaction(
- inputs=[{'txid': prevtx['txid'], 'vout': 0}],
- outputs=[{node.get_deterministic_priv_key().address: 50 - 0.00125}],
- )
- sigtx = node.signrawtransactionwithkey(
- hexstring=rawtx,
- privkeys=[node.get_deterministic_priv_key().key],
- prevtxs=[{
- 'txid': prevtx['txid'],
- 'vout': 0,
- 'scriptPubKey': prevtx['vout'][0]['scriptPubKey']['hex'],
- }],
- )['hex']
- txpeer.send_message(msg_tx(tx_from_hex(sigtx)))
+ tx = self.wallet.create_self_transfer()['tx']
+ txpeer.send_message(msg_tx(tx))
protected_peers.add(current_peer)
self.log.info("Create 8 peers and protect them from eviction by having faster pings")
@@ -133,5 +122,6 @@ class P2PEvict(BitcoinTestFramework):
self.log.debug("{} protected peers: {}".format(len(protected_peers), protected_peers))
assert evicted_peers[0] not in protected_peers
+
if __name__ == '__main__':
P2PEvict().main()
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index b65e927d5b..6b03cdf877 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -6,7 +6,6 @@
from decimal import Decimal
-from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import MSG_TX, MSG_WTX, msg_feefilter
from test_framework.p2p import P2PInterface, p2p_lock
from test_framework.test_framework import BitcoinTestFramework
@@ -80,9 +79,6 @@ class FeeFilterTest(BitcoinTestFramework):
node1 = self.nodes[1]
node0 = self.nodes[0]
miniwallet = MiniWallet(node1)
- # Add enough mature utxos to the wallet, so that all txs spend confirmed coins
- self.generate(miniwallet, 5)
- self.generate(node1, COINBASE_MATURITY)
conn = self.nodes[0].add_p2p_connection(TestP2PConn())
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index 3cf92b0316..b3e68ca536 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -214,7 +214,6 @@ class FilterTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
filter_peer = self.nodes[0].add_p2p_connection(P2PBloomFilter())
self.log.info('Test filter size limits')
diff --git a/test/functional/p2p_getaddr_caching.py b/test/functional/p2p_getaddr_caching.py
index 8907c34a89..1c9ad7289b 100755
--- a/test/functional/p2p_getaddr_caching.py
+++ b/test/functional/p2p_getaddr_caching.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 addr response caching"""
@@ -60,7 +60,7 @@ class AddrTest(BitcoinTestFramework):
# Need to make sure we hit MAX_ADDR_TO_SEND records in the addr response later because
# only a fraction of all known addresses can be cached and returned.
- assert(len(self.nodes[0].getnodeaddresses(0)) > int(MAX_ADDR_TO_SEND / (MAX_PCT_ADDR_TO_SEND / 100)))
+ assert len(self.nodes[0].getnodeaddresses(0)) > int(MAX_ADDR_TO_SEND / (MAX_PCT_ADDR_TO_SEND / 100))
last_response_on_local_bind = None
last_response_on_onion_bind1 = None
@@ -85,9 +85,9 @@ class AddrTest(BitcoinTestFramework):
if i > 0:
# Responses from different binds should be unique
- assert(last_response_on_local_bind != addr_receiver_onion1.get_received_addrs())
- assert(last_response_on_local_bind != addr_receiver_onion2.get_received_addrs())
- assert(last_response_on_onion_bind1 != addr_receiver_onion2.get_received_addrs())
+ assert last_response_on_local_bind != addr_receiver_onion1.get_received_addrs()
+ assert last_response_on_local_bind != addr_receiver_onion2.get_received_addrs()
+ assert last_response_on_onion_bind1 != addr_receiver_onion2.get_received_addrs()
# Responses on from the same bind should be the same
assert_equal(last_response_on_local_bind, addr_receiver_local.get_received_addrs())
assert_equal(last_response_on_onion_bind1, addr_receiver_onion1.get_received_addrs())
@@ -119,9 +119,9 @@ class AddrTest(BitcoinTestFramework):
addr_receiver_onion2.wait_until(addr_receiver_onion2.addr_received)
# new response is different
- assert(set(last_response_on_local_bind) != set(addr_receiver_local.get_received_addrs()))
- assert(set(last_response_on_onion_bind1) != set(addr_receiver_onion1.get_received_addrs()))
- assert(set(last_response_on_onion_bind2) != set(addr_receiver_onion2.get_received_addrs()))
+ assert set(last_response_on_local_bind) != set(addr_receiver_local.get_received_addrs())
+ assert set(last_response_on_onion_bind1) != set(addr_receiver_onion1.get_received_addrs())
+ assert set(last_response_on_onion_bind2) != set(addr_receiver_onion2.get_received_addrs())
if __name__ == '__main__':
AddrTest().main()
diff --git a/test/functional/p2p_headers_sync_with_minchainwork.py b/test/functional/p2p_headers_sync_with_minchainwork.py
index 991e3348ed..832fd7e0e9 100755
--- a/test/functional/p2p_headers_sync_with_minchainwork.py
+++ b/test/functional/p2p_headers_sync_with_minchainwork.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 that we reject low difficulty headers to prevent our block tree from filling up with useless bloat"""
@@ -27,6 +27,7 @@ NODE2_BLOCKS_REQUIRED = 2047
class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
def set_test_params(self):
+ self.rpc_timeout *= 4 # To avoid timeout when generating BLOCKS_TO_MINE
self.setup_clean_chain = True
self.num_nodes = 4
# Node0 has no required chainwork; node1 requires 15 blocks on top of the genesis block; node2 requires 2047
@@ -57,7 +58,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
def check_node3_chaintips(num_tips, tip_hash, height):
node3_chaintips = self.nodes[3].getchaintips()
- assert(len(node3_chaintips) == num_tips)
+ assert len(node3_chaintips) == num_tips
assert {
'height': height,
'hash': tip_hash,
@@ -69,7 +70,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
for node in self.nodes[1:3]:
chaintips = node.getchaintips()
- assert(len(chaintips) == 1)
+ assert len(chaintips) == 1
assert {
'height': 0,
'hash': '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206',
@@ -89,7 +90,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
'status': 'active',
} in self.nodes[2].getchaintips()
- assert(len(self.nodes[2].getchaintips()) == 1)
+ assert len(self.nodes[2].getchaintips()) == 1
self.log.info("Check that node3 accepted these headers as well")
check_node3_chaintips(2, self.nodes[0].getbestblockhash(), NODE1_BLOCKS_REQUIRED)
diff --git a/test/functional/p2p_i2p_sessions.py b/test/functional/p2p_i2p_sessions.py
index 4e52522b81..9e7fdc6e14 100755
--- a/test/functional/p2p_i2p_sessions.py
+++ b/test/functional/p2p_i2p_sessions.py
@@ -23,12 +23,12 @@ class I2PSessions(BitcoinTestFramework):
self.log.info("Ensure we create a persistent session when -i2pacceptincoming=1")
node0 = self.nodes[0]
- with node0.assert_debug_log(expected_msgs=[f"Creating persistent SAM session"]):
+ with node0.assert_debug_log(expected_msgs=["Creating persistent SAM session"]):
node0.addnode(node=addr, command="onetry")
self.log.info("Ensure we create a transient session when -i2pacceptincoming=0")
node1 = self.nodes[1]
- with node1.assert_debug_log(expected_msgs=[f"Creating transient SAM session"]):
+ with node1.assert_debug_log(expected_msgs=["Creating transient SAM session"]):
node1.addnode(node=addr, command="onetry")
diff --git a/test/functional/p2p_ibd_stalling.py b/test/functional/p2p_ibd_stalling.py
new file mode 100755
index 0000000000..aca98ceb3f
--- /dev/null
+++ b/test/functional/p2p_ibd_stalling.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022- 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 stalling logic during IBD
+"""
+
+import time
+
+from test_framework.blocktools import (
+ create_block,
+ create_coinbase
+)
+from test_framework.messages import (
+ MSG_BLOCK,
+ MSG_TYPE_MASK,
+)
+from test_framework.p2p import (
+ CBlockHeader,
+ msg_block,
+ msg_headers,
+ P2PDataStore,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+)
+
+
+class P2PStaller(P2PDataStore):
+ def __init__(self, stall_block):
+ self.stall_block = stall_block
+ super().__init__()
+
+ def on_getdata(self, message):
+ for inv in message.inv:
+ self.getdata_requests.append(inv.hash)
+ if (inv.type & MSG_TYPE_MASK) == MSG_BLOCK:
+ if (inv.hash != self.stall_block):
+ self.send_message(msg_block(self.block_store[inv.hash]))
+
+ def on_getheaders(self, message):
+ pass
+
+
+class P2PIBDStallingTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def run_test(self):
+ NUM_BLOCKS = 1025
+ NUM_PEERS = 4
+ node = self.nodes[0]
+ tip = int(node.getbestblockhash(), 16)
+ blocks = []
+ height = 1
+ block_time = node.getblock(node.getbestblockhash())['time'] + 1
+ self.log.info("Prepare blocks without sending them to the node")
+ block_dict = {}
+ for _ in range(NUM_BLOCKS):
+ blocks.append(create_block(tip, create_coinbase(height), block_time))
+ blocks[-1].solve()
+ tip = blocks[-1].sha256
+ block_time += 1
+ height += 1
+ block_dict[blocks[-1].sha256] = blocks[-1]
+ stall_block = blocks[0].sha256
+
+ headers_message = msg_headers()
+ headers_message.headers = [CBlockHeader(b) for b in blocks[:NUM_BLOCKS-1]]
+ peers = []
+
+ self.log.info("Check that a staller does not get disconnected if the 1024 block lookahead buffer is filled")
+ for id in range(NUM_PEERS):
+ peers.append(node.add_outbound_p2p_connection(P2PStaller(stall_block), p2p_idx=id, connection_type="outbound-full-relay"))
+ peers[-1].block_store = block_dict
+ peers[-1].send_message(headers_message)
+
+ # Need to wait until 1023 blocks are received - the magic total bytes number is a workaround in lack of an rpc
+ # returning the number of downloaded (but not connected) blocks.
+ self.wait_until(lambda: self.total_bytes_recv_for_blocks() == 172761)
+
+ self.all_sync_send_with_ping(peers)
+ # If there was a peer marked for stalling, it would get disconnected
+ self.mocktime = int(time.time()) + 3
+ node.setmocktime(self.mocktime)
+ self.all_sync_send_with_ping(peers)
+ assert_equal(node.num_test_p2p_connections(), NUM_PEERS)
+
+ self.log.info("Check that increasing the window beyond 1024 blocks triggers stalling logic")
+ headers_message.headers = [CBlockHeader(b) for b in blocks]
+ with node.assert_debug_log(expected_msgs=['Stall started']):
+ for p in peers:
+ p.send_message(headers_message)
+ self.all_sync_send_with_ping(peers)
+
+ self.log.info("Check that the stalling peer is disconnected after 2 seconds")
+ self.mocktime += 3
+ node.setmocktime(self.mocktime)
+ peers[0].wait_for_disconnect()
+ assert_equal(node.num_test_p2p_connections(), NUM_PEERS - 1)
+ self.wait_until(lambda: self.is_block_requested(peers, stall_block))
+ # Make sure that SendMessages() is invoked, which assigns the missing block
+ # to another peer and starts the stalling logic for them
+ self.all_sync_send_with_ping(peers)
+
+ self.log.info("Check that the stalling timeout gets doubled to 4 seconds for the next staller")
+ # No disconnect after just 3 seconds
+ self.mocktime += 3
+ node.setmocktime(self.mocktime)
+ self.all_sync_send_with_ping(peers)
+ assert_equal(node.num_test_p2p_connections(), NUM_PEERS - 1)
+
+ self.mocktime += 2
+ node.setmocktime(self.mocktime)
+ self.wait_until(lambda: sum(x.is_connected for x in node.p2ps) == NUM_PEERS - 2)
+ self.wait_until(lambda: self.is_block_requested(peers, stall_block))
+ self.all_sync_send_with_ping(peers)
+
+ self.log.info("Check that the stalling timeout gets doubled to 8 seconds for the next staller")
+ # No disconnect after just 7 seconds
+ self.mocktime += 7
+ node.setmocktime(self.mocktime)
+ self.all_sync_send_with_ping(peers)
+ assert_equal(node.num_test_p2p_connections(), NUM_PEERS - 2)
+
+ self.mocktime += 2
+ node.setmocktime(self.mocktime)
+ self.wait_until(lambda: sum(x.is_connected for x in node.p2ps) == NUM_PEERS - 3)
+ self.wait_until(lambda: self.is_block_requested(peers, stall_block))
+ self.all_sync_send_with_ping(peers)
+
+ self.log.info("Provide the withheld block and check that stalling timeout gets reduced back to 2 seconds")
+ with node.assert_debug_log(expected_msgs=['Decreased stalling timeout to 2 seconds']):
+ for p in peers:
+ if p.is_connected and (stall_block in p.getdata_requests):
+ p.send_message(msg_block(block_dict[stall_block]))
+
+ self.log.info("Check that all outstanding blocks get connected")
+ self.wait_until(lambda: node.getblockcount() == NUM_BLOCKS)
+
+ def total_bytes_recv_for_blocks(self):
+ total = 0
+ for info in self.nodes[0].getpeerinfo():
+ if ("block" in info["bytesrecv_per_msg"].keys()):
+ total += info["bytesrecv_per_msg"]["block"]
+ return total
+
+ def all_sync_send_with_ping(self, peers):
+ for p in peers:
+ if p.is_connected:
+ p.sync_send_with_ping()
+
+ def is_block_requested(self, peers, hash):
+ for p in peers:
+ if p.is_connected and (hash in p.getdata_requests):
+ return True
+ return False
+
+
+if __name__ == '__main__':
+ P2PIBDStallingTest().main()
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index 3109ad2b56..644abda914 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -13,11 +13,12 @@ from test_framework.messages import (
MAX_HEADERS_RESULTS,
MAX_INV_SIZE,
MAX_PROTOCOL_MESSAGE_LENGTH,
+ MSG_TX,
+ from_hex,
msg_getdata,
msg_headers,
msg_inv,
msg_ping,
- MSG_TX,
msg_version,
ser_string,
)
@@ -73,11 +74,17 @@ class InvalidMessagesTest(BitcoinTestFramework):
self.test_oversized_inv_msg()
self.test_oversized_getdata_msg()
self.test_oversized_headers_msg()
+ self.test_invalid_pow_headers_msg()
self.test_resource_exhaustion()
def test_buffer(self):
self.log.info("Test message with header split across two buffers is received")
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
+ # After add_p2p_connection both sides have the verack processed.
+ # However the pong from conn in reply to the ping from the node has not
+ # been processed and recorded in totalbytesrecv.
+ # Flush the pong from conn by sending a ping from conn.
+ conn.sync_with_ping(timeout=1)
# Create valid message
msg = conn.build_message(msg_ping(nonce=12345))
cut_pos = 12 # Chosen at an arbitrary position within the header
@@ -87,8 +94,6 @@ class InvalidMessagesTest(BitcoinTestFramework):
# Wait until node has processed the first half of the message
self.wait_until(lambda: self.nodes[0].getnettotals()['totalbytesrecv'] != before)
middle = self.nodes[0].getnettotals()['totalbytesrecv']
- # If this assert fails, we've hit an unlikely race
- # where the test framework sent a message in between the two halves
assert_equal(middle, before + cut_pos)
conn.send_raw_message(msg[cut_pos:])
conn.sync_with_ping(timeout=1)
@@ -248,6 +253,36 @@ class InvalidMessagesTest(BitcoinTestFramework):
size = MAX_HEADERS_RESULTS + 1
self.test_oversized_msg(msg_headers([CBlockHeader()] * size), size)
+ def test_invalid_pow_headers_msg(self):
+ self.log.info("Test headers message with invalid proof-of-work is logged as misbehaving and disconnects peer")
+ blockheader_tip_hash = self.nodes[0].getbestblockhash()
+ blockheader_tip = from_hex(CBlockHeader(), self.nodes[0].getblockheader(blockheader_tip_hash, False))
+
+ # send valid headers message first
+ assert_equal(self.nodes[0].getblockchaininfo()['headers'], 0)
+ blockheader = CBlockHeader()
+ blockheader.hashPrevBlock = int(blockheader_tip_hash, 16)
+ blockheader.nTime = int(time.time())
+ blockheader.nBits = blockheader_tip.nBits
+ blockheader.rehash()
+ while not blockheader.hash.startswith('0'):
+ blockheader.nNonce += 1
+ blockheader.rehash()
+ peer = self.nodes[0].add_p2p_connection(P2PInterface())
+ peer.send_and_ping(msg_headers([blockheader]))
+ assert_equal(self.nodes[0].getblockchaininfo()['headers'], 1)
+ chaintips = self.nodes[0].getchaintips()
+ assert_equal(chaintips[0]['status'], 'headers-only')
+ assert_equal(chaintips[0]['hash'], blockheader.hash)
+
+ # invalidate PoW
+ while not blockheader.hash.startswith('f'):
+ blockheader.nNonce += 1
+ blockheader.rehash()
+ with self.nodes[0].assert_debug_log(['Misbehaving', 'header with invalid proof of work']):
+ peer.send_message(msg_headers([blockheader]))
+ peer.wait_for_disconnect()
+
def test_resource_exhaustion(self):
self.log.info("Test node stays up despite many large junk messages")
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py
index 28efd5a81e..ae9dc816ab 100755
--- a/test/functional/p2p_invalid_tx.py
+++ b/test/functional/p2p_invalid_tx.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 transactions.
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index 936c22197c..645488f24d 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 message sending before handshake completion.
diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py
index 4c064b359e..6283dd89ac 100755
--- a/test/functional/p2p_leak_tx.py
+++ b/test/functional/p2p_leak_tx.py
@@ -4,7 +4,6 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that we don't leak txs to inbound peers that we haven't yet announced to"""
-from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import msg_getdata, CInv, MSG_TX
from test_framework.p2p import p2p_lock, P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
@@ -26,9 +25,6 @@ class P2PLeakTxTest(BitcoinTestFramework):
def run_test(self):
gen_node = self.nodes[0] # The block and tx generating node
miniwallet = MiniWallet(gen_node)
- # Add enough mature utxos to the wallet, so that all txs spend confirmed coins
- self.generate(miniwallet, 1)
- self.generate(gen_node, COINBASE_MATURITY)
inbound_peer = self.nodes[0].add_p2p_connection(P2PNode()) # An "attacking" inbound peer
diff --git a/test/functional/p2p_message_capture.py b/test/functional/p2p_message_capture.py
index 87c77f4540..3ab0b79ba2 100755
--- a/test/functional/p2p_message_capture.py
+++ b/test/functional/p2p_message_capture.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 per-peer message capture capability.
@@ -36,7 +36,7 @@ def mini_parser(dat_file):
"""
with open(dat_file, 'rb') as f_in:
# This should have at least one message in it
- assert(os.fstat(f_in.fileno()).st_size >= TIME_SIZE + LENGTH_SIZE + MSGTYPE_SIZE)
+ assert os.fstat(f_in.fileno()).st_size >= TIME_SIZE + LENGTH_SIZE + MSGTYPE_SIZE
while True:
tmp_header_raw = f_in.read(TIME_SIZE + LENGTH_SIZE + MSGTYPE_SIZE)
if not tmp_header_raw:
@@ -44,7 +44,7 @@ def mini_parser(dat_file):
tmp_header = BytesIO(tmp_header_raw)
tmp_header.read(TIME_SIZE) # skip the timestamp field
msgtype = tmp_header.read(MSGTYPE_SIZE).rstrip(b'\x00')
- assert(msgtype in MESSAGEMAP)
+ assert msgtype in MESSAGEMAP
length: int = int.from_bytes(tmp_header.read(LENGTH_SIZE), "little")
data = f_in.read(length)
assert_equal(len(data), length)
diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py
index 5a0003d3ef..a56afbcf7b 100755
--- a/test/functional/p2p_node_network_limited.py
+++ b/test/functional/p2p_node_network_limited.py
@@ -85,7 +85,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
self.connect_nodes(0, 2)
try:
self.sync_blocks([self.nodes[0], self.nodes[2]], timeout=5)
- except:
+ except Exception:
pass
# node2 must remain at height 0
assert_equal(self.nodes[2].getblockheader(self.nodes[2].getbestblockhash())['height'], 0)
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index 453a0920cc..f84bbf67e6 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 p2p permission message.
@@ -7,30 +7,26 @@
Test that permissions are correctly calculated and applied
"""
-from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
from test_framework.messages import (
- CTxInWitness,
- tx_from_hex,
+ SEQUENCE_FINAL,
)
from test_framework.p2p import P2PDataStore
-from test_framework.script import (
- CScript,
- OP_TRUE,
-)
from test_framework.test_node import ErrorMatch
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
p2p_port,
)
+from test_framework.wallet import MiniWallet
class P2PPermissionsTests(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = True
def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
+
self.check_tx_relay()
self.checkpermission(
@@ -60,12 +56,12 @@ class P2PPermissionsTests(BitcoinTestFramework):
# For this, we need to use whitebind instead of bind
# by modifying the configuration file.
ip_port = "127.0.0.1:{}".format(p2p_port(1))
- self.replaceinconfig(1, "bind=127.0.0.1", "whitebind=bloomfilter,forcerelay@" + ip_port)
+ self.nodes[1].replace_in_config([("bind=127.0.0.1", "whitebind=bloomfilter,forcerelay@" + ip_port)])
self.checkpermission(
["-whitelist=noban@127.0.0.1"],
# Check parameter interaction forcerelay should activate relay
["noban", "bloomfilter", "forcerelay", "relay", "download"])
- self.replaceinconfig(1, "whitebind=bloomfilter,forcerelay@" + ip_port, "bind=127.0.0.1")
+ self.nodes[1].replace_in_config([("whitebind=bloomfilter,forcerelay@" + ip_port, "bind=127.0.0.1")])
self.checkpermission(
# legacy whitelistrelay should be ignored
@@ -94,8 +90,6 @@ class P2PPermissionsTests(BitcoinTestFramework):
self.nodes[1].assert_start_raises_init_error(["-whitebind=noban@127.0.0.1", "-bind=127.0.0.1", "-listen=0"], "Cannot set -bind or -whitebind together with -listen=0", match=ErrorMatch.PARTIAL_REGEX)
def check_tx_relay(self):
- block_op_true = self.nodes[0].getblock(self.generatetoaddress(self.nodes[0], 100, ADDRESS_BCRT1_P2WSH_OP_TRUE)[0])
-
self.log.debug("Create a connection from a forcerelay peer that rebroadcasts raw txs")
# A test framework p2p connection is needed to send the raw transaction directly. If a full node was used, it could only
# rebroadcast via the inv-getdata mechanism. However, even for forcerelay connections, a full node would
@@ -104,18 +98,7 @@ class P2PPermissionsTests(BitcoinTestFramework):
p2p_rebroadcast_wallet = self.nodes[1].add_p2p_connection(P2PDataStore())
self.log.debug("Send a tx from the wallet initially")
- tx = tx_from_hex(
- self.nodes[0].createrawtransaction(
- inputs=[{
- 'txid': block_op_true['tx'][0],
- 'vout': 0,
- }], outputs=[{
- ADDRESS_BCRT1_P2WSH_OP_TRUE: 5,
- }],
- replaceable=False),
- )
- tx.wit.vtxinwit = [CTxInWitness()]
- tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
+ tx = self.wallet.create_self_transfer(sequence=SEQUENCE_FINAL)['tx']
txid = tx.rehash()
self.log.debug("Wait until tx is in node[1]'s mempool")
@@ -155,12 +138,6 @@ class P2PPermissionsTests(BitcoinTestFramework):
if p not in peerinfo['permissions']:
raise AssertionError("Expected permissions %r is not granted." % p)
- def replaceinconfig(self, nodeid, old, new):
- with open(self.nodes[nodeid].bitcoinconf, encoding="utf8") as f:
- newText = f.read().replace(old, new)
- with open(self.nodes[nodeid].bitcoinconf, 'w', encoding="utf8") as f:
- f.write(newText)
-
if __name__ == '__main__':
P2PPermissionsTests().main()
diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py
index 52dae90d19..3ba30a42b1 100755
--- a/test/functional/p2p_ping.py
+++ b/test/functional/p2p_ping.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 ping message
@@ -12,7 +12,9 @@ from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
+
PING_INTERVAL = 2 * 60
+TIMEOUT_INTERVAL = 20 * 60
class msg_pong_corrupt(msg_pong):
@@ -20,19 +22,11 @@ class msg_pong_corrupt(msg_pong):
return b""
-class NodePongAdd1(P2PInterface):
- def on_ping(self, message):
- self.send_message(msg_pong(message.nonce + 1))
-
-
class NodeNoPong(P2PInterface):
def on_ping(self, message):
pass
-TIMEOUT_INTERVAL = 20 * 60
-
-
class PingPongTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 311b0b67db..b0900e49b8 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 segwit transactions and blocks on P2P network."""
@@ -622,8 +622,10 @@ class SegWitTest(BitcoinTestFramework):
if not self.segwit_active:
# Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed
# in blocks and the tx is impossible to mine right now.
- assert_equal(
- self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]),
+ testres3 = self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()])
+ testres3[0]["fees"].pop("effective-feerate")
+ testres3[0]["fees"].pop("effective-includes")
+ assert_equal(testres3,
[{
'txid': tx3.hash,
'wtxid': tx3.getwtxid(),
@@ -639,8 +641,10 @@ class SegWitTest(BitcoinTestFramework):
tx3 = tx
tx3.vout = [tx3_out]
tx3.rehash()
- assert_equal(
- self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]),
+ testres3_replaced = self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()])
+ testres3_replaced[0]["fees"].pop("effective-feerate")
+ testres3_replaced[0]["fees"].pop("effective-includes")
+ assert_equal(testres3_replaced,
[{
'txid': tx3.hash,
'wtxid': tx3.getwtxid(),
diff --git a/test/functional/p2p_sendtxrcncl.py b/test/functional/p2p_sendtxrcncl.py
new file mode 100755
index 0000000000..0e349ef70c
--- /dev/null
+++ b/test/functional/p2p_sendtxrcncl.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 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 SENDTXRCNCL message
+"""
+
+from test_framework.messages import (
+ msg_sendtxrcncl,
+ msg_verack,
+ msg_version,
+ msg_wtxidrelay,
+ NODE_BLOOM,
+)
+from test_framework.p2p import (
+ P2PInterface,
+ P2P_SERVICES,
+ P2P_SUBVERSION,
+ P2P_VERSION,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+class PeerNoVerack(P2PInterface):
+ def __init__(self, wtxidrelay=True):
+ super().__init__(wtxidrelay=wtxidrelay)
+
+ def on_version(self, message):
+ # Avoid sending verack in response to version.
+ # When calling add_p2p_connection, wait_for_verack=False must be set (see
+ # comment in add_p2p_connection).
+ if message.nVersion >= 70016 and self.wtxidrelay:
+ self.send_message(msg_wtxidrelay())
+
+class SendTxrcnclReceiver(P2PInterface):
+ def __init__(self):
+ super().__init__()
+ self.sendtxrcncl_msg_received = None
+
+ def on_sendtxrcncl(self, message):
+ self.sendtxrcncl_msg_received = message
+
+
+class P2PFeelerReceiver(SendTxrcnclReceiver):
+ def on_version(self, message):
+ pass # feeler connections can not send any message other than their own version
+
+
+class PeerTrackMsgOrder(P2PInterface):
+ def __init__(self):
+ super().__init__()
+ self.messages = []
+
+ def on_message(self, message):
+ super().on_message(message)
+ self.messages.append(message)
+
+def create_sendtxrcncl_msg():
+ sendtxrcncl_msg = msg_sendtxrcncl()
+ sendtxrcncl_msg.version = 1
+ sendtxrcncl_msg.salt = 2
+ return sendtxrcncl_msg
+
+class SendTxRcnclTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.extra_args = [['-txreconciliation']]
+
+ def run_test(self):
+ # Check everything concerning *sending* SENDTXRCNCL
+ # First, *sending* to *inbound*.
+ self.log.info('SENDTXRCNCL sent to an inbound')
+ peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True)
+ assert peer.sendtxrcncl_msg_received
+ assert_equal(peer.sendtxrcncl_msg_received.version, 1)
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('SENDTXRCNCL should be sent before VERACK')
+ peer = self.nodes[0].add_p2p_connection(PeerTrackMsgOrder(), send_version=True, wait_for_verack=True)
+ peer.wait_for_verack()
+ verack_index = [i for i, msg in enumerate(peer.messages) if msg.msgtype == b'verack'][0]
+ sendtxrcncl_index = [i for i, msg in enumerate(peer.messages) if msg.msgtype == b'sendtxrcncl'][0]
+ assert sendtxrcncl_index < verack_index
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('SENDTXRCNCL on pre-WTXID version should not be sent')
+ peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=False, wait_for_verack=False)
+ pre_wtxid_version_msg = msg_version()
+ pre_wtxid_version_msg.nVersion = 70015
+ pre_wtxid_version_msg.strSubVer = P2P_SUBVERSION
+ pre_wtxid_version_msg.nServices = P2P_SERVICES
+ pre_wtxid_version_msg.relay = 1
+ peer.send_message(pre_wtxid_version_msg)
+ peer.wait_for_verack()
+ assert not peer.sendtxrcncl_msg_received
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('SENDTXRCNCL for fRelay=false should not be sent')
+ peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=False, wait_for_verack=False)
+ no_txrelay_version_msg = msg_version()
+ no_txrelay_version_msg.nVersion = P2P_VERSION
+ no_txrelay_version_msg.strSubVer = P2P_SUBVERSION
+ no_txrelay_version_msg.nServices = P2P_SERVICES
+ no_txrelay_version_msg.relay = 0
+ peer.send_message(no_txrelay_version_msg)
+ peer.wait_for_verack()
+ assert not peer.sendtxrcncl_msg_received
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('SENDTXRCNCL for fRelay=false should not be sent (with NODE_BLOOM offered)')
+ self.restart_node(0, ["-peerbloomfilters", "-txreconciliation"])
+ peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=False, wait_for_verack=False)
+ no_txrelay_version_msg = msg_version()
+ no_txrelay_version_msg.nVersion = P2P_VERSION
+ no_txrelay_version_msg.strSubVer = P2P_SUBVERSION
+ no_txrelay_version_msg.nServices = P2P_SERVICES
+ no_txrelay_version_msg.relay = 0
+ peer.send_message(no_txrelay_version_msg)
+ peer.wait_for_verack()
+ assert peer.nServices & NODE_BLOOM != 0
+ assert not peer.sendtxrcncl_msg_received
+ self.nodes[0].disconnect_p2ps()
+
+ # Now, *sending* to *outbound*.
+ self.log.info('SENDTXRCNCL sent to an outbound')
+ peer = self.nodes[0].add_outbound_p2p_connection(
+ SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=0, connection_type="outbound-full-relay")
+ assert peer.sendtxrcncl_msg_received
+ assert_equal(peer.sendtxrcncl_msg_received.version, 1)
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('SENDTXRCNCL should not be sent if block-relay-only')
+ peer = self.nodes[0].add_outbound_p2p_connection(
+ SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=0, connection_type="block-relay-only")
+ assert not peer.sendtxrcncl_msg_received
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info("SENDTXRCNCL should not be sent if feeler")
+ peer = self.nodes[0].add_outbound_p2p_connection(P2PFeelerReceiver(), p2p_idx=0, connection_type="feeler")
+ assert not peer.sendtxrcncl_msg_received
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info("SENDTXRCNCL should not be sent if addrfetch")
+ peer = self.nodes[0].add_outbound_p2p_connection(
+ SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=0, connection_type="addr-fetch")
+ assert not peer.sendtxrcncl_msg_received
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('SENDTXRCNCL not sent if -txreconciliation flag is not set')
+ self.restart_node(0, [])
+ peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True)
+ assert not peer.sendtxrcncl_msg_received
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('SENDTXRCNCL not sent if blocksonly is set')
+ self.restart_node(0, ["-txreconciliation", "-blocksonly"])
+ peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True)
+ assert not peer.sendtxrcncl_msg_received
+ self.nodes[0].disconnect_p2ps()
+
+ # Check everything concerning *receiving* SENDTXRCNCL
+ # First, receiving from *inbound*.
+ self.restart_node(0, ["-txreconciliation"])
+ self.log.info('valid SENDTXRCNCL received')
+ peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False)
+ with self.nodes[0].assert_debug_log(["received: sendtxrcncl"]):
+ peer.send_message(create_sendtxrcncl_msg())
+ self.log.info('second SENDTXRCNCL triggers a disconnect')
+ with self.nodes[0].assert_debug_log(["(sendtxrcncl received from already registered peer); disconnecting"]):
+ peer.send_message(create_sendtxrcncl_msg())
+ peer.wait_for_disconnect()
+
+ self.restart_node(0, [])
+ self.log.info('SENDTXRCNCL if no txreconciliation supported is ignored')
+ peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False)
+ with self.nodes[0].assert_debug_log(['ignored, as our node does not have txreconciliation enabled']):
+ peer.send_message(create_sendtxrcncl_msg())
+ self.nodes[0].disconnect_p2ps()
+
+ self.restart_node(0, ["-txreconciliation"])
+
+ self.log.info('SENDTXRCNCL with version=0 triggers a disconnect')
+ sendtxrcncl_low_version = create_sendtxrcncl_msg()
+ sendtxrcncl_low_version.version = 0
+ peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False)
+ with self.nodes[0].assert_debug_log(["txreconciliation protocol violation"]):
+ peer.send_message(sendtxrcncl_low_version)
+ peer.wait_for_disconnect()
+
+ self.log.info('SENDTXRCNCL with version=2 is valid')
+ sendtxrcncl_higher_version = create_sendtxrcncl_msg()
+ sendtxrcncl_higher_version.version = 2
+ peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False)
+ with self.nodes[0].assert_debug_log(['Register peer=1']):
+ peer.send_message(sendtxrcncl_higher_version)
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('unexpected SENDTXRCNCL is ignored')
+ peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=False, wait_for_verack=False)
+ old_version_msg = msg_version()
+ old_version_msg.nVersion = 70015
+ old_version_msg.strSubVer = P2P_SUBVERSION
+ old_version_msg.nServices = P2P_SERVICES
+ old_version_msg.relay = 1
+ peer.send_message(old_version_msg)
+ with self.nodes[0].assert_debug_log(['Ignore unexpected txreconciliation signal']):
+ peer.send_message(create_sendtxrcncl_msg())
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('sending SENDTXRCNCL after sending VERACK triggers a disconnect')
+ peer = self.nodes[0].add_p2p_connection(P2PInterface())
+ with self.nodes[0].assert_debug_log(["sendtxrcncl received after verack"]):
+ peer.send_message(create_sendtxrcncl_msg())
+ peer.wait_for_disconnect()
+
+ self.log.info('SENDTXRCNCL without WTXIDRELAY is ignored (recon state is erased after VERACK)')
+ peer = self.nodes[0].add_p2p_connection(PeerNoVerack(wtxidrelay=False), send_version=True, wait_for_verack=False)
+ with self.nodes[0].assert_debug_log(['Forget txreconciliation state of peer']):
+ peer.send_message(create_sendtxrcncl_msg())
+ peer.send_message(msg_verack())
+ self.nodes[0].disconnect_p2ps()
+
+ # Now, *receiving* from *outbound*.
+ self.log.info('SENDTXRCNCL if block-relay-only triggers a disconnect')
+ peer = self.nodes[0].add_outbound_p2p_connection(
+ PeerNoVerack(), wait_for_verack=False, p2p_idx=0, connection_type="block-relay-only")
+ with self.nodes[0].assert_debug_log(["we indicated no tx relay; disconnecting"]):
+ peer.send_message(create_sendtxrcncl_msg())
+ peer.wait_for_disconnect()
+
+
+if __name__ == '__main__':
+ SendTxRcnclTest().main()
diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py
index 15a879ae3c..a308577c02 100755
--- a/test/functional/p2p_timeouts.py
+++ b/test/functional/p2p_timeouts.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 various net timeouts.
diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py
index 7356b8bbb3..0e463c5072 100755
--- a/test/functional/p2p_tx_download.py
+++ b/test/functional/p2p_tx_download.py
@@ -5,6 +5,7 @@
"""
Test transaction download behavior
"""
+import time
from test_framework.messages import (
CInv,
@@ -13,7 +14,6 @@ from test_framework.messages import (
MSG_WTX,
msg_inv,
msg_notfound,
- tx_from_hex,
)
from test_framework.p2p import (
P2PInterface,
@@ -23,9 +23,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
)
-from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
-
-import time
+from test_framework.wallet import MiniWallet
class TestP2PConn(P2PInterface):
@@ -88,19 +86,8 @@ class TxDownloadTest(BitcoinTestFramework):
def test_inv_block(self):
self.log.info("Generate a transaction on node 0")
- tx = self.nodes[0].createrawtransaction(
- inputs=[{ # coinbase
- "txid": self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0],
- "vout": 0
- }],
- outputs={ADDRESS_BCRT1_UNSPENDABLE: 50 - 0.00025},
- )
- tx = self.nodes[0].signrawtransactionwithkey(
- hexstring=tx,
- privkeys=[self.nodes[0].get_deterministic_priv_key().key],
- )['hex']
- ctx = tx_from_hex(tx)
- txid = int(ctx.rehash(), 16)
+ tx = self.wallet.create_self_transfer()
+ txid = int(tx['txid'], 16)
self.log.info(
"Announce the transaction to all nodes from all {} incoming peers, but never send it".format(NUM_INBOUND))
@@ -109,7 +96,7 @@ class TxDownloadTest(BitcoinTestFramework):
p.send_and_ping(msg)
self.log.info("Put the tx in node 0's mempool")
- self.nodes[0].sendrawtransaction(tx)
+ self.nodes[0].sendrawtransaction(tx['hex'])
# Since node 1 is connected outbound to an honest peer (node 0), it
# should get the tx within a timeout. (Assuming that node 0
@@ -255,6 +242,8 @@ class TxDownloadTest(BitcoinTestFramework):
self.nodes[0].p2ps[0].send_message(msg_notfound(vec=[CInv(MSG_TX, 1)]))
def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
+
# Run tests without mocktime that only need one peer-connection first, to avoid restarting the nodes
self.test_expiry_fallback()
self.test_disconnect_fallback()
diff --git a/test/functional/p2p_tx_privacy.py b/test/functional/p2p_tx_privacy.py
new file mode 100755
index 0000000000..e674f6c3eb
--- /dev/null
+++ b/test/functional/p2p_tx_privacy.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 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 that transaction announcements are only queued for peers that have
+successfully completed the version handshake.
+
+Topology:
+
+ tx_originator ----> node[0] <---- spy
+
+We test that a transaction sent by tx_originator is only relayed to spy
+if it was received after spy's version handshake completed.
+
+1. Fully connect tx_originator
+2. Connect spy (no version handshake)
+3. tx_originator sends tx1
+4. spy completes the version handshake
+5. tx_originator sends tx2
+6. We check that only tx2 is announced on the spy interface
+"""
+from test_framework.messages import (
+ msg_wtxidrelay,
+ msg_verack,
+ msg_tx,
+ CInv,
+ MSG_WTX,
+)
+from test_framework.p2p import (
+ P2PInterface,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.wallet import MiniWallet
+
+class P2PTxSpy(P2PInterface):
+ def __init__(self):
+ super().__init__()
+ self.all_invs = []
+
+ def on_version(self, message):
+ self.send_message(msg_wtxidrelay())
+
+ def on_inv(self, message):
+ self.all_invs += message.inv
+
+ def wait_for_inv_match(self, expected_inv):
+ self.wait_until(lambda: len(self.all_invs) == 1 and self.all_invs[0] == expected_inv)
+
+class TxPrivacyTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
+
+ tx_originator = self.nodes[0].add_p2p_connection(P2PInterface())
+ spy = self.nodes[0].add_p2p_connection(P2PTxSpy(), wait_for_verack=False)
+ spy.wait_for_verack()
+
+ # tx_originator sends tx1
+ tx1 = self.wallet.create_self_transfer()["tx"]
+ tx_originator.send_and_ping(msg_tx(tx1))
+
+ # Spy sends the verack
+ spy.send_and_ping(msg_verack())
+
+ # tx_originator sends tx2
+ tx2 = self.wallet.create_self_transfer()["tx"]
+ tx_originator.send_and_ping(msg_tx(tx2))
+
+ # Spy should only get an inv for the second transaction as the first
+ # one was received pre-verack with the spy
+ spy.wait_for_inv_match(CInv(MSG_WTX, tx2.calc_sha256(True)))
+
+if __name__ == '__main__':
+ TxPrivacyTest().main()
diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py
index 5030e7af26..f368434895 100755
--- a/test/functional/p2p_unrequested_blocks.py
+++ b/test/functional/p2p_unrequested_blocks.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 processing of unrequested blocks.
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index d07d28879e..6022042c11 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 RPCs related to blockchainstate.
@@ -25,6 +25,7 @@ from decimal import Decimal
import http.client
import os
import subprocess
+import textwrap
from test_framework.blocktools import (
MAX_FUTURE_BLOCK_TIME,
@@ -68,6 +69,7 @@ class BlockchainTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
+ self._test_prune_disk_space()
self.mine_chain()
self._test_max_future_block_time()
self.restart_node(
@@ -89,6 +91,7 @@ class BlockchainTest(BitcoinTestFramework):
self._test_waitforblockheight()
self._test_getblock()
self._test_getdeploymentinfo()
+ self._test_y2106()
assert self.nodes[0].verifychain(4, 0)
def mine_chain(self):
@@ -98,6 +101,13 @@ class BlockchainTest(BitcoinTestFramework):
self.generate(self.wallet, 1)
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], HEIGHT)
+ def _test_prune_disk_space(self):
+ self.log.info("Test that a manually pruned node does not run into "
+ "integer overflow on first start up")
+ self.restart_node(0, extra_args=["-prune=1"])
+ self.log.info("Avoid warning when assumed chain size is enough")
+ self.restart_node(0, extra_args=["-prune=123456789"])
+
def _test_max_future_block_time(self):
self.stop_node(0)
self.log.info("A block tip of more than MAX_FUTURE_BLOCK_TIME in the future raises an error")
@@ -255,6 +265,14 @@ class BlockchainTest(BitcoinTestFramework):
# calling with an explicit hash works
self.check_signalling_deploymentinfo_result(self.nodes[0].getdeploymentinfo(gbci207["bestblockhash"]), gbci207["blocks"], gbci207["bestblockhash"], "started")
+ def _test_y2106(self):
+ self.log.info("Check that block timestamps work until year 2106")
+ self.generate(self.nodes[0], 8)[-1]
+ time_2106 = 2**32 - 1
+ self.nodes[0].setmocktime(time_2106)
+ last = self.generate(self.nodes[0], 6)[-1]
+ assert_equal(self.nodes[0].getblockheader(last)["mediantime"], time_2106)
+
def _test_getchaintxstats(self):
self.log.info("Test getchaintxstats")
@@ -361,7 +379,7 @@ class BlockchainTest(BitcoinTestFramework):
# hash_type muhash should return a different UTXO set hash.
res6 = node.gettxoutsetinfo(hash_type='muhash')
assert 'muhash' in res6
- assert(res['hash_serialized_2'] != res6['muhash'])
+ assert res['hash_serialized_2'] != res6['muhash']
# muhash should not be returned unless requested.
for r in [res, res2, res3, res4, res5]:
@@ -420,6 +438,17 @@ class BlockchainTest(BitcoinTestFramework):
def _test_getnetworkhashps(self):
self.log.info("Test getnetworkhashps")
hashes_per_second = self.nodes[0].getnetworkhashps()
+ assert_raises_rpc_error(
+ -3,
+ textwrap.dedent("""
+ Wrong type passed:
+ {
+ "Position 1 (nblocks)": "JSON value of type string is not of expected type number",
+ "Position 2 (height)": "JSON value of type array is not of expected type number"
+ }
+ """).strip(),
+ lambda: self.nodes[0].getnetworkhashps("a", []),
+ )
# This should be 2 hashes every 10 minutes or 1/300
assert abs(hashes_per_second * 300 - 1) < 0.0001
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 1ad3fc24c9..7d03ed2951 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 multisig RPCs"""
@@ -24,12 +24,13 @@ from test_framework.wallet import (
)
class RpcCreateMultiSigTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
self.supports_cli = False
- if self.is_bdb_compiled():
- self.requires_wallet = True
def get_keys(self):
self.pub = []
@@ -50,6 +51,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
self.wallet = MiniWallet(test_node=node0)
if self.is_bdb_compiled():
+ self.import_deterministic_coinbase_privkeys()
self.check_addmultisigaddress_errors()
self.log.info('Generating blocks ...')
diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py
index 343cb73989..673836bd04 100755
--- a/test/functional/rpc_decodescript.py
+++ b/test/functional/rpc_decodescript.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 decoding scripts via decodescript RPC command."""
@@ -263,6 +263,19 @@ class DecodeScriptTest(BitcoinTestFramework):
rpc_result = self.nodes[0].decodescript(script)
assert_equal(result, rpc_result)
+ def decodescript_miniscript(self):
+ """Check that a Miniscript is decoded when possible under P2WSH context."""
+ # Sourced from https://github.com/bitcoin/bitcoin/pull/27037#issuecomment-1416151907.
+ # Miniscript-compatible offered HTLC
+ res = self.nodes[0].decodescript("82012088a914ffffffffffffffffffffffffffffffffffffffff88210250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0ad51b2")
+ assert res["segwit"]["desc"] == "wsh(and_v(and_v(v:hash160(ffffffffffffffffffffffffffffffffffffffff),v:pk(0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0)),older(1)))#gm8xz4fl"
+ # Miniscript-incompatible offered HTLC
+ res = self.nodes[0].decodescript("82012088a914ffffffffffffffffffffffffffffffffffffffff882102ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffacb2")
+ assert res["segwit"]["desc"] == "wsh(raw(82012088a914ffffffffffffffffffffffffffffffffffffffff882102ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffacb2))#ra6w2xa7"
+ # Miniscript-compatible multisig bigger than 520 byte P2SH limit.
+ res = self.nodes[0].decodescript("5b21020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b678172612102675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af992102896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d4821029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c2102a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc401021031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb2103079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b2103111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2210318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa08401742103230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de121035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a62103bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c2103cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d175462103d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d4248282103ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a5fae736402c00fb269522103aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79210291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807210386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb53ae68")
+ assert_equal(res["segwit"]["desc"], "wsh(or_d(multi(11,020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261,02675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af99,02896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d48,029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c,02a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc4010,031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb,03079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b,03111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2,0318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa0840174,03230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de1,035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a6,03bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c,03cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d17546,03d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d424828,03ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a),and_v(v:older(4032),multi(2,03aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79,0291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807,0386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb))))#7jwwklk4")
+
def run_test(self):
self.log.info("Test decoding of standard input scripts [scriptSig]")
self.decodescript_script_sig()
@@ -272,6 +285,8 @@ class DecodeScriptTest(BitcoinTestFramework):
self.decoderawtransaction_asm_sighashtype()
self.log.info("Data-driven tests")
self.decodescript_datadriven_tests()
+ self.log.info("Miniscript descriptor decoding")
+ self.decodescript_miniscript()
if __name__ == '__main__':
DecodeScriptTest().main()
diff --git a/test/functional/rpc_deriveaddresses.py b/test/functional/rpc_deriveaddresses.py
index 42d7d59d56..e96b6bda90 100755
--- a/test/functional/rpc_deriveaddresses.py
+++ b/test/functional/rpc_deriveaddresses.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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."""
@@ -44,6 +44,13 @@ class DeriveaddressesTest(BitcoinTestFramework):
combo_descriptor = descsum_create("combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)")
assert_equal(self.nodes[0].deriveaddresses(combo_descriptor), ["mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", "mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", address, "2NDvEwGfpEqJWfybzpKPHF2XH3jwoQV3D7x"])
+ # Before #26275, bitcoind would crash when deriveaddresses was
+ # called with derivation index 2147483647, which is the maximum
+ # positive value of a signed int32, and - currently - the
+ # maximum value that the deriveaddresses bitcoin RPC call
+ # accepts as derivation index.
+ assert_equal(self.nodes[0].deriveaddresses(descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), [2147483647, 2147483647]), ["bcrt1qtzs23vgzpreks5gtygwxf8tv5rldxvvsyfpdkg"])
+
hardened_without_privkey_descriptor = descsum_create("wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1'/1/0)")
assert_raises_rpc_error(-5, "Cannot derive script without private keys", self.nodes[0].deriveaddresses, hardened_without_privkey_descriptor)
diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py
index 672c9a53dc..39a931be03 100755
--- a/test/functional/rpc_dumptxoutset.py
+++ b/test/functional/rpc_dumptxoutset.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 generation of UTXO snapshots using `dumptxoutset`.
diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py
index b057400887..dad3cbcf0c 100755
--- a/test/functional/rpc_estimatefee.py
+++ b/test/functional/rpc_estimatefee.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 estimatefee RPCs.
diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py
index 2b1dd20ea1..8948ccb48d 100755
--- a/test/functional/rpc_generate.py
+++ b/test/functional/rpc_generate.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 generate* RPCs."""
@@ -28,7 +28,6 @@ class RPCGenerateTest(BitcoinTestFramework):
def test_generateblock(self):
node = self.nodes[0]
miniwallet = MiniWallet(node)
- miniwallet.rescan_utxos()
self.log.info('Generate an empty block to address')
address = miniwallet.get_address()
diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py
index 278a343b2b..2f093bebff 100755
--- a/test/functional/rpc_getblockfrompeer.py
+++ b/test/functional/rpc_getblockfrompeer.py
@@ -1,11 +1,16 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 getblockfrompeer RPC."""
from test_framework.authproxy import JSONRPCException
-from test_framework.messages import NODE_WITNESS
+from test_framework.messages import (
+ CBlock,
+ from_hex,
+ msg_headers,
+ NODE_WITNESS,
+)
from test_framework.p2p import (
P2P_SERVICES,
P2PInterface,
@@ -16,16 +21,22 @@ from test_framework.util import (
assert_raises_rpc_error,
)
+
class GetBlockFromPeerTest(BitcoinTestFramework):
def set_test_params(self):
- self.num_nodes = 2
+ self.num_nodes = 3
+ self.extra_args = [
+ [],
+ [],
+ ["-fastprune", "-prune=1"]
+ ]
def setup_network(self):
self.setup_nodes()
- def check_for_block(self, hash):
+ def check_for_block(self, node, hash):
try:
- self.nodes[0].getblock(hash)
+ self.nodes[node].getblock(hash)
return True
except JSONRPCException:
return False
@@ -42,7 +53,7 @@ class GetBlockFromPeerTest(BitcoinTestFramework):
self.log.info("Connect nodes to sync headers")
self.connect_nodes(0, 1)
- self.sync_blocks()
+ self.sync_blocks(self.nodes[0:2])
self.log.info("Node 0 should only have the header for node 1's block 3")
x = next(filter(lambda x: x['hash'] == short_tip, self.nodes[0].getchaintips()))
@@ -75,12 +86,70 @@ class GetBlockFromPeerTest(BitcoinTestFramework):
self.log.info("Successful fetch")
result = self.nodes[0].getblockfrompeer(short_tip, peer_0_peer_1_id)
- self.wait_until(lambda: self.check_for_block(short_tip), timeout=1)
+ self.wait_until(lambda: self.check_for_block(node=0, hash=short_tip), timeout=1)
assert_equal(result, {})
self.log.info("Don't fetch blocks we already have")
assert_raises_rpc_error(-1, "Block already downloaded", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id)
+ self.log.info("Don't fetch blocks while the node has not synced past it yet")
+ # For this test we need node 1 in prune mode and as a side effect this also disconnects
+ # the nodes which is also necessary for the rest of the test.
+ self.restart_node(1, ["-prune=550"])
+
+ # Generate a block on the disconnected node that the pruning node is not connected to
+ blockhash = self.generate(self.nodes[0], 1, sync_fun=self.no_op)[0]
+ block_hex = self.nodes[0].getblock(blockhash=blockhash, verbosity=0)
+ block = from_hex(CBlock(), block_hex)
+
+ # Connect a P2PInterface to the pruning node and have it submit only the header of the
+ # block that the pruning node has not seen
+ node1_interface = self.nodes[1].add_p2p_connection(P2PInterface())
+ node1_interface.send_and_ping(msg_headers([block]))
+
+ # Get the peer id of the P2PInterface from the pruning node
+ node1_peers = self.nodes[1].getpeerinfo()
+ assert_equal(len(node1_peers), 1)
+ node1_interface_id = node1_peers[0]["id"]
+
+ # Trying to fetch this block from the P2PInterface should not be possible
+ error_msg = "In prune mode, only blocks that the node has already synced previously can be fetched from a peer"
+ assert_raises_rpc_error(-1, error_msg, self.nodes[1].getblockfrompeer, blockhash, node1_interface_id)
+
+ self.log.info("Connect pruned node")
+ # We need to generate more blocks to be able to prune
+ self.connect_nodes(0, 2)
+ pruned_node = self.nodes[2]
+ self.generate(self.nodes[0], 400, sync_fun=self.no_op)
+ self.sync_blocks([self.nodes[0], pruned_node])
+ pruneheight = pruned_node.pruneblockchain(300)
+ assert_equal(pruneheight, 248)
+ # Ensure the block is actually pruned
+ pruned_block = self.nodes[0].getblockhash(2)
+ assert_raises_rpc_error(-1, "Block not available (pruned data)", pruned_node.getblock, pruned_block)
+
+ self.log.info("Fetch pruned block")
+ peers = pruned_node.getpeerinfo()
+ assert_equal(len(peers), 1)
+ pruned_node_peer_0_id = peers[0]["id"]
+ result = pruned_node.getblockfrompeer(pruned_block, pruned_node_peer_0_id)
+ self.wait_until(lambda: self.check_for_block(node=2, hash=pruned_block), timeout=1)
+ assert_equal(result, {})
+
+ self.log.info("Fetched block persists after next pruning event")
+ self.generate(self.nodes[0], 250, sync_fun=self.no_op)
+ self.sync_blocks([self.nodes[0], pruned_node])
+ pruneheight += 251
+ assert_equal(pruned_node.pruneblockchain(700), pruneheight)
+ assert_equal(pruned_node.getblock(pruned_block)["hash"], "36c56c5b5ebbaf90d76b0d1a074dcb32d42abab75b7ec6fa0ffd9b4fbce8f0f7")
+
+ self.log.info("Fetched block can be pruned again when prune height exceeds the height of the tip at the time when the block was fetched")
+ self.generate(self.nodes[0], 250, sync_fun=self.no_op)
+ self.sync_blocks([self.nodes[0], pruned_node])
+ pruneheight += 250
+ assert_equal(pruned_node.pruneblockchain(1000), pruneheight)
+ assert_raises_rpc_error(-1, "Block not available (pruned data)", pruned_node.getblock, pruned_block)
+
if __name__ == '__main__':
GetBlockFromPeerTest().main()
diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py
index 1ea1ee5659..bf261befcc 100755
--- a/test/functional/rpc_getblockstats.py
+++ b/test/functional/rpc_getblockstats.py
@@ -43,6 +43,10 @@ class GetblockstatsTest(BitcoinTestFramework):
def generate_test_data(self, filename):
mocktime = 1525107225
self.nodes[0].setmocktime(mocktime)
+ self.nodes[0].createwallet(wallet_name='test')
+ privkey = self.nodes[0].get_deterministic_priv_key().key
+ self.nodes[0].importprivkey(privkey)
+
self.generate(self.nodes[0], COINBASE_MATURITY + 1)
address = self.nodes[0].get_deterministic_priv_key().address
@@ -53,6 +57,8 @@ class GetblockstatsTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=False)
self.nodes[0].settxfee(amount=0.003)
self.nodes[0].sendtoaddress(address=address, amount=1, subtractfeefromamount=True)
+ # Send to OP_RETURN output to test its exclusion from statistics
+ self.nodes[0].send(outputs={"data": "21"})
self.sync_all()
self.generate(self.nodes[0], 1)
@@ -161,6 +167,20 @@ class GetblockstatsTest(BitcoinTestFramework):
assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats, '00', 1, 2)
assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats)
+ self.log.info('Test block height 0')
+ genesis_stats = self.nodes[0].getblockstats(0)
+ assert_equal(genesis_stats["blockhash"], "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")
+ assert_equal(genesis_stats["utxo_increase"], 1)
+ assert_equal(genesis_stats["utxo_size_inc"], 117)
+ assert_equal(genesis_stats["utxo_increase_actual"], 0)
+ assert_equal(genesis_stats["utxo_size_inc_actual"], 0)
+
+ self.log.info('Test tip including OP_RETURN')
+ tip_stats = self.nodes[0].getblockstats(tip)
+ assert_equal(tip_stats["utxo_increase"], 6)
+ assert_equal(tip_stats["utxo_size_inc"], 441)
+ assert_equal(tip_stats["utxo_increase_actual"], 4)
+ assert_equal(tip_stats["utxo_size_inc_actual"], 300)
if __name__ == '__main__':
GetblockstatsTest().main()
diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py
index f683577c47..7acc3cbbd5 100755
--- a/test/functional/rpc_help.py
+++ b/test/functional/rpc_help.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 RPC help output."""
@@ -43,6 +43,9 @@ def process_mapping(fname):
class HelpRpcTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
self.supports_cli = False
diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py
index fcc49d0a75..fd282a9bc1 100755
--- a/test/functional/rpc_invalid_address_message.py
+++ b/test/functional/rpc_invalid_address_message.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 error messages for 'getaddressinfo' and 'validateaddress' RPC commands."""
@@ -39,6 +39,9 @@ INVALID_ADDRESS = 'asfah14i8fajz0123f'
INVALID_ADDRESS_2 = '1q049ldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
class InvalidAddressErrorMessageTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
@@ -61,7 +64,7 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
def test_validateaddress(self):
# Invalid Bech32
self.check_invalid(BECH32_INVALID_SIZE, 'Invalid Bech32 address data size')
- self.check_invalid(BECH32_INVALID_PREFIX, 'Not a valid Bech32 or Base58 encoding')
+ self.check_invalid(BECH32_INVALID_PREFIX, 'Invalid or unsupported Segwit (Bech32) or Base58 encoding.')
self.check_invalid(BECH32_INVALID_BECH32, 'Version 1+ witness address must use Bech32m checksum')
self.check_invalid(BECH32_INVALID_BECH32M, 'Version 0 witness address must use Bech32 checksum')
self.check_invalid(BECH32_INVALID_VERSION, 'Invalid Bech32 address witness version')
@@ -81,27 +84,31 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
self.check_valid(BECH32_VALID_MULTISIG)
# Invalid Base58
- self.check_invalid(BASE58_INVALID_PREFIX, 'Invalid prefix for Base58-encoded address')
- self.check_invalid(BASE58_INVALID_CHECKSUM, 'Invalid checksum or length of Base58 address')
- self.check_invalid(BASE58_INVALID_LENGTH, 'Invalid checksum or length of Base58 address')
+ self.check_invalid(BASE58_INVALID_PREFIX, 'Invalid or unsupported Base58-encoded address.')
+ self.check_invalid(BASE58_INVALID_CHECKSUM, 'Invalid checksum or length of Base58 address (P2PKH or P2SH)')
+ self.check_invalid(BASE58_INVALID_LENGTH, 'Invalid checksum or length of Base58 address (P2PKH or P2SH)')
# Valid Base58
self.check_valid(BASE58_VALID)
# Invalid address format
- self.check_invalid(INVALID_ADDRESS, 'Not a valid Bech32 or Base58 encoding')
- self.check_invalid(INVALID_ADDRESS_2, 'Not a valid Bech32 or Base58 encoding')
+ self.check_invalid(INVALID_ADDRESS, 'Invalid or unsupported Segwit (Bech32) or Base58 encoding.')
+ self.check_invalid(INVALID_ADDRESS_2, 'Invalid or unsupported Segwit (Bech32) or Base58 encoding.')
- def test_getaddressinfo(self):
node = self.nodes[0]
- assert_raises_rpc_error(-5, "Invalid Bech32 address data size", node.getaddressinfo, BECH32_INVALID_SIZE)
-
- assert_raises_rpc_error(-5, "Not a valid Bech32 or Base58 encoding", node.getaddressinfo, BECH32_INVALID_PREFIX)
+ # Missing arg returns the help text
+ assert_raises_rpc_error(-1, "Return information about the given bitcoin address.", node.validateaddress)
+ # Explicit None is not allowed for required parameters
+ assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", node.validateaddress, None)
- assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", node.getaddressinfo, BASE58_INVALID_PREFIX)
+ def test_getaddressinfo(self):
+ node = self.nodes[0]
- assert_raises_rpc_error(-5, "Not a valid Bech32 or Base58 encoding", node.getaddressinfo, INVALID_ADDRESS)
+ assert_raises_rpc_error(-5, "Invalid Bech32 address data size", node.getaddressinfo, BECH32_INVALID_SIZE)
+ assert_raises_rpc_error(-5, "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", node.getaddressinfo, BECH32_INVALID_PREFIX)
+ assert_raises_rpc_error(-5, "Invalid or unsupported Base58-encoded address.", node.getaddressinfo, BASE58_INVALID_PREFIX)
+ assert_raises_rpc_error(-5, "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", node.getaddressinfo, INVALID_ADDRESS)
def run_test(self):
self.test_validateaddress()
diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py
index 1e33e7ca9c..69c5397ce2 100755
--- a/test/functional/rpc_invalidateblock.py
+++ b/test/functional/rpc_invalidateblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 invalidateblock RPC."""
diff --git a/test/functional/rpc_mempool_info.py b/test/functional/rpc_mempool_info.py
index 9b5a3b9112..246af22e50 100755
--- a/test/functional/rpc_mempool_info.py
+++ b/test/functional/rpc_mempool_info.py
@@ -18,7 +18,6 @@ class RPCMempoolInfoTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
confirmed_utxo = self.wallet.get_utxo()
# Create a tree of unconfirmed transactions in the mempool:
@@ -84,7 +83,7 @@ class RPCMempoolInfoTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", self.nodes[0].gettxspendingprevout, [{'txid' : txidA, 'vout' : -1}])
self.log.info("Invalid txid provided")
- assert_raises_rpc_error(-3, "Expected type string for txid, got number", self.nodes[0].gettxspendingprevout, [{'txid' : 42, 'vout' : 0}])
+ assert_raises_rpc_error(-3, "JSON value of type number for field txid is not of expected type string", self.nodes[0].gettxspendingprevout, [{'txid' : 42, 'vout' : 0}])
self.log.info("Missing outputs")
assert_raises_rpc_error(-8, "Invalid parameter, outputs are missing", self.nodes[0].gettxspendingprevout, [])
diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py
index f6ee6a5215..43d1e2c731 100755
--- a/test/functional/rpc_misc.py
+++ b/test/functional/rpc_misc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 RPC misc output."""
diff --git a/test/functional/rpc_named_arguments.py b/test/functional/rpc_named_arguments.py
index 41b9312969..46d9ffceae 100755
--- a/test/functional/rpc_named_arguments.py
+++ b/test/functional/rpc_named_arguments.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2019 The Bitcoin Core developers
+# Copyright (c) 2016-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test using named arguments for RPCs."""
@@ -30,6 +30,9 @@ class NamedArgumentTest(BitcoinTestFramework):
assert_equal(node.echo(arg1=1), [None, 1])
assert_equal(node.echo(arg9=None), [None]*10)
assert_equal(node.echo(arg0=0,arg3=3,arg9=9), [0] + [None]*2 + [3] + [None]*5 + [9])
+ assert_equal(node.echo(0, 1, arg3=3, arg5=5), [0, 1, None, 3, None, 5])
+ assert_raises_rpc_error(-8, "Parameter arg1 specified twice both as positional and named argument", node.echo, 0, 1, arg1=1)
+ assert_raises_rpc_error(-8, "Parameter arg1 specified twice both as positional and named argument", node.echo, 0, None, 2, arg1=1)
if __name__ == '__main__':
NamedArgumentTest().main()
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index ad8ba06824..5fdd5daddf 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 RPC calls related to net.
@@ -11,7 +11,6 @@ from decimal import Decimal
from itertools import product
import time
-from test_framework.blocktools import COINBASE_MATURITY
import test_framework.messages
from test_framework.p2p import (
P2PInterface,
@@ -43,7 +42,6 @@ def assert_net_servicesnames(servicesflag, servicenames):
class NetTest(BitcoinTestFramework):
def set_test_params(self):
- self.setup_clean_chain = True
self.num_nodes = 2
self.extra_args = [["-minrelaytxfee=0.00001000"], ["-minrelaytxfee=0.00000500"]]
self.supports_cli = False
@@ -51,9 +49,6 @@ class NetTest(BitcoinTestFramework):
def run_test(self):
# We need miniwallet to make a transaction
self.wallet = MiniWallet(self.nodes[0])
- self.generate(self.wallet, 1)
- # Get out of IBD for the minfeefilter and getpeerinfo tests.
- self.generate(self.nodes[0], COINBASE_MATURITY + 1)
# By default, the test framework sets up an addnode connection from
# node 1 --> node0. By connecting node0 --> node 1, we're left with
@@ -107,6 +102,55 @@ class NetTest(BitcoinTestFramework):
# Check dynamically generated networks list in getpeerinfo help output.
assert "(ipv4, ipv6, onion, i2p, cjdns, not_publicly_routable)" in self.nodes[0].help("getpeerinfo")
+ self.log.info("Check getpeerinfo output before a version message was sent")
+ no_version_peer_id = 2
+ no_version_peer_conntime = int(time.time())
+ self.nodes[0].setmocktime(no_version_peer_conntime)
+ with self.nodes[0].assert_debug_log([f"Added connection peer={no_version_peer_id}"]):
+ no_version_peer = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False)
+ self.nodes[0].setmocktime(0)
+ peer_info = self.nodes[0].getpeerinfo()[no_version_peer_id]
+ peer_info.pop("addr")
+ peer_info.pop("addrbind")
+ assert_equal(
+ peer_info,
+ {
+ "addr_processed": 0,
+ "addr_rate_limited": 0,
+ "addr_relay_enabled": False,
+ "bip152_hb_from": False,
+ "bip152_hb_to": False,
+ "bytesrecv": 0,
+ "bytesrecv_per_msg": {},
+ "bytessent": 0,
+ "bytessent_per_msg": {},
+ "connection_type": "inbound",
+ "conntime": no_version_peer_conntime,
+ "id": no_version_peer_id,
+ "inbound": True,
+ "inflight": [],
+ "last_block": 0,
+ "last_transaction": 0,
+ "lastrecv": 0,
+ "lastsend": 0,
+ "minfeefilter": Decimal("0E-8"),
+ "network": "not_publicly_routable",
+ "permissions": [],
+ "presynced_headers": -1,
+ "relaytxes": False,
+ "services": "0000000000000000",
+ "servicesnames": [],
+ "startingheight": -1,
+ "subver": "",
+ "synced_blocks": -1,
+ "synced_headers": -1,
+ "timeoffset": 0,
+ "version": 0,
+ },
+ )
+ no_version_peer.peer_disconnect()
+ self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 2)
+
def test_getnettotals(self):
self.log.info("Test getnettotals")
# Test getnettotals and getpeerinfo by doing a ping. The bytes
@@ -136,7 +180,8 @@ class NetTest(BitcoinTestFramework):
self.nodes[0].setnetworkactive(state=False)
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False)
# Wait a bit for all sockets to close
- self.wait_until(lambda: self.nodes[0].getnetworkinfo()['connections'] == 0, timeout=3)
+ for n in self.nodes:
+ self.wait_until(lambda: n.getnetworkinfo()['connections'] == 0, timeout=3)
with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']):
self.nodes[0].setnetworkactive(state=True)
@@ -257,6 +302,9 @@ class NetTest(BitcoinTestFramework):
assert_equal(node.addpeeraddress(address="", port=8333), {"success": False})
assert_equal(node.getnodeaddresses(count=0), [])
+ self.log.debug("Test that non-bool tried fails")
+ assert_raises_rpc_error(-3, "JSON value of type string is not of expected type bool", self.nodes[0].addpeeraddress, address="1.2.3.4", tried="True", port=1234)
+
self.log.debug("Test that adding an address with invalid port fails")
assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress, address="1.2.3.4", port=-1)
assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress,address="1.2.3.4", port=65536)
diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py
index 9a563cbf5f..6cb9760b3d 100755
--- a/test/functional/rpc_packages.py
+++ b/test/functional/rpc_packages.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""RPCs that handle raw transaction packages."""
@@ -7,35 +7,30 @@
from decimal import Decimal
import random
-from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
-from test_framework.test_framework import BitcoinTestFramework
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
- COIN,
- CTxInWitness,
tx_from_hex,
)
from test_framework.p2p import P2PTxInvStore
-from test_framework.script import (
- CScript,
- OP_TRUE,
-)
+from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_fee_amount,
assert_raises_rpc_error,
)
from test_framework.wallet import (
- create_child_with_parents,
- create_raw_chain,
+ COIN,
DEFAULT_FEE,
- make_chain,
+ MiniWallet,
)
+
class RPCPackagesTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
+ self.extra_args = [["-whitelist=noban@127.0.0.1"]] # noban speeds up tx relay
def assert_testres_equal(self, package_hex, testres_expected):
"""Shuffle package_hex and assert that the testmempoolaccept result matches testres_expected. This should only
@@ -49,38 +44,38 @@ class RPCPackagesTest(BitcoinTestFramework):
assert_equal(shuffled_testres, self.nodes[0].testmempoolaccept(shuffled_package))
def run_test(self):
- self.log.info("Generate blocks to create UTXOs")
node = self.nodes[0]
- self.privkeys = [node.get_deterministic_priv_key().key]
- self.address = node.get_deterministic_priv_key().address
- self.coins = []
- # The last 100 coinbase transactions are premature
- for b in self.generatetoaddress(node, 220, self.address)[:-100]:
- coinbase = node.getblock(blockhash=b, verbosity=2)["tx"][0]
- self.coins.append({
+
+ # get an UTXO that requires signature to be spent
+ deterministic_address = node.get_deterministic_priv_key().address
+ blockhash = self.generatetoaddress(node, 1, deterministic_address)[0]
+ coinbase = node.getblock(blockhash=blockhash, verbosity=2)["tx"][0]
+ coin = {
"txid": coinbase["txid"],
"amount": coinbase["vout"][0]["value"],
"scriptPubKey": coinbase["vout"][0]["scriptPubKey"],
- })
+ "vout": 0,
+ "height": 0
+ }
+
+ self.wallet = MiniWallet(self.nodes[0])
+ self.generate(self.wallet, COINBASE_MATURITY + 100) # blocks generated for inputs
+ self.log.info("Create some transactions")
# Create some transactions that can be reused throughout the test. Never submit these to mempool.
self.independent_txns_hex = []
self.independent_txns_testres = []
for _ in range(3):
- coin = self.coins.pop()
- rawtx = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}],
- {self.address : coin["amount"] - Decimal("0.0001")})
- signedtx = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys)
- assert signedtx["complete"]
- testres = node.testmempoolaccept([signedtx["hex"]])
+ tx_hex = self.wallet.create_self_transfer(fee_rate=Decimal("0.0001"))["hex"]
+ testres = self.nodes[0].testmempoolaccept([tx_hex])
assert testres[0]["allowed"]
- self.independent_txns_hex.append(signedtx["hex"])
+ self.independent_txns_hex.append(tx_hex)
# testmempoolaccept returns a list of length one, avoid creating a 2D list
self.independent_txns_testres.append(testres[0])
self.independent_txns_testres_blank = [{
"txid": res["txid"], "wtxid": res["wtxid"]} for res in self.independent_txns_testres]
- self.test_independent()
+ self.test_independent(coin)
self.test_chain()
self.test_multiple_children()
self.test_multiple_parents()
@@ -88,14 +83,15 @@ class RPCPackagesTest(BitcoinTestFramework):
self.test_rbf()
self.test_submitpackage()
- def test_independent(self):
+ def test_independent(self, coin):
self.log.info("Test multiple independent transactions in a package")
node = self.nodes[0]
# For independent transactions, order doesn't matter.
self.assert_testres_equal(self.independent_txns_hex, self.independent_txns_testres)
self.log.info("Test an otherwise valid package with an extra garbage tx appended")
- garbage_tx = node.createrawtransaction([{"txid": "00" * 32, "vout": 5}], {self.address: 1})
+ address = node.get_deterministic_priv_key().address
+ garbage_tx = node.createrawtransaction([{"txid": "00" * 32, "vout": 5}], {address: 1})
tx = tx_from_hex(garbage_tx)
# Only the txid and wtxids are returned because validation is incomplete for the independent txns.
# Package validation is atomic: if the node cannot find a UTXO for any single tx in the package,
@@ -105,9 +101,8 @@ class RPCPackagesTest(BitcoinTestFramework):
self.assert_testres_equal(package_bad, testres_bad)
self.log.info("Check testmempoolaccept tells us when some transactions completed validation successfully")
- coin = self.coins.pop()
tx_bad_sig_hex = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}],
- {self.address : coin["amount"] - Decimal("0.0001")})
+ {address : coin["amount"] - Decimal("0.0001")})
tx_bad_sig = tx_from_hex(tx_bad_sig_hex)
testres_bad_sig = node.testmempoolaccept(self.independent_txns_hex + [tx_bad_sig_hex])
# By the time the signature for the last transaction is checked, all the other transactions
@@ -120,23 +115,22 @@ class RPCPackagesTest(BitcoinTestFramework):
}])
self.log.info("Check testmempoolaccept reports txns in packages that exceed max feerate")
- coin = self.coins.pop()
- tx_high_fee_raw = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}],
- {self.address : coin["amount"] - Decimal("0.999")})
- tx_high_fee_signed = node.signrawtransactionwithkey(hexstring=tx_high_fee_raw, privkeys=self.privkeys)
- assert tx_high_fee_signed["complete"]
- tx_high_fee = tx_from_hex(tx_high_fee_signed["hex"])
- testres_high_fee = node.testmempoolaccept([tx_high_fee_signed["hex"]])
+ tx_high_fee = self.wallet.create_self_transfer(fee=Decimal("0.999"))
+ testres_high_fee = node.testmempoolaccept([tx_high_fee["hex"]])
assert_equal(testres_high_fee, [
- {"txid": tx_high_fee.rehash(), "wtxid": tx_high_fee.getwtxid(), "allowed": False, "reject-reason": "max-fee-exceeded"}
+ {"txid": tx_high_fee["txid"], "wtxid": tx_high_fee["wtxid"], "allowed": False, "reject-reason": "max-fee-exceeded"}
])
- package_high_fee = [tx_high_fee_signed["hex"]] + self.independent_txns_hex
+ package_high_fee = [tx_high_fee["hex"]] + self.independent_txns_hex
testres_package_high_fee = node.testmempoolaccept(package_high_fee)
assert_equal(testres_package_high_fee, testres_high_fee + self.independent_txns_testres_blank)
def test_chain(self):
node = self.nodes[0]
- (chain_hex, chain_txns) = create_raw_chain(node, self.coins.pop(), self.address, self.privkeys)
+
+ chain = self.wallet.create_self_transfer_chain(chain_length=25)
+ chain_hex = [t["hex"] for t in chain]
+ chain_txns = [t["tx"] for t in chain]
+
self.log.info("Check that testmempoolaccept requires packages to be sorted by dependency")
assert_equal(node.testmempoolaccept(rawtxs=chain_hex[::-1]),
[{"txid": tx.rehash(), "wtxid": tx.getwtxid(), "package-error": "package-not-sorted"} for tx in chain_txns[::-1]])
@@ -158,78 +152,57 @@ class RPCPackagesTest(BitcoinTestFramework):
def test_multiple_children(self):
node = self.nodes[0]
-
self.log.info("Testmempoolaccept a package in which a transaction has two children within the package")
- first_coin = self.coins.pop()
- value = (first_coin["amount"] - Decimal("0.0002")) / 2 # Deduct reasonable fee and make 2 outputs
- inputs = [{"txid": first_coin["txid"], "vout": 0}]
- outputs = [{self.address : value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE : value}]
- rawtx = node.createrawtransaction(inputs, outputs)
-
- parent_signed = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys)
- assert parent_signed["complete"]
- parent_tx = tx_from_hex(parent_signed["hex"])
- parent_txid = parent_tx.rehash()
- assert node.testmempoolaccept([parent_signed["hex"]])[0]["allowed"]
- parent_locking_script_a = parent_tx.vout[0].scriptPubKey.hex()
- child_value = value - Decimal("0.0001")
+ parent_tx = self.wallet.create_self_transfer_multi(num_outputs=2)
+ assert node.testmempoolaccept([parent_tx["hex"]])[0]["allowed"]
# Child A
- (_, tx_child_a_hex, _, _) = make_chain(node, self.address, self.privkeys, parent_txid, child_value, 0, parent_locking_script_a)
- assert not node.testmempoolaccept([tx_child_a_hex])[0]["allowed"]
+ child_a_tx = self.wallet.create_self_transfer(utxo_to_spend=parent_tx["new_utxos"][0])
+ assert not node.testmempoolaccept([child_a_tx["hex"]])[0]["allowed"]
# Child B
- rawtx_b = node.createrawtransaction([{"txid": parent_txid, "vout": 1}], {self.address : child_value})
- tx_child_b = tx_from_hex(rawtx_b)
- tx_child_b.wit.vtxinwit = [CTxInWitness()]
- tx_child_b.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
- tx_child_b_hex = tx_child_b.serialize().hex()
- assert not node.testmempoolaccept([tx_child_b_hex])[0]["allowed"]
+ child_b_tx = self.wallet.create_self_transfer(utxo_to_spend=parent_tx["new_utxos"][1])
+ assert not node.testmempoolaccept([child_b_tx["hex"]])[0]["allowed"]
self.log.info("Testmempoolaccept with entire package, should work with children in either order")
- testres_multiple_ab = node.testmempoolaccept(rawtxs=[parent_signed["hex"], tx_child_a_hex, tx_child_b_hex])
- testres_multiple_ba = node.testmempoolaccept(rawtxs=[parent_signed["hex"], tx_child_b_hex, tx_child_a_hex])
+ testres_multiple_ab = node.testmempoolaccept(rawtxs=[parent_tx["hex"], child_a_tx["hex"], child_b_tx["hex"]])
+ testres_multiple_ba = node.testmempoolaccept(rawtxs=[parent_tx["hex"], child_b_tx["hex"], child_a_tx["hex"]])
assert all([testres["allowed"] for testres in testres_multiple_ab + testres_multiple_ba])
testres_single = []
# Test accept and then submit each one individually, which should be identical to package testaccept
- for rawtx in [parent_signed["hex"], tx_child_a_hex, tx_child_b_hex]:
+ for rawtx in [parent_tx["hex"], child_a_tx["hex"], child_b_tx["hex"]]:
testres = node.testmempoolaccept([rawtx])
testres_single.append(testres[0])
# Submit the transaction now so its child should have no problem validating
node.sendrawtransaction(rawtx)
assert_equal(testres_single, testres_multiple_ab)
-
def test_multiple_parents(self):
node = self.nodes[0]
-
self.log.info("Testmempoolaccept a package in which a transaction has multiple parents within the package")
+
for num_parents in [2, 10, 24]:
# Test a package with num_parents parents and 1 child transaction.
+ parent_coins = []
package_hex = []
- parents_tx = []
- values = []
- parent_locking_scripts = []
+
for _ in range(num_parents):
- parent_coin = self.coins.pop()
- value = parent_coin["amount"]
- (tx, txhex, value, parent_locking_script) = make_chain(node, self.address, self.privkeys, parent_coin["txid"], value)
- package_hex.append(txhex)
- parents_tx.append(tx)
- values.append(value)
- parent_locking_scripts.append(parent_locking_script)
- child_hex = create_child_with_parents(node, self.address, self.privkeys, parents_tx, values, parent_locking_scripts)
- # Package accept should work with the parents in any order (as long as parents come before child)
+ # Package accept should work with the parents in any order (as long as parents come before child)
+ parent_tx = self.wallet.create_self_transfer()
+ parent_coins.append(parent_tx["new_utxo"])
+ package_hex.append(parent_tx["hex"])
+
+ child_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_coins, fee_per_output=2000)
for _ in range(10):
random.shuffle(package_hex)
- testres_multiple = node.testmempoolaccept(rawtxs=package_hex + [child_hex])
+ testres_multiple = node.testmempoolaccept(rawtxs=package_hex + [child_tx['hex']])
assert all([testres["allowed"] for testres in testres_multiple])
testres_single = []
# Test accept and then submit each one individually, which should be identical to package testaccept
- for rawtx in package_hex + [child_hex]:
+ for rawtx in package_hex + [child_tx["hex"]]:
testres_single.append(node.testmempoolaccept([rawtx])[0])
# Submit the transaction now so its child should have no problem validating
node.sendrawtransaction(rawtx)
@@ -237,77 +210,63 @@ class RPCPackagesTest(BitcoinTestFramework):
def test_conflicting(self):
node = self.nodes[0]
- prevtx = self.coins.pop()
- inputs = [{"txid": prevtx["txid"], "vout": 0}]
- output1 = {node.get_deterministic_priv_key().address: 50 - 0.00125}
- output2 = {ADDRESS_BCRT1_P2WSH_OP_TRUE: 50 - 0.00125}
+ coin = self.wallet.get_utxo()
# tx1 and tx2 share the same inputs
- rawtx1 = node.createrawtransaction(inputs, output1)
- rawtx2 = node.createrawtransaction(inputs, output2)
- signedtx1 = node.signrawtransactionwithkey(hexstring=rawtx1, privkeys=self.privkeys)
- signedtx2 = node.signrawtransactionwithkey(hexstring=rawtx2, privkeys=self.privkeys)
- tx1 = tx_from_hex(signedtx1["hex"])
- tx2 = tx_from_hex(signedtx2["hex"])
- assert signedtx1["complete"]
- assert signedtx2["complete"]
+ tx1 = self.wallet.create_self_transfer(utxo_to_spend=coin)
+ tx2 = self.wallet.create_self_transfer(utxo_to_spend=coin)
# Ensure tx1 and tx2 are valid by themselves
- assert node.testmempoolaccept([signedtx1["hex"]])[0]["allowed"]
- assert node.testmempoolaccept([signedtx2["hex"]])[0]["allowed"]
+ assert node.testmempoolaccept([tx1["hex"]])[0]["allowed"]
+ assert node.testmempoolaccept([tx2["hex"]])[0]["allowed"]
self.log.info("Test duplicate transactions in the same package")
- testres = node.testmempoolaccept([signedtx1["hex"], signedtx1["hex"]])
+ testres = node.testmempoolaccept([tx1["hex"], tx1["hex"]])
assert_equal(testres, [
- {"txid": tx1.rehash(), "wtxid": tx1.getwtxid(), "package-error": "conflict-in-package"},
- {"txid": tx1.rehash(), "wtxid": tx1.getwtxid(), "package-error": "conflict-in-package"}
+ {"txid": tx1["txid"], "wtxid": tx1["wtxid"], "package-error": "conflict-in-package"},
+ {"txid": tx1["txid"], "wtxid": tx1["wtxid"], "package-error": "conflict-in-package"}
])
self.log.info("Test conflicting transactions in the same package")
- testres = node.testmempoolaccept([signedtx1["hex"], signedtx2["hex"]])
+ testres = node.testmempoolaccept([tx1["hex"], tx2["hex"]])
assert_equal(testres, [
- {"txid": tx1.rehash(), "wtxid": tx1.getwtxid(), "package-error": "conflict-in-package"},
- {"txid": tx2.rehash(), "wtxid": tx2.getwtxid(), "package-error": "conflict-in-package"}
+ {"txid": tx1["txid"], "wtxid": tx1["wtxid"], "package-error": "conflict-in-package"},
+ {"txid": tx2["txid"], "wtxid": tx2["wtxid"], "package-error": "conflict-in-package"}
])
def test_rbf(self):
node = self.nodes[0]
- coin = self.coins.pop()
- inputs = [{"txid": coin["txid"], "vout": 0, "sequence": MAX_BIP125_RBF_SEQUENCE}]
- fee = Decimal('0.00125000')
- output = {node.get_deterministic_priv_key().address: 50 - fee}
- raw_replaceable_tx = node.createrawtransaction(inputs, output)
- signed_replaceable_tx = node.signrawtransactionwithkey(hexstring=raw_replaceable_tx, privkeys=self.privkeys)
- testres_replaceable = node.testmempoolaccept([signed_replaceable_tx["hex"]])
- replaceable_tx = tx_from_hex(signed_replaceable_tx["hex"])
- assert_equal(testres_replaceable, [
- {"txid": replaceable_tx.rehash(), "wtxid": replaceable_tx.getwtxid(),
- "allowed": True, "vsize": replaceable_tx.get_vsize(), "fees": { "base": fee }}
- ])
- # Replacement transaction is identical except has double the fee
- replacement_tx = tx_from_hex(signed_replaceable_tx["hex"])
- replacement_tx.vout[0].nValue -= int(fee * COIN) # Doubled fee
- signed_replacement_tx = node.signrawtransactionwithkey(replacement_tx.serialize().hex(), self.privkeys)
- replacement_tx = tx_from_hex(signed_replacement_tx["hex"])
+ coin = self.wallet.get_utxo()
+ fee = Decimal("0.00125000")
+ replaceable_tx = self.wallet.create_self_transfer(utxo_to_spend=coin, sequence=MAX_BIP125_RBF_SEQUENCE, fee = fee)
+ testres_replaceable = node.testmempoolaccept([replaceable_tx["hex"]])[0]
+ assert_equal(testres_replaceable["txid"], replaceable_tx["txid"])
+ assert_equal(testres_replaceable["wtxid"], replaceable_tx["wtxid"])
+ assert testres_replaceable["allowed"]
+ assert_equal(testres_replaceable["vsize"], replaceable_tx["tx"].get_vsize())
+ assert_equal(testres_replaceable["fees"]["base"], fee)
+ assert_fee_amount(fee, replaceable_tx["tx"].get_vsize(), testres_replaceable["fees"]["effective-feerate"])
+ assert_equal(testres_replaceable["fees"]["effective-includes"], [replaceable_tx["wtxid"]])
- self.log.info("Test that transactions within a package cannot replace each other")
- testres_rbf_conflicting = node.testmempoolaccept([signed_replaceable_tx["hex"], signed_replacement_tx["hex"]])
+ # Replacement transaction is identical except has double the fee
+ replacement_tx = self.wallet.create_self_transfer(utxo_to_spend=coin, sequence=MAX_BIP125_RBF_SEQUENCE, fee = 2 * fee)
+ testres_rbf_conflicting = node.testmempoolaccept([replaceable_tx["hex"], replacement_tx["hex"]])
assert_equal(testres_rbf_conflicting, [
- {"txid": replaceable_tx.rehash(), "wtxid": replaceable_tx.getwtxid(), "package-error": "conflict-in-package"},
- {"txid": replacement_tx.rehash(), "wtxid": replacement_tx.getwtxid(), "package-error": "conflict-in-package"}
+ {"txid": replaceable_tx["txid"], "wtxid": replaceable_tx["wtxid"], "package-error": "conflict-in-package"},
+ {"txid": replacement_tx["txid"], "wtxid": replacement_tx["wtxid"], "package-error": "conflict-in-package"}
])
self.log.info("Test that packages cannot conflict with mempool transactions, even if a valid BIP125 RBF")
- node.sendrawtransaction(signed_replaceable_tx["hex"])
- testres_rbf_single = node.testmempoolaccept([signed_replacement_tx["hex"]])
# This transaction is a valid BIP125 replace-by-fee
+ self.wallet.sendrawtransaction(from_node=node, tx_hex=replaceable_tx["hex"])
+ testres_rbf_single = node.testmempoolaccept([replacement_tx["hex"]])
assert testres_rbf_single[0]["allowed"]
testres_rbf_package = self.independent_txns_testres_blank + [{
- "txid": replacement_tx.rehash(), "wtxid": replacement_tx.getwtxid(), "allowed": False,
+ "txid": replacement_tx["txid"], "wtxid": replacement_tx["wtxid"], "allowed": False,
"reject-reason": "bip125-replacement-disallowed"
}]
- self.assert_testres_equal(self.independent_txns_hex + [signed_replacement_tx["hex"]], testres_rbf_package)
+ self.assert_testres_equal(self.independent_txns_hex + [replacement_tx["hex"]], testres_rbf_package)
def assert_equal_package_results(self, node, testmempoolaccept_result, submitpackage_result):
"""Assert that a successful submitpackage result is consistent with testmempoolaccept
@@ -330,90 +289,78 @@ class RPCPackagesTest(BitcoinTestFramework):
def test_submit_child_with_parents(self, num_parents, partial_submit):
node = self.nodes[0]
peer = node.add_p2p_connection(P2PTxInvStore())
- # Test a package with num_parents parents and 1 child transaction.
- package_hex = []
+
package_txns = []
- values = []
- scripts = []
+ presubmitted_wtxids = set()
for _ in range(num_parents):
- parent_coin = self.coins.pop()
- value = parent_coin["amount"]
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, parent_coin["txid"], value)
- package_hex.append(txhex)
- package_txns.append(tx)
- values.append(value)
- scripts.append(spk)
+ parent_tx = self.wallet.create_self_transfer(fee=DEFAULT_FEE)
+ package_txns.append(parent_tx)
if partial_submit and random.choice([True, False]):
- node.sendrawtransaction(txhex)
- child_hex = create_child_with_parents(node, self.address, self.privkeys, package_txns, values, scripts)
- package_hex.append(child_hex)
- package_txns.append(tx_from_hex(child_hex))
+ node.sendrawtransaction(parent_tx["hex"])
+ presubmitted_wtxids.add(parent_tx["wtxid"])
+ child_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=[tx["new_utxo"] for tx in package_txns], fee_per_output=10000) #DEFAULT_FEE
+ package_txns.append(child_tx)
- testmempoolaccept_result = node.testmempoolaccept(rawtxs=package_hex)
- submitpackage_result = node.submitpackage(package=package_hex)
+ testmempoolaccept_result = node.testmempoolaccept(rawtxs=[tx["hex"] for tx in package_txns])
+ submitpackage_result = node.submitpackage(package=[tx["hex"] for tx in package_txns])
# Check that each result is present, with the correct size and fees
- for i in range(num_parents + 1):
- tx = package_txns[i]
+ for package_txn in package_txns:
+ tx = package_txn["tx"]
+ assert tx.getwtxid() in submitpackage_result["tx-results"]
wtxid = tx.getwtxid()
assert wtxid in submitpackage_result["tx-results"]
tx_result = submitpackage_result["tx-results"][wtxid]
- assert_equal(tx_result, {
- "txid": tx.rehash(),
- "vsize": tx.get_vsize(),
- "fees": {
- "base": DEFAULT_FEE,
- }
- })
+ assert_equal(tx_result["txid"], tx.rehash())
+ assert_equal(tx_result["vsize"], tx.get_vsize())
+ assert_equal(tx_result["fees"]["base"], DEFAULT_FEE)
+ if wtxid not in presubmitted_wtxids:
+ assert_fee_amount(DEFAULT_FEE, tx.get_vsize(), tx_result["fees"]["effective-feerate"])
+ assert_equal(tx_result["fees"]["effective-includes"], [wtxid])
# submitpackage result should be consistent with testmempoolaccept and getmempoolentry
self.assert_equal_package_results(node, testmempoolaccept_result, submitpackage_result)
- # Package feerate is calculated for the remaining transactions after deduplication and
- # individual submission. If only 0 or 1 transaction is left, e.g. because all transactions
- # had high-feerates or were already in the mempool, no package feerate is provided.
- # In this case, since all of the parents have high fees, each is accepted individually.
- assert "package-feerate" not in submitpackage_result
-
# The node should announce each transaction. No guarantees for propagation.
- peer.wait_for_broadcast([tx.getwtxid() for tx in package_txns])
+ peer.wait_for_broadcast([tx["tx"].getwtxid() for tx in package_txns])
self.generate(node, 1)
-
def test_submit_cpfp(self):
node = self.nodes[0]
peer = node.add_p2p_connection(P2PTxInvStore())
- # 2 parent 1 child CPFP. First parent pays high fees, second parent pays 0 fees and is
- # fee-bumped by the child.
- coin_rich = self.coins.pop()
- coin_poor = self.coins.pop()
- tx_rich, hex_rich, value_rich, spk_rich = make_chain(node, self.address, self.privkeys, coin_rich["txid"], coin_rich["amount"])
- tx_poor, hex_poor, value_poor, spk_poor = make_chain(node, self.address, self.privkeys, coin_poor["txid"], coin_poor["amount"], fee=0)
+ # Package with 2 parents and 1 child. One parent pays for itself using modified fees, and
+ # another has 0 fees but is bumped by child.
+ tx_poor = self.wallet.create_self_transfer(fee=0, fee_rate=0)
+ tx_rich = self.wallet.create_self_transfer(fee=0, fee_rate=0)
+ node.prioritisetransaction(tx_rich["txid"], 0, int(DEFAULT_FEE * COIN))
package_txns = [tx_rich, tx_poor]
- hex_child = create_child_with_parents(node, self.address, self.privkeys, package_txns, [value_rich, value_poor], [spk_rich, spk_poor])
- tx_child = tx_from_hex(hex_child)
+ coins = [tx["new_utxo"] for tx in package_txns]
+ tx_child = self.wallet.create_self_transfer_multi(utxos_to_spend=coins, fee_per_output=10000) #DEFAULT_FEE
package_txns.append(tx_child)
- submitpackage_result = node.submitpackage([hex_rich, hex_poor, hex_child])
+ submitpackage_result = node.submitpackage([tx["hex"] for tx in package_txns])
- rich_parent_result = submitpackage_result["tx-results"][tx_rich.getwtxid()]
- poor_parent_result = submitpackage_result["tx-results"][tx_poor.getwtxid()]
- child_result = submitpackage_result["tx-results"][tx_child.getwtxid()]
- assert_equal(rich_parent_result["fees"]["base"], DEFAULT_FEE)
+ rich_parent_result = submitpackage_result["tx-results"][tx_rich["wtxid"]]
+ poor_parent_result = submitpackage_result["tx-results"][tx_poor["wtxid"]]
+ child_result = submitpackage_result["tx-results"][tx_child["tx"].getwtxid()]
+ assert_equal(rich_parent_result["fees"]["base"], 0)
assert_equal(poor_parent_result["fees"]["base"], 0)
assert_equal(child_result["fees"]["base"], DEFAULT_FEE)
- # Package feerate is calculated for the remaining transactions after deduplication and
- # individual submission. Since this package had a 0-fee parent, package feerate must have
- # been used and returned.
- assert "package-feerate" in submitpackage_result
- assert_fee_amount(DEFAULT_FEE, rich_parent_result["vsize"] + child_result["vsize"], submitpackage_result["package-feerate"])
+ # The "rich" parent does not require CPFP so its effective feerate.
+ assert_fee_amount(DEFAULT_FEE, tx_rich["tx"].get_vsize(), rich_parent_result["fees"]["effective-feerate"])
+ assert_equal(rich_parent_result["fees"]["effective-includes"], [tx_rich["wtxid"]])
+ # The "poor" parent and child's effective feerates are the same, composed of the child's fee
+ # divided by their combined vsize.
+ assert_fee_amount(DEFAULT_FEE, tx_poor["tx"].get_vsize() + tx_child["tx"].get_vsize(), poor_parent_result["fees"]["effective-feerate"])
+ assert_fee_amount(DEFAULT_FEE, tx_poor["tx"].get_vsize() + tx_child["tx"].get_vsize(), child_result["fees"]["effective-feerate"])
+ assert_equal([tx_poor["wtxid"], tx_child["tx"].getwtxid()], poor_parent_result["fees"]["effective-includes"])
+ assert_equal([tx_poor["wtxid"], tx_child["tx"].getwtxid()], child_result["fees"]["effective-includes"])
# The node will broadcast each transaction, still abiding by its peer's fee filter
- peer.wait_for_broadcast([tx.getwtxid() for tx in package_txns])
+ peer.wait_for_broadcast([tx["tx"].getwtxid() for tx in package_txns])
self.generate(node, 1)
-
def test_submitpackage(self):
node = self.nodes[0]
@@ -427,7 +374,7 @@ class RPCPackagesTest(BitcoinTestFramework):
self.log.info("Submitpackage only allows packages of 1 child with its parents")
# Chain of 3 transactions has too many generations
- chain_hex, _ = create_raw_chain(node, self.coins.pop(), self.address, self.privkeys, 3)
+ chain_hex = [t["hex"] for t in self.wallet.create_self_transfer_chain(chain_length=25)]
assert_raises_rpc_error(-25, "not-child-with-parents", node.submitpackage, chain_hex)
diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py
index 91298937fd..3062a86565 100755
--- a/test/functional/rpc_preciousblock.py
+++ b/test/functional/rpc_preciousblock.py
@@ -16,7 +16,7 @@ def unidirectional_node_sync_via_rpc(node_src, node_dest):
try:
assert len(node_dest.getblock(blockhash, False)) > 0
break
- except:
+ except Exception:
blocks_to_copy.append(blockhash)
blockhash = node_src.getblockheader(blockhash, True)['previousblockhash']
blocks_to_copy.reverse()
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 4583ca25cf..76886cc0ea 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -1,10 +1,9 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 Partially Signed Transaction RPCs.
"""
-
from decimal import Decimal
from itertools import product
@@ -27,12 +26,17 @@ from test_framework.psbt import (
PSBT_IN_SHA256,
PSBT_IN_HASH160,
PSBT_IN_HASH256,
+ PSBT_IN_NON_WITNESS_UTXO,
+ PSBT_IN_WITNESS_UTXO,
+ PSBT_OUT_TAP_TREE,
)
+from test_framework.script import CScript, OP_TRUE
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_approx,
assert_equal,
assert_greater_than,
+ assert_greater_than_or_equal,
assert_raises_rpc_error,
find_output,
find_vout_for_address,
@@ -44,8 +48,9 @@ import json
import os
-# Create one-input, one-output, no-fee transaction:
class PSBTTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
def set_test_params(self):
self.num_nodes = 3
@@ -54,13 +59,16 @@ class PSBTTest(BitcoinTestFramework):
["-walletrbf=0", "-changetype=legacy"],
[]
]
+ # whitelist peers to speed up tx relay / mempool sync
+ for args in self.extra_args:
+ args.append("-whitelist=noban@127.0.0.1")
self.supports_cli = False
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
- # TODO: Re-enable this test with segwit v1
def test_utxo_conversion(self):
+ self.log.info("Check that non-witness UTXOs are removed for segwit v1+ inputs")
mining_node = self.nodes[2]
offline_node = self.nodes[0]
online_node = self.nodes[1]
@@ -72,36 +80,102 @@ class PSBTTest(BitcoinTestFramework):
# Create watchonly on online_node
online_node.createwallet(wallet_name='wonline', disable_private_keys=True)
wonline = online_node.get_wallet_rpc('wonline')
- w2 = online_node.get_wallet_rpc('')
+ w2 = online_node.get_wallet_rpc(self.default_wallet_name)
# Mine a transaction that credits the offline address
- offline_addr = offline_node.getnewaddress(address_type="p2sh-segwit")
- online_addr = w2.getnewaddress(address_type="p2sh-segwit")
+ offline_addr = offline_node.getnewaddress(address_type="bech32m")
+ online_addr = w2.getnewaddress(address_type="bech32m")
wonline.importaddress(offline_addr, "", False)
- mining_node.sendtoaddress(address=offline_addr, amount=1.0)
- self.generate(mining_node, nblocks=1)
+ mining_wallet = mining_node.get_wallet_rpc(self.default_wallet_name)
+ mining_wallet.sendtoaddress(address=offline_addr, amount=1.0)
+ self.generate(mining_node, nblocks=1, sync_fun=lambda: self.sync_all([online_node, mining_node]))
- # Construct an unsigned PSBT on the online node (who doesn't know the output is Segwit, so will include a non-witness UTXO)
+ # Construct an unsigned PSBT on the online node
utxos = wonline.listunspent(addresses=[offline_addr])
raw = wonline.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:0.9999}])
psbt = wonline.walletprocesspsbt(online_node.converttopsbt(raw))["psbt"]
- assert "non_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0]
+ assert not "not_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0]
+
+ # add non-witness UTXO manually
+ psbt_new = PSBT.from_base64(psbt)
+ prev_tx = wonline.gettransaction(utxos[0]["txid"])["hex"]
+ psbt_new.i[0].map[PSBT_IN_NON_WITNESS_UTXO] = bytes.fromhex(prev_tx)
+ assert "non_witness_utxo" in mining_node.decodepsbt(psbt_new.to_base64())["inputs"][0]
- # Have the offline node sign the PSBT (which will update the UTXO to segwit)
- signed_psbt = offline_node.walletprocesspsbt(psbt)["psbt"]
- assert "witness_utxo" in mining_node.decodepsbt(signed_psbt)["inputs"][0]
+ # Have the offline node sign the PSBT (which will remove the non-witness UTXO)
+ signed_psbt = offline_node.walletprocesspsbt(psbt_new.to_base64())["psbt"]
+ assert not "non_witness_utxo" in mining_node.decodepsbt(signed_psbt)["inputs"][0]
# Make sure we can mine the resulting transaction
txid = mining_node.sendrawtransaction(mining_node.finalizepsbt(signed_psbt)["hex"])
- self.generate(mining_node, 1)
+ self.generate(mining_node, nblocks=1, sync_fun=lambda: self.sync_all([online_node, mining_node]))
assert_equal(online_node.gettxout(txid,0)["confirmations"], 1)
wonline.unloadwallet()
# Reconnect
- self.connect_nodes(0, 1)
+ self.connect_nodes(1, 0)
self.connect_nodes(0, 2)
+ def test_input_confs_control(self):
+ self.nodes[0].createwallet("minconf")
+ wallet = self.nodes[0].get_wallet_rpc("minconf")
+
+ # Fund the wallet with different chain heights
+ for _ in range(2):
+ self.nodes[1].sendmany("", {wallet.getnewaddress():1, wallet.getnewaddress():1})
+ self.generate(self.nodes[1], 1)
+
+ unconfirmed_txid = wallet.sendtoaddress(wallet.getnewaddress(), 0.5)
+
+ self.log.info("Crafting PSBT using an unconfirmed input")
+ target_address = self.nodes[1].getnewaddress()
+ psbtx1 = wallet.walletcreatefundedpsbt([], {target_address: 0.1}, 0, {'fee_rate': 1, 'maxconf': 0})['psbt']
+
+ # Make sure we only had the one input
+ tx1_inputs = self.nodes[0].decodepsbt(psbtx1)['tx']['vin']
+ assert_equal(len(tx1_inputs), 1)
+
+ utxo1 = tx1_inputs[0]
+ assert_equal(unconfirmed_txid, utxo1['txid'])
+
+ signed_tx1 = wallet.walletprocesspsbt(psbtx1)['psbt']
+ final_tx1 = wallet.finalizepsbt(signed_tx1)['hex']
+ txid1 = self.nodes[0].sendrawtransaction(final_tx1)
+
+ mempool = self.nodes[0].getrawmempool()
+ assert txid1 in mempool
+
+ self.log.info("Fail to craft a new PSBT that sends more funds with add_inputs = False")
+ assert_raises_rpc_error(-4, "The preselected coins total amount does not cover the transaction target. Please allow other inputs to be automatically selected or include more coins manually", wallet.walletcreatefundedpsbt, [{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1}, 0, {'add_inputs': False})
+
+ self.log.info("Fail to craft a new PSBT with minconf above highest one")
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, [{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1}, 0, {'add_inputs': True, 'minconf': 3, 'fee_rate': 10})
+
+ self.log.info("Fail to broadcast a new PSBT with maxconf 0 due to BIP125 rules to verify it actually chose unconfirmed outputs")
+ psbt_invalid = wallet.walletcreatefundedpsbt([{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1}, 0, {'add_inputs': True, 'maxconf': 0, 'fee_rate': 10})['psbt']
+ signed_invalid = wallet.walletprocesspsbt(psbt_invalid)['psbt']
+ final_invalid = wallet.finalizepsbt(signed_invalid)['hex']
+ assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, final_invalid)
+
+ self.log.info("Craft a replacement adding inputs with highest confs possible")
+ psbtx2 = wallet.walletcreatefundedpsbt([{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1}, 0, {'add_inputs': True, 'minconf': 2, 'fee_rate': 10})['psbt']
+ tx2_inputs = self.nodes[0].decodepsbt(psbtx2)['tx']['vin']
+ assert_greater_than_or_equal(len(tx2_inputs), 2)
+ for vin in tx2_inputs:
+ if vin['txid'] != unconfirmed_txid:
+ assert_greater_than_or_equal(self.nodes[0].gettxout(vin['txid'], vin['vout'])['confirmations'], 2)
+
+ signed_tx2 = wallet.walletprocesspsbt(psbtx2)['psbt']
+ final_tx2 = wallet.finalizepsbt(signed_tx2)['hex']
+ txid2 = self.nodes[0].sendrawtransaction(final_tx2)
+
+ mempool = self.nodes[0].getrawmempool()
+ assert txid1 not in mempool
+ assert txid2 in mempool
+
+ wallet.unloadwallet()
+
def assert_change_type(self, psbtx, expected_type):
"""Assert that the given PSBT has a change output with the given type."""
@@ -116,7 +190,9 @@ class PSBTTest(BitcoinTestFramework):
# If inputs are specified, do not automatically add more:
utxo1 = self.nodes[0].listunspent()[0]
- assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[0].walletcreatefundedpsbt, [{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():90})
+ assert_raises_rpc_error(-4, "The preselected coins total amount does not cover the transaction target. "
+ "Please allow other inputs to be automatically selected or include more coins manually",
+ self.nodes[0].walletcreatefundedpsbt, [{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():90})
psbtx1 = self.nodes[0].walletcreatefundedpsbt([{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():90}, 0, {"add_inputs": True})['psbt']
assert_equal(len(self.nodes[0].decodepsbt(psbtx1)['tx']['vin']), 2)
@@ -272,7 +348,7 @@ class PSBTTest(BitcoinTestFramework):
self.log.info("- raises RPC error with invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
- assert_raises_rpc_error(-3, "Expected type string for estimate_mode, got {}".format(k),
+ assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string",
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"estimate_mode": v, "conf_target": 0.1, "add_inputs": True})
for mode in ["", "foo", Decimal("3.141592")]:
assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"',
@@ -282,7 +358,7 @@ class PSBTTest(BitcoinTestFramework):
for mode in ["unset", "economical", "conservative"]:
self.log.debug("{}".format(mode))
for k, v in {"string": "", "object": {"foo": "bar"}}.items():
- assert_raises_rpc_error(-3, "Expected type number for conf_target, got {}".format(k),
+ assert_raises_rpc_error(-3, f"JSON value of type {k} for field conf_target is not of expected type number",
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"estimate_mode": mode, "conf_target": v, "add_inputs": True})
for n in [-1, 0, 1009]:
assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees.h
@@ -505,8 +581,10 @@ class PSBTTest(BitcoinTestFramework):
for i, signer in enumerate(signers):
self.nodes[2].unloadwallet("wallet{}".format(i))
- # TODO: Re-enable this for segwit v1
- # self.test_utxo_conversion()
+ if self.options.descriptors:
+ self.test_utxo_conversion()
+
+ self.test_input_confs_control()
# Test that psbts with p2pkh outputs are created properly
p2pkh = self.nodes[0].getnewaddress(address_type='legacy')
@@ -654,7 +732,7 @@ class PSBTTest(BitcoinTestFramework):
ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0]
# An external input without solving data should result in an error
- assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, [ext_utxo], {self.nodes[0].getnewaddress(): 15})
+ assert_raises_rpc_error(-4, "Not solvable pre-selected input COutPoint(%s, %s)" % (ext_utxo["txid"][0:10], ext_utxo["vout"]), wallet.walletcreatefundedpsbt, [ext_utxo], {self.nodes[0].getnewaddress(): 15})
# But funding should work when the solving data is provided
psbt = wallet.walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {"add_inputs": True, "solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"], addr_info["embedded"]["embedded"]["scriptPubKey"]]}})
@@ -779,9 +857,18 @@ class PSBTTest(BitcoinTestFramework):
self.generate(self.nodes[0], 1)
self.nodes[0].importdescriptors([{"desc": descsum_create("tr({})".format(privkey)), "timestamp":"now"}])
- psbt = watchonly.sendall([wallet.getnewaddress()])["psbt"]
+ psbt = watchonly.sendall([wallet.getnewaddress(), addr])["psbt"]
psbt = self.nodes[0].walletprocesspsbt(psbt)["psbt"]
- self.nodes[0].sendrawtransaction(self.nodes[0].finalizepsbt(psbt)["hex"])
+ txid = self.nodes[0].sendrawtransaction(self.nodes[0].finalizepsbt(psbt)["hex"])
+ vout = find_vout_for_address(self.nodes[0], txid, addr)
+
+ # Make sure tap tree is in psbt
+ parsed_psbt = PSBT.from_base64(psbt)
+ assert_greater_than(len(parsed_psbt.o[vout].map[PSBT_OUT_TAP_TREE]), 0)
+ assert "taproot_tree" in self.nodes[0].decodepsbt(psbt)["outputs"][vout]
+ parsed_psbt.make_blank()
+ comb_psbt = self.nodes[0].combinepsbt([psbt, parsed_psbt.to_base64()])
+ assert_equal(comb_psbt, psbt)
self.log.info("Test that walletprocesspsbt both updates and signs a non-updated psbt containing Taproot inputs")
addr = self.nodes[0].getnewaddress("", "bech32m")
@@ -793,6 +880,14 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[0].sendrawtransaction(rawtx)
self.generate(self.nodes[0], 1)
+ # Make sure tap tree is not in psbt
+ parsed_psbt = PSBT.from_base64(psbt)
+ assert PSBT_OUT_TAP_TREE not in parsed_psbt.o[0].map
+ assert "taproot_tree" not in self.nodes[0].decodepsbt(psbt)["outputs"][0]
+ parsed_psbt.make_blank()
+ comb_psbt = self.nodes[0].combinepsbt([psbt, parsed_psbt.to_base64()])
+ assert_equal(comb_psbt, psbt)
+
self.log.info("Test decoding PSBT with per-input preimage types")
# note that the decodepsbt RPC doesn't check whether preimages and hashes match
hash_ripemd160, preimage_ripemd160 = random_bytes(20), random_bytes(50)
@@ -834,6 +929,18 @@ class PSBTTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "PSBTs not compatible (different transactions)", self.nodes[0].combinepsbt, [psbt1, psbt2])
assert_equal(self.nodes[0].combinepsbt([psbt1, psbt1]), psbt1)
+ self.log.info("Test that PSBT inputs are being checked via script execution")
+ acs_prevout = CTxOut(nValue=0, scriptPubKey=CScript([OP_TRUE]))
+ tx = CTransaction()
+ tx.vin = [CTxIn(outpoint=COutPoint(hash=int('dd' * 32, 16), n=0), scriptSig=b"")]
+ tx.vout = [CTxOut(nValue=0, scriptPubKey=b"")]
+ psbt = PSBT()
+ psbt.g = PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()})
+ psbt.i = [PSBTMap({bytes([PSBT_IN_WITNESS_UTXO]) : acs_prevout.serialize()})]
+ psbt.o = [PSBTMap()]
+ assert_equal(self.nodes[0].finalizepsbt(psbt.to_base64()),
+ {'hex': '0200000001dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd0000000000000000000100000000000000000000000000', 'complete': True})
+
if __name__ == '__main__':
PSBTTest().main()
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 930aaaa897..2395935620 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 rawtransaction RPCs.
@@ -14,13 +14,21 @@ Test the following RPCs:
from collections import OrderedDict
from decimal import Decimal
+from itertools import product
-from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
+ COIN,
CTransaction,
+ CTxOut,
tx_from_hex,
)
+from test_framework.script import (
+ CScript,
+ OP_FALSE,
+ OP_INVALIDOPCODE,
+ OP_RETURN,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -54,8 +62,10 @@ class multidict(dict):
class RawTransactionsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=False)
+
def set_test_params(self):
- self.setup_clean_chain = True
self.num_nodes = 3
self.extra_args = [
["-txindex"],
@@ -65,8 +75,6 @@ class RawTransactionsTest(BitcoinTestFramework):
# whitelist all peers to speed up tx relay / mempool sync
for args in self.extra_args:
args.append("-whitelist=noban@127.0.0.1")
- self.requires_wallet = self.is_specified_wallet_compiled()
-
self.supports_cli = False
def setup_network(self):
@@ -75,17 +83,16 @@ class RawTransactionsTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- self.log.info("Prepare some coins for multiple *rawtransaction commands")
- self.generate(self.wallet, 10)
- self.generate(self.nodes[0], COINBASE_MATURITY + 1)
self.getrawtransaction_tests()
+ self.getrawtransaction_verbosity_tests()
self.createrawtransaction_tests()
self.sendrawtransaction_tests()
self.sendrawtransaction_testmempoolaccept_tests()
self.decoderawtransaction_tests()
self.transaction_version_number_tests()
- if self.requires_wallet and not self.options.descriptors:
+ if self.is_specified_wallet_compiled() and not self.options.descriptors:
+ self.import_deterministic_coinbase_privkeys()
self.raw_multisig_transaction_legacy_tests()
def getrawtransaction_tests(self):
@@ -114,6 +121,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# 4. valid parameters - supply txid and 1 for verbose.
# We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], tx['hex'])
+ assert_equal(self.nodes[n].getrawtransaction(txId, 2)["hex"], tx['hex'])
# 5. valid parameters - supply txid and True for non-verbose
assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], tx['hex'])
@@ -124,13 +132,14 @@ class RawTransactionsTest(BitcoinTestFramework):
# 6. invalid parameters - supply txid and invalid boolean values (strings) for verbose
for value in ["True", "False"]:
- assert_raises_rpc_error(-3, "not of expected type bool", self.nodes[n].getrawtransaction, txid=txId, verbose=value)
+ assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txid=txId, verbose=value)
+ assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txid=txId, verbosity=value)
# 7. invalid parameters - supply txid and empty array
- assert_raises_rpc_error(-3, "not of expected type bool", self.nodes[n].getrawtransaction, txId, [])
+ assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txId, [])
# 8. invalid parameters - supply txid and empty dict
- assert_raises_rpc_error(-3, "not of expected type bool", self.nodes[n].getrawtransaction, txId, {})
+ assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txId, {})
# Make a tx by sending, then generate 2 blocks; block1 has the tx in it
tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid']
@@ -143,9 +152,10 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(gottx['in_active_chain'], True)
if n == 0:
self.log.info("Test getrawtransaction with -txindex, without blockhash: 'in_active_chain' should be absent")
- gottx = self.nodes[n].getrawtransaction(txid=tx, verbose=True)
- assert_equal(gottx['txid'], tx)
- assert 'in_active_chain' not in gottx
+ for v in [1,2]:
+ gottx = self.nodes[n].getrawtransaction(txid=tx, verbosity=v)
+ assert_equal(gottx['txid'], tx)
+ assert 'in_active_chain' not in gottx
else:
self.log.info("Test getrawtransaction without -txindex, without blockhash: expect the call to raise")
assert_raises_rpc_error(-5, err_msg, self.nodes[n].getrawtransaction, txid=tx, verbose=True)
@@ -170,6 +180,70 @@ class RawTransactionsTest(BitcoinTestFramework):
block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
assert_raises_rpc_error(-5, "The genesis block coinbase is not considered an ordinary transaction", self.nodes[0].getrawtransaction, block['merkleroot'])
+ def getrawtransaction_verbosity_tests(self):
+ tx = self.wallet.send_self_transfer(from_node=self.nodes[1])['txid']
+ [block1] = self.generate(self.nodes[1], 1)
+ fields = [
+ 'blockhash',
+ 'blocktime',
+ 'confirmations',
+ 'hash',
+ 'hex',
+ 'in_active_chain',
+ 'locktime',
+ 'size',
+ 'time',
+ 'txid',
+ 'vin',
+ 'vout',
+ 'vsize',
+ 'weight',
+ ]
+ prevout_fields = [
+ 'generated',
+ 'height',
+ 'value',
+ 'scriptPubKey',
+ ]
+ script_pub_key_fields = [
+ 'address',
+ 'asm',
+ 'hex',
+ 'type',
+ ]
+ # node 0 & 2 with verbosity 1 & 2
+ for n, v in product([0, 2], [1, 2]):
+ self.log.info(f"Test getrawtransaction_verbosity {v} {'with' if n == 0 else 'without'} -txindex, with blockhash")
+ gottx = self.nodes[n].getrawtransaction(txid=tx, verbosity=v, blockhash=block1)
+ missing_fields = set(fields).difference(gottx.keys())
+ if missing_fields:
+ raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction")
+
+ assert len(gottx['vin']) > 0
+ if v == 1:
+ assert 'fee' not in gottx
+ assert 'prevout' not in gottx['vin'][0]
+ if v == 2:
+ assert isinstance(gottx['fee'], Decimal)
+ assert 'prevout' in gottx['vin'][0]
+ prevout = gottx['vin'][0]['prevout']
+ script_pub_key = prevout['scriptPubKey']
+
+ missing_fields = set(prevout_fields).difference(prevout.keys())
+ if missing_fields:
+ raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction")
+
+ missing_fields = set(script_pub_key_fields).difference(script_pub_key.keys())
+ if missing_fields:
+ raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction")
+
+ # check verbosity 2 without blockhash but with txindex
+ assert 'fee' in self.nodes[0].getrawtransaction(txid=tx, verbosity=2)
+ # check that coinbase has no fee or does not throw any errors for verbosity 2
+ coin_base = self.nodes[1].getblock(block1)['tx'][0]
+ gottx = self.nodes[1].getrawtransaction(txid=coin_base, verbosity=2, blockhash=block1)
+ assert 'fee' not in gottx
+
def createrawtransaction_tests(self):
self.log.info("Test createrawtransaction")
# Test `createrawtransaction` required parameters
@@ -265,6 +339,57 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[2].sendrawtransaction, rawtx)
+ self.log.info("Test sendrawtransaction exceeding, falling short of, and equaling maxburnamount")
+ max_burn_exceeded = "Unspendable output exceeds maximum configured by user (maxburnamount)"
+
+
+ # Test that spendable transaction with default maxburnamount (0) gets sent
+ tx = self.wallet.create_self_transfer()['tx']
+ tx_hex = tx.serialize().hex()
+ self.nodes[2].sendrawtransaction(hexstring=tx_hex)
+
+ # Test that datacarrier transaction with default maxburnamount (0) does not get sent
+ tx = self.wallet.create_self_transfer()['tx']
+ tx_val = 0.001
+ tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
+ tx_hex = tx.serialize().hex()
+ assert_raises_rpc_error(-25, max_burn_exceeded, self.nodes[2].sendrawtransaction, tx_hex)
+
+ # Test that oversized script gets rejected by sendrawtransaction
+ tx = self.wallet.create_self_transfer()['tx']
+ tx_val = 0.001
+ tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_FALSE] * 10001))]
+ tx_hex = tx.serialize().hex()
+ assert_raises_rpc_error(-25, max_burn_exceeded, self.nodes[2].sendrawtransaction, tx_hex)
+
+ # Test that script containing invalid opcode gets rejected by sendrawtransaction
+ tx = self.wallet.create_self_transfer()['tx']
+ tx_val = 0.01
+ tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_INVALIDOPCODE]))]
+ tx_hex = tx.serialize().hex()
+ assert_raises_rpc_error(-25, max_burn_exceeded, self.nodes[2].sendrawtransaction, tx_hex)
+
+ # Test a transaction where our burn exceeds maxburnamount
+ tx = self.wallet.create_self_transfer()['tx']
+ tx_val = 0.001
+ tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
+ tx_hex = tx.serialize().hex()
+ assert_raises_rpc_error(-25, max_burn_exceeded, self.nodes[2].sendrawtransaction, tx_hex, 0, 0.0009)
+
+ # Test a transaction where our burn falls short of maxburnamount
+ tx = self.wallet.create_self_transfer()['tx']
+ tx_val = 0.001
+ tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
+ tx_hex = tx.serialize().hex()
+ self.nodes[2].sendrawtransaction(hexstring=tx_hex, maxfeerate='0', maxburnamount='0.0011')
+
+ # Test a transaction where our burn equals maxburnamount
+ tx = self.wallet.create_self_transfer()['tx']
+ tx_val = 0.001
+ tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
+ tx_hex = tx.serialize().hex()
+ self.nodes[2].sendrawtransaction(hexstring=tx_hex, maxfeerate='0', maxburnamount='0.001')
+
def sendrawtransaction_testmempoolaccept_tests(self):
self.log.info("Test sendrawtransaction/testmempoolaccept with maxfeerate")
fee_exceeds_max = "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"
diff --git a/test/functional/rpc_scanblocks.py b/test/functional/rpc_scanblocks.py
new file mode 100755
index 0000000000..126e95362b
--- /dev/null
+++ b/test/functional/rpc_scanblocks.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021-2022 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 scanblocks RPC call."""
+from test_framework.blockfilter import (
+ bip158_basic_element_hash,
+ bip158_relevant_scriptpubkeys,
+)
+from test_framework.messages import COIN
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+from test_framework.wallet import (
+ MiniWallet,
+ getnewdestination,
+)
+
+
+class ScanblocksTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 2
+ self.extra_args = [["-blockfilterindex=1"], []]
+
+ def run_test(self):
+ node = self.nodes[0]
+ wallet = MiniWallet(node)
+
+ # send 1.0, mempool only
+ _, spk_1, addr_1 = getnewdestination()
+ wallet.send_to(from_node=node, scriptPubKey=spk_1, amount=1 * COIN)
+
+ parent_key = "tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B"
+ # send 1.0, mempool only
+ # childkey 5 of `parent_key`
+ wallet.send_to(from_node=node,
+ scriptPubKey=bytes.fromhex(node.validateaddress("mkS4HXoTYWRTescLGaUTGbtTTYX5EjJyEE")['scriptPubKey']),
+ amount=1 * COIN)
+
+ # mine a block and assure that the mined blockhash is in the filterresult
+ blockhash = self.generate(node, 1)[0]
+ height = node.getblockheader(blockhash)['height']
+ self.wait_until(lambda: all(i["synced"] for i in node.getindexinfo().values()))
+
+ out = node.scanblocks("start", [f"addr({addr_1})"])
+ assert blockhash in out['relevant_blocks']
+ assert_equal(height, out['to_height'])
+ assert_equal(0, out['from_height'])
+
+ # mine another block
+ blockhash_new = self.generate(node, 1)[0]
+ height_new = node.getblockheader(blockhash_new)['height']
+
+ # make sure the blockhash is not in the filter result if we set the start_height
+ # to the just mined block (unlikely to hit a false positive)
+ assert blockhash not in node.scanblocks(
+ "start", [f"addr({addr_1})"], height_new)['relevant_blocks']
+
+ # make sure the blockhash is present when using the first mined block as start_height
+ assert blockhash in node.scanblocks(
+ "start", [f"addr({addr_1})"], height)['relevant_blocks']
+ for v in [False, True]:
+ assert blockhash in node.scanblocks(
+ action="start",
+ scanobjects=[f"addr({addr_1})"],
+ start_height=height,
+ options={"filter_false_positives": v})['relevant_blocks']
+
+ # also test the stop height
+ assert blockhash in node.scanblocks(
+ "start", [f"addr({addr_1})"], height, height)['relevant_blocks']
+
+ # use the stop_height to exclude the relevant block
+ assert blockhash not in node.scanblocks(
+ "start", [f"addr({addr_1})"], 0, height - 1)['relevant_blocks']
+
+ # make sure the blockhash is present when using the first mined block as start_height
+ assert blockhash in node.scanblocks(
+ "start", [{"desc": f"pkh({parent_key}/*)", "range": [0, 100]}], height)['relevant_blocks']
+
+ # check that false-positives are included in the result now; note that
+ # finding a false-positive at runtime would take too long, hence we simply
+ # use a pre-calculated one that collides with the regtest genesis block's
+ # coinbase output and verify that their BIP158 ranged hashes match
+ genesis_blockhash = node.getblockhash(0)
+ genesis_spks = bip158_relevant_scriptpubkeys(node, genesis_blockhash)
+ assert_equal(len(genesis_spks), 1)
+ genesis_coinbase_spk = list(genesis_spks)[0]
+ false_positive_spk = bytes.fromhex("001400000000000000000000000000000000000cadcb")
+
+ genesis_coinbase_hash = bip158_basic_element_hash(genesis_coinbase_spk, 1, genesis_blockhash)
+ false_positive_hash = bip158_basic_element_hash(false_positive_spk, 1, genesis_blockhash)
+ assert_equal(genesis_coinbase_hash, false_positive_hash)
+
+ assert genesis_blockhash in node.scanblocks(
+ "start", [{"desc": f"raw({genesis_coinbase_spk.hex()})"}], 0, 0)['relevant_blocks']
+ assert genesis_blockhash in node.scanblocks(
+ "start", [{"desc": f"raw({false_positive_spk.hex()})"}], 0, 0)['relevant_blocks']
+
+ # check that the filter_false_positives option works
+ assert genesis_blockhash in node.scanblocks(
+ "start", [{"desc": f"raw({genesis_coinbase_spk.hex()})"}], 0, 0, "basic", {"filter_false_positives": True})['relevant_blocks']
+ assert genesis_blockhash not in node.scanblocks(
+ "start", [{"desc": f"raw({false_positive_spk.hex()})"}], 0, 0, "basic", {"filter_false_positives": True})['relevant_blocks']
+
+ # test node with disabled blockfilterindex
+ assert_raises_rpc_error(-1, "Index is not enabled for filtertype basic",
+ self.nodes[1].scanblocks, "start", [f"addr({addr_1})"])
+
+ # test unknown filtertype
+ assert_raises_rpc_error(-5, "Unknown filtertype",
+ node.scanblocks, "start", [f"addr({addr_1})"], 0, 10, "extended")
+
+ # test invalid start_height
+ assert_raises_rpc_error(-1, "Invalid start_height",
+ node.scanblocks, "start", [f"addr({addr_1})"], 100000000)
+
+ # test invalid stop_height
+ assert_raises_rpc_error(-1, "Invalid stop_height",
+ node.scanblocks, "start", [f"addr({addr_1})"], 10, 0)
+ assert_raises_rpc_error(-1, "Invalid stop_height",
+ node.scanblocks, "start", [f"addr({addr_1})"], 10, 100000000)
+
+ # test accessing the status (must be empty)
+ assert_equal(node.scanblocks("status"), None)
+
+ # test aborting the current scan (there is no, must return false)
+ assert_equal(node.scanblocks("abort"), False)
+
+ # test invalid command
+ assert_raises_rpc_error(-8, "Invalid action 'foobar'", node.scanblocks, "foobar")
+
+
+if __name__ == '__main__':
+ ScanblocksTest().main()
diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py
index acb6d3ea4a..507a4f48e5 100755
--- a/test/functional/rpc_scantxoutset.py
+++ b/test/functional/rpc_scantxoutset.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 scantxoutset rpc call."""
@@ -31,7 +31,9 @@ class ScantxoutsetTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
+
+ self.log.info("Test if we find coinbase outputs.")
+ assert_equal(sum(u["coinbase"] for u in self.nodes[0].scantxoutset("start", [self.wallet.get_descriptor()])["unspents"]), 49)
self.log.info("Create UTXOs...")
pubk1, spk_P2SH_SEGWIT, addr_P2SH_SEGWIT = getnewdestination("p2sh-segwit")
diff --git a/test/functional/rpc_signer.py b/test/functional/rpc_signer.py
index de17b2b929..4300190387 100755
--- a/test/functional/rpc_signer.py
+++ b/test/functional/rpc_signer.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 external signer.
diff --git a/test/functional/rpc_signmessagewithprivkey.py b/test/functional/rpc_signmessagewithprivkey.py
index 6635da150f..c5df22157d 100755
--- a/test/functional/rpc_signmessagewithprivkey.py
+++ b/test/functional/rpc_signmessagewithprivkey.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 RPC commands for signing messages with private key."""
diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py
index d04d05962f..60b7ce8d20 100755
--- a/test/functional/rpc_txoutproof.py
+++ b/test/functional/rpc_txoutproof.py
@@ -4,7 +4,6 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test gettxoutproof and verifytxoutproof RPCs."""
-from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import (
CMerkleBlock,
from_hex,
@@ -20,7 +19,6 @@ from test_framework.wallet import MiniWallet
class MerkleBlockTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = True
self.extra_args = [
[],
["-txindex"],
@@ -28,12 +26,9 @@ class MerkleBlockTest(BitcoinTestFramework):
def run_test(self):
miniwallet = MiniWallet(self.nodes[0])
- # Add enough mature utxos to the wallet, so that all txs spend confirmed coins
- self.generate(miniwallet, 5)
- self.generate(self.nodes[0], COINBASE_MATURITY)
chain_height = self.nodes[1].getblockcount()
- assert_equal(chain_height, 105)
+ assert_equal(chain_height, 200)
txid1 = miniwallet.send_self_transfer(from_node=self.nodes[0])['txid']
txid2 = miniwallet.send_self_transfer(from_node=self.nodes[0])['txid']
diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py
index 024e8aec1a..cb99e483ec 100755
--- a/test/functional/rpc_uptime.py
+++ b/test/functional/rpc_uptime.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 RPC call related to the uptime command.
diff --git a/test/functional/rpc_users.py b/test/functional/rpc_users.py
index 1a35a57802..8cc3ec401e 100755
--- a/test/functional/rpc_users.py
+++ b/test/functional/rpc_users.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 multiple RPC users."""
@@ -53,13 +53,13 @@ class HTTPBasicsTest(BitcoinTestFramework):
# Generate RPCAUTH with specified password
self.rt2password = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI="
- p = subprocess.Popen([sys.executable, gen_rpcauth, 'rt2', self.rt2password], stdout=subprocess.PIPE, universal_newlines=True)
+ p = subprocess.Popen([sys.executable, gen_rpcauth, 'rt2', self.rt2password], stdout=subprocess.PIPE, text=True)
lines = p.stdout.read().splitlines()
rpcauth2 = lines[1]
# Generate RPCAUTH without specifying password
self.user = ''.join(SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(10))
- p = subprocess.Popen([sys.executable, gen_rpcauth, self.user], stdout=subprocess.PIPE, universal_newlines=True)
+ p = subprocess.Popen([sys.executable, gen_rpcauth, self.user], stdout=subprocess.PIPE, text=True)
lines = p.stdout.read().splitlines()
rpcauth3 = lines[1]
self.password = lines[3]
diff --git a/test/functional/test-shell.md b/test/functional/test-shell.md
index 78737509cb..80f4e88109 100644
--- a/test/functional/test-shell.md
+++ b/test/functional/test-shell.md
@@ -93,8 +93,10 @@ We now let the first node generate 101 regtest blocks, and direct the coinbase
rewards to a wallet address owned by the mining node.
```
+>>> test.nodes[0].createwallet('default')
+{'name': 'default', 'warning': 'Empty string given as passphrase, wallet will not be encrypted.'}
>>> address = test.nodes[0].getnewaddress()
->>> test.self.generatetoaddress(nodes[0], 101, address)
+>>> test.generatetoaddress(test.nodes[0], 101, address)
['2b98dd0044aae6f1cca7f88a0acf366a4bfe053c7f7b00da3c0d115f03d67efb', ...
```
Since the two nodes are both initialized by default to establish an outbound
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
index 92244b5ed8..959a2a65bd 100644
--- a/test/functional/test_framework/address.py
+++ b/test/functional/test_framework/address.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Encode and decode Bitcoin addresses.
diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py
index c4ffd1fbf6..61f92aeac3 100644
--- a/test/functional/test_framework/authproxy.py
+++ b/test/functional/test_framework/authproxy.py
@@ -78,7 +78,10 @@ class AuthServiceProxy():
passwd = None if self.__url.password is None else self.__url.password.encode('utf8')
authpair = user + b':' + passwd
self.__auth_header = b'Basic ' + base64.b64encode(authpair)
- self.timeout = timeout
+ # clamp the socket timeout, since larger values can cause an
+ # "Invalid argument" exception in Python's HTTP(S) client
+ # library on some operating systems (e.g. OpenBSD, FreeBSD)
+ self.timeout = min(timeout, 2147483)
self._set_conn(connection)
def __getattr__(self, name):
@@ -131,10 +134,12 @@ class AuthServiceProxy():
json.dumps(args or argsn, default=EncodeDecimal, ensure_ascii=self.ensure_ascii),
))
if args and argsn:
- raise ValueError('Cannot handle both named and positional arguments')
+ params = dict(args=args, **argsn)
+ else:
+ params = args or argsn
return {'version': '1.1',
'method': self._service_name,
- 'params': args or argsn,
+ 'params': params,
'id': AuthServiceProxy.__id_count}
def __call__(self, *args, **argsn):
diff --git a/test/functional/test_framework/blockfilter.py b/test/functional/test_framework/blockfilter.py
new file mode 100644
index 0000000000..a30e37ea5b
--- /dev/null
+++ b/test/functional/test_framework/blockfilter.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Helper routines relevant for compact block filters (BIP158).
+"""
+from .siphash import siphash
+
+
+def bip158_basic_element_hash(script_pub_key, N, block_hash):
+ """ Calculates the ranged hash of a filter element as defined in BIP158:
+
+ 'The first step in the filter construction is hashing the variable-sized
+ raw items in the set to the range [0, F), where F = N * M.'
+
+ 'The items are first passed through the pseudorandom function SipHash, which takes a
+ 128-bit key k and a variable-sized byte vector and produces a uniformly random 64-bit
+ output. Implementations of this BIP MUST use the SipHash parameters c = 2 and d = 4.'
+
+ 'The parameter k MUST be set to the first 16 bytes of the hash (in standard
+ little-endian representation) of the block for which the filter is constructed. This
+ ensures the key is deterministic while still varying from block to block.'
+ """
+ M = 784931
+ block_hash_bytes = bytes.fromhex(block_hash)[::-1]
+ k0 = int.from_bytes(block_hash_bytes[0:8], 'little')
+ k1 = int.from_bytes(block_hash_bytes[8:16], 'little')
+ return (siphash(k0, k1, script_pub_key) * (N * M)) >> 64
+
+
+def bip158_relevant_scriptpubkeys(node, block_hash):
+ """ Determines the basic filter relvant scriptPubKeys as defined in BIP158:
+
+ 'A basic filter MUST contain exactly the following items for each transaction in a block:
+ - The previous output script (the script being spent) for each input, except for
+ the coinbase transaction.
+ - The scriptPubKey of each output, aside from all OP_RETURN output scripts.'
+ """
+ spks = set()
+ for tx in node.getblock(blockhash=block_hash, verbosity=3)['tx']:
+ # gather prevout scripts
+ for i in tx['vin']:
+ if 'prevout' in i:
+ spks.add(bytes.fromhex(i['prevout']['scriptPubKey']['hex']))
+ # gather output scripts
+ for o in tx['vout']:
+ if o['scriptPubKey']['type'] != 'nulldata':
+ spks.add(bytes.fromhex(o['scriptPubKey']['hex']))
+ return spks
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 574ea10356..b08cc6a3f9 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Utilities for manipulating blocks and transactions."""
@@ -61,6 +61,7 @@ WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
NORMAL_GBT_REQUEST_PARAMS = {"rules": ["segwit"]}
VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4
+MIN_BLOCKS_TO_KEEP = 288
def create_block(hashprev=None, coinbase=None, ntime=None, *, version=None, tmpl=None, txlist=None):
@@ -120,7 +121,7 @@ def script_BIP34_coinbase_height(height):
return CScript([CScriptNum(height)])
-def create_coinbase(height, pubkey=None, extra_output_script=None, fees=0, nValue=50):
+def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_script=None, fees=0, nValue=50):
"""Create a coinbase transaction.
If pubkey is passed in, the coinbase output will be a P2PK output;
@@ -138,6 +139,8 @@ def create_coinbase(height, pubkey=None, extra_output_script=None, fees=0, nValu
coinbaseoutput.nValue += fees
if pubkey is not None:
coinbaseoutput.scriptPubKey = key_to_p2pk_script(pubkey)
+ elif script_pubkey is not None:
+ coinbaseoutput.scriptPubKey = script_pubkey
else:
coinbaseoutput.scriptPubKey = CScript([OP_TRUE])
coinbase.vout = [coinbaseoutput]
diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py
index 68afc1383d..ad305ce1ef 100644
--- a/test/functional/test_framework/key.py
+++ b/test/functional/test_framework/key.py
@@ -139,7 +139,7 @@ class EllipticCurve:
See https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates - Point Addition (with affine point)"""
x1, y1, z1 = p1
x2, y2, z2 = p2
- assert(z2 == 1)
+ assert z2 == 1
# Adding to the point at infinity is a no-op
if z1 == 0:
return p2
@@ -262,7 +262,7 @@ class ECPubKey():
return self.valid
def get_bytes(self):
- assert(self.valid)
+ assert self.valid
p = SECP256K1.affine(self.p)
if p is None:
return None
@@ -276,7 +276,7 @@ class ECPubKey():
See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the
ECDSA verifier algorithm"""
- assert(self.valid)
+ assert self.valid
# Extract r and s from the DER formatted signature. Return false for
# any DER encoding errors.
@@ -349,7 +349,7 @@ class ECKey():
def set(self, secret, compressed):
"""Construct a private key object with given 32-byte secret and compressed flag."""
- assert(len(secret) == 32)
+ assert len(secret) == 32
secret = int.from_bytes(secret, 'big')
self.valid = (secret > 0 and secret < SECP256K1_ORDER)
if self.valid:
@@ -362,7 +362,7 @@ class ECKey():
def get_bytes(self):
"""Retrieve the 32-byte representation of this key."""
- assert(self.valid)
+ assert self.valid
return self.secret.to_bytes(32, 'big')
@property
@@ -375,7 +375,7 @@ class ECKey():
def get_pubkey(self):
"""Compute an ECPubKey object for this secret key."""
- assert(self.valid)
+ assert self.valid
ret = ECPubKey()
p = SECP256K1.mul([(SECP256K1_G, self.secret)])
ret.p = p
@@ -388,7 +388,7 @@ class ECKey():
See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the
ECDSA signer algorithm."""
- assert(self.valid)
+ assert self.valid
z = int.from_bytes(msg, 'big')
# Note: no RFC6979 by default, but a simple random nonce (some tests rely on distinct transactions for the same operation)
if rfc6979:
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 8a928a1e50..8c6f68cacb 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
-# Copyright (c) 2010-2021 The Bitcoin Core developers
+# Copyright (c) 2010-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Bitcoin test framework primitive and message structures
@@ -1838,3 +1838,25 @@ class msg_cfcheckpt:
def __repr__(self):
return "msg_cfcheckpt(filter_type={:#x}, stop_hash={:x})".format(
self.filter_type, self.stop_hash)
+
+class msg_sendtxrcncl:
+ __slots__ = ("version", "salt")
+ msgtype = b"sendtxrcncl"
+
+ def __init__(self):
+ self.version = 0
+ self.salt = 0
+
+ def deserialize(self, f):
+ self.version = struct.unpack("<I", f.read(4))[0]
+ self.salt = struct.unpack("<Q", f.read(8))[0]
+
+ def serialize(self):
+ r = b""
+ r += struct.pack("<I", self.version)
+ r += struct.pack("<Q", self.salt)
+ return r
+
+ def __repr__(self):
+ return "msg_sendtxrcncl(version=%lu, salt=%lu)" %\
+ (self.version, self.salt)
diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index b64f66e69b..fcea4b2f68 100644
--- a/test/functional/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Linux network utilities.
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index fc72a9ab73..2433e52671 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
-# Copyright (c) 2010-2021 The Bitcoin Core developers
+# Copyright (c) 2010-2022 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 objects for interacting with a bitcoind node over the p2p protocol.
@@ -62,6 +62,7 @@ from test_framework.messages import (
msg_sendaddrv2,
msg_sendcmpct,
msg_sendheaders,
+ msg_sendtxrcncl,
msg_tx,
MSG_TX,
MSG_TYPE_MASK,
@@ -126,6 +127,7 @@ MESSAGEMAP = {
b"sendaddrv2": msg_sendaddrv2,
b"sendcmpct": msg_sendcmpct,
b"sendheaders": msg_sendheaders,
+ b"sendtxrcncl": msg_sendtxrcncl,
b"tx": msg_tx,
b"verack": msg_verack,
b"version": msg_version,
@@ -383,7 +385,7 @@ class P2PInterface(P2PConnection):
self.message_count[msgtype] += 1
self.last_message[msgtype] = message
getattr(self, 'on_' + msgtype)(message)
- except:
+ except Exception:
print("ERROR delivering %s (%s)" % (repr(message), sys.exc_info()[0]))
raise
@@ -421,6 +423,7 @@ class P2PInterface(P2PConnection):
def on_sendaddrv2(self, message): pass
def on_sendcmpct(self, message): pass
def on_sendheaders(self, message): pass
+ def on_sendtxrcncl(self, message): pass
def on_tx(self, message): pass
def on_wtxidrelay(self, message): pass
@@ -446,6 +449,7 @@ class P2PInterface(P2PConnection):
self.send_message(msg_sendaddrv2())
self.send_message(msg_verack())
self.nServices = message.nServices
+ self.relay = message.relay
self.send_message(msg_getaddr())
# Connection helper methods
@@ -460,7 +464,7 @@ class P2PInterface(P2PConnection):
def wait_for_connect(self, timeout=60):
test_function = lambda: self.is_connected
- wait_until_helper(test_function, timeout=timeout, lock=p2p_lock)
+ self.wait_until(test_function, timeout=timeout, check_connected=False)
def wait_for_disconnect(self, timeout=60):
test_function = lambda: not self.is_connected
diff --git a/test/functional/test_framework/psbt.py b/test/functional/test_framework/psbt.py
index 68945e7e84..1eff4a250e 100644
--- a/test/functional/test_framework/psbt.py
+++ b/test/functional/test_framework/psbt.py
@@ -105,8 +105,8 @@ class PSBT:
def deserialize(self, f):
assert f.read(5) == b"psbt\xff"
self.g = from_binary(PSBTMap, f)
- assert 0 in self.g.map
- self.tx = from_binary(CTransaction, self.g.map[0])
+ assert PSBT_GLOBAL_UNSIGNED_TX in self.g.map
+ self.tx = from_binary(CTransaction, self.g.map[PSBT_GLOBAL_UNSIGNED_TX])
self.i = [from_binary(PSBTMap, f) for _ in self.tx.vin]
self.o = [from_binary(PSBTMap, f) for _ in self.tx.vout]
return self
@@ -115,14 +115,23 @@ class PSBT:
assert isinstance(self.g, PSBTMap)
assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
- assert 0 in self.g.map
- tx = from_binary(CTransaction, self.g.map[0])
+ assert PSBT_GLOBAL_UNSIGNED_TX in self.g.map
+ tx = from_binary(CTransaction, self.g.map[PSBT_GLOBAL_UNSIGNED_TX])
assert len(tx.vin) == len(self.i)
assert len(tx.vout) == len(self.o)
psbt = [x.serialize() for x in [self.g] + self.i + self.o]
return b"psbt\xff" + b"".join(psbt)
+ def make_blank(self):
+ """
+ Remove all fields except for PSBT_GLOBAL_UNSIGNED_TX
+ """
+ for m in self.i + self.o:
+ m.map.clear()
+
+ self.g = PSBTMap(map={PSBT_GLOBAL_UNSIGNED_TX: self.g.map[PSBT_GLOBAL_UNSIGNED_TX]})
+
def to_base64(self):
return base64.b64encode(self.serialize()).decode("utf8")
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 2b70eab4e4..443cae86a1 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Functionality to build scripts, as well as signature hash functions.
@@ -12,7 +12,7 @@ import struct
import unittest
from typing import List, Dict
-from .key import TaggedHash, tweak_add_pubkey
+from .key import TaggedHash, tweak_add_pubkey, compute_xonly_pubkey
from .messages import (
CTransaction,
@@ -597,6 +597,13 @@ class CScript(bytes):
lastOpcode = opcode
return n
+ def IsWitnessProgram(self):
+ """A witness program is any valid CScript that consists of a 1-byte
+ push opcode followed by a data push between 2 and 40 bytes."""
+ return ((4 <= len(self) <= 42) and
+ (self[0] == OP_0 or (OP_1 <= self[0] <= OP_16)) and
+ (self[1] + 2 == len(self)))
+
SIGHASH_DEFAULT = 0 # Taproot-only default, semantics same as SIGHASH_ALL
SIGHASH_ALL = 1
@@ -824,10 +831,10 @@ def taproot_tree_helper(scripts):
if len(scripts) == 1:
# One entry: treat as a leaf
script = scripts[0]
- assert(not callable(script))
+ assert not callable(script)
if isinstance(script, list):
return taproot_tree_helper(script)
- assert(isinstance(script, tuple))
+ assert isinstance(script, tuple)
version = LEAF_VERSION_TAPSCRIPT
name = script[0]
code = script[1]
@@ -872,7 +879,7 @@ TaprootInfo = namedtuple("TaprootInfo", "scriptPubKey,internal_pubkey,negflag,tw
# - merklebranch: the merkle branch to use for this leaf (32*N bytes)
TaprootLeafInfo = namedtuple("TaprootLeafInfo", "script,version,merklebranch,leaf_hash")
-def taproot_construct(pubkey, scripts=None):
+def taproot_construct(pubkey, scripts=None, treat_internal_as_infinity=False):
"""Construct a tree of Taproot spending conditions
pubkey: a 32-byte xonly pubkey for the internal pubkey (bytes)
@@ -891,7 +898,10 @@ def taproot_construct(pubkey, scripts=None):
ret, h = taproot_tree_helper(scripts)
tweak = TaggedHash("TapTweak", pubkey + h)
- tweaked, negated = tweak_add_pubkey(pubkey, tweak)
+ if treat_internal_as_infinity:
+ tweaked, negated = compute_xonly_pubkey(tweak)
+ else:
+ tweaked, negated = tweak_add_pubkey(pubkey, tweak)
leaves = dict((name, TaprootLeafInfo(script, version, merklebranch, leaf)) for name, version, script, merklebranch, leaf in ret)
return TaprootInfo(CScript([OP_1, tweaked]), pubkey, negated + 0, tweak, leaves, h, tweaked)
diff --git a/test/functional/test_framework/script_util.py b/test/functional/test_framework/script_util.py
index b114002145..62894cc0f4 100755
--- a/test/functional/test_framework/script_util.py
+++ b/test/functional/test_framework/script_util.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Useful Script constants and utils."""
@@ -13,12 +13,13 @@ from test_framework.script import (
OP_EQUAL,
OP_EQUALVERIFY,
OP_HASH160,
+ OP_RETURN,
hash160,
sha256,
)
# To prevent a "tx-size-small" policy rule error, a transaction has to have a
-# non-witness size of at least 82 bytes (MIN_STANDARD_TX_NONWITNESS_SIZE in
+# non-witness size of at least 65 bytes (MIN_STANDARD_TX_NONWITNESS_SIZE in
# src/policy/policy.h). Considering a Tx with the smallest possible single
# input (blank, empty scriptSig), and with an output omitting the scriptPubKey,
# we get to a minimum size of 60 bytes:
@@ -28,15 +29,15 @@ from test_framework.script import (
# Output: 8 [Amount] + 1 [scriptPubKeyLen] = 9 bytes
#
# Hence, the scriptPubKey of the single output has to have a size of at
-# least 22 bytes, which corresponds to the size of a P2WPKH scriptPubKey.
-# The following script constant consists of a single push of 21 bytes of 'a':
-# <PUSH_21> <21-bytes of 'a'>
-# resulting in a 22-byte size. It should be used whenever (small) fake
-# scriptPubKeys are needed, to guarantee that the minimum transaction size is
-# met.
-DUMMY_P2WPKH_SCRIPT = CScript([b'a' * 21])
-DUMMY_2_P2WPKH_SCRIPT = CScript([b'b' * 21])
-
+# least 5 bytes.
+MIN_STANDARD_TX_NONWITNESS_SIZE = 65
+MIN_PADDING = MIN_STANDARD_TX_NONWITNESS_SIZE - 10 - 41 - 9
+assert MIN_PADDING == 5
+
+# This script cannot be spent, allowing dust output values under
+# standardness checks
+DUMMY_MIN_OP_RETURN_SCRIPT = CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 1)))
+assert len(DUMMY_MIN_OP_RETURN_SCRIPT) == MIN_PADDING
def key_to_p2pk_script(key):
key = check_key(key)
diff --git a/test/functional/test_framework/siphash.py b/test/functional/test_framework/siphash.py
index 85836845d4..884dbcab46 100644
--- a/test/functional/test_framework/siphash.py
+++ b/test/functional/test_framework/siphash.py
@@ -1,15 +1,17 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Specialized SipHash-2-4 implementations.
+"""SipHash-2-4 implementation.
-This implements SipHash-2-4 for 256-bit integers.
+This implements SipHash-2-4. For convenience, an interface taking 256-bit
+integers is provided in addition to the one accepting generic data.
"""
def rotl64(n, b):
return n >> (64 - b) | (n & ((1 << (64 - b)) - 1)) << b
+
def siphash_round(v0, v1, v2, v3):
v0 = (v0 + v1) & ((1 << 64) - 1)
v1 = rotl64(v1, 13)
@@ -27,37 +29,37 @@ def siphash_round(v0, v1, v2, v3):
v2 = rotl64(v2, 32)
return (v0, v1, v2, v3)
-def siphash256(k0, k1, h):
- n0 = h & ((1 << 64) - 1)
- n1 = (h >> 64) & ((1 << 64) - 1)
- n2 = (h >> 128) & ((1 << 64) - 1)
- n3 = (h >> 192) & ((1 << 64) - 1)
+
+def siphash(k0, k1, data):
+ assert type(data) == bytes
v0 = 0x736f6d6570736575 ^ k0
v1 = 0x646f72616e646f6d ^ k1
v2 = 0x6c7967656e657261 ^ k0
- v3 = 0x7465646279746573 ^ k1 ^ n0
- v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
- v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
- v0 ^= n0
- v3 ^= n1
- v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
- v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
- v0 ^= n1
- v3 ^= n2
+ v3 = 0x7465646279746573 ^ k1
+ c = 0
+ t = 0
+ for d in data:
+ t |= d << (8 * (c % 8))
+ c = (c + 1) & 0xff
+ if (c & 7) == 0:
+ v3 ^= t
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0 ^= t
+ t = 0
+ t = t | (c << 56)
+ v3 ^= t
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
- v0 ^= n2
- v3 ^= n3
- v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
- v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
- v0 ^= n3
- v3 ^= 0x2000000000000000
- v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
- v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
- v0 ^= 0x2000000000000000
- v2 ^= 0xFF
+ v0 ^= t
+ v2 ^= 0xff
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
return v0 ^ v1 ^ v2 ^ v3
+
+
+def siphash256(k0, k1, num):
+ assert type(num) == int
+ return siphash(k0, k1, num.to_bytes(32, 'little'))
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index b1164b98fd..66a23b443c 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Base class for RPC testing."""
@@ -97,6 +97,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.chain: str = 'regtest'
self.setup_clean_chain: bool = False
self.nodes: List[TestNode] = []
+ self.extra_args = None
self.network_thread = None
self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond
self.supports_cli = True
@@ -113,14 +114,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.wallet_names = None
# By default the wallet is not required. Set to true by skip_if_no_wallet().
# When False, we ignore wallet_names regardless of what it is.
- self.requires_wallet = False
+ self._requires_wallet = False
# Disable ThreadOpenConnections by default, so that adding entries to
# addrman will not result in automatic connections to them.
self.disable_autoconnect = True
self.set_test_params()
assert self.wallet_names is None or len(self.wallet_names) <= self.num_nodes
- if self.options.timeout_factor == 0 :
- self.options.timeout_factor = 99999
self.rpc_timeout = int(self.rpc_timeout * self.options.timeout_factor) # optionally, increase timeout by a factor
def main(self):
@@ -192,13 +191,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown. valgrind 3.14 or later required. Forces --nosandbox.")
parser.add_argument("--randomseed", type=int,
help="set a random seed for deterministically reproducing a previous test run")
- parser.add_argument('--timeout-factor', dest="timeout_factor", type=float, default=1.0, help='adjust test timeouts by a factor. Setting it to 0 disables all timeouts')
-
- group = parser.add_mutually_exclusive_group()
- group.add_argument("--descriptors", action='store_const', const=True,
- help="Run test using a descriptor wallet", dest='descriptors')
- group.add_argument("--legacy-wallet", action='store_const', const=False,
- help="Run test using legacy wallets", dest='descriptors')
+ parser.add_argument("--timeout-factor", dest="timeout_factor", type=float, help="adjust test timeouts by a factor. Setting it to 0 disables all timeouts")
self.add_options(parser)
# Running TestShell in a Jupyter notebook causes an additional -f argument
@@ -206,21 +199,31 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# source: https://stackoverflow.com/questions/48796169/how-to-fix-ipykernel-launcher-py-error-unrecognized-arguments-in-jupyter/56349168#56349168
parser.add_argument("-f", "--fff", help="a dummy argument to fool ipython", default="1")
self.options = parser.parse_args()
+ if self.options.timeout_factor == 0:
+ self.options.timeout_factor = 99999
+ self.options.timeout_factor = self.options.timeout_factor or (4 if self.options.valgrind else 1)
self.options.previous_releases_path = previous_releases_path
config = configparser.ConfigParser()
config.read_file(open(self.options.configfile))
self.config = config
- if self.options.descriptors is None:
- # Prefer BDB unless it isn't available
- if self.is_bdb_compiled():
- self.options.descriptors = False
- elif self.is_sqlite_compiled():
+ if "descriptors" not in self.options:
+ # Wallet is not required by the test at all and the value of self.options.descriptors won't matter.
+ # It still needs to exist and be None in order for tests to work however.
+ # So set it to None to force -disablewallet, because the wallet is not needed.
+ self.options.descriptors = None
+ elif self.options.descriptors is None:
+ # Some wallet is either required or optionally used by the test.
+ # Prefer SQLite unless it isn't available
+ if self.is_sqlite_compiled():
self.options.descriptors = True
+ elif self.is_bdb_compiled():
+ self.options.descriptors = False
else:
# If neither are compiled, tests requiring a wallet will be skipped and the value of self.options.descriptors won't matter
# It still needs to exist and be None in order for tests to work however.
+ # So set it to None, which will also set -disablewallet.
self.options.descriptors = None
PortSeed.n = self.options.port_seed
@@ -277,10 +280,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
if seed is None:
seed = random.randrange(sys.maxsize)
else:
- self.log.debug("User supplied random seed {}".format(seed))
+ self.log.info("User supplied random seed {}".format(seed))
random.seed(seed)
- self.log.debug("PRNG seed is: {}".format(seed))
+ self.log.info("PRNG seed is: {}".format(seed))
self.log.debug('Setting up network thread')
self.network_thread = NetworkThread()
@@ -407,12 +410,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def setup_nodes(self):
"""Override this method to customize test node setup"""
- extra_args = [[]] * self.num_nodes
- if hasattr(self, "extra_args"):
- extra_args = self.extra_args
- self.add_nodes(self.num_nodes, extra_args)
+ self.add_nodes(self.num_nodes, self.extra_args)
self.start_nodes()
- if self.requires_wallet:
+ if self._requires_wallet:
self.import_deterministic_coinbase_privkeys()
if not self.setup_clean_chain:
for n in self.nodes:
@@ -446,6 +446,21 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# Public helper methods. These can be accessed by the subclass test scripts.
+ def add_wallet_options(self, parser, *, descriptors=True, legacy=True):
+ kwargs = {}
+ if descriptors + legacy == 1:
+ # If only one type can be chosen, set it as default
+ kwargs["default"] = descriptors
+ group = parser.add_mutually_exclusive_group(
+ # If only one type is allowed, require it to be set in test_runner.py
+ required=os.getenv("REQUIRE_WALLET_TYPE_SET") == "1" and "default" in kwargs)
+ if descriptors:
+ group.add_argument("--descriptors", action='store_const', const=True, **kwargs,
+ help="Run test using a descriptor wallet", dest='descriptors')
+ if legacy:
+ group.add_argument("--legacy-wallet", action='store_const', const=False, **kwargs,
+ help="Run test using legacy wallets", dest='descriptors')
+
def add_nodes(self, num_nodes: int, extra_args=None, *, rpchost=None, binary=None, binary_cli=None, versions=None):
"""Instantiate TestNode objects.
@@ -519,11 +534,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.nodes.append(test_node_i)
if not test_node_i.version_is_at_least(170000):
# adjust conf for pre 17
- conf_file = test_node_i.bitcoinconf
- with open(conf_file, 'r', encoding='utf8') as conf:
- conf_data = conf.read()
- with open(conf_file, 'w', encoding='utf8') as conf:
- conf.write(conf_data.replace('[regtest]', ''))
+ test_node_i.replace_in_config([('[regtest]', '')])
def start_node(self, i, *args, **kwargs):
"""Start a bitcoind"""
@@ -547,7 +558,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
node.start(extra_args[i], *args, **kwargs)
for node in self.nodes:
node.wait_for_rpc_connection()
- except:
+ except Exception:
# If one node failed to start, stop the others
self.stop_nodes()
raise
@@ -594,6 +605,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.wait_until(lambda: sum(peer['version'] != 0 for peer in to_connection.getpeerinfo()) == to_num_peers)
self.wait_until(lambda: sum(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo()) == from_num_peers)
self.wait_until(lambda: sum(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in to_connection.getpeerinfo()) == to_num_peers)
+ # The message bytes are counted before processing the message, so make
+ # sure it was fully processed by waiting for a ping.
+ self.wait_until(lambda: sum(peer["bytesrecv_per_msg"].pop("pong", 0) >= 32 for peer in from_connection.getpeerinfo()) == from_num_peers)
+ self.wait_until(lambda: sum(peer["bytesrecv_per_msg"].pop("pong", 0) >= 32 for peer in to_connection.getpeerinfo()) == to_num_peers)
def disconnect_nodes(self, a, b):
def disconnect_nodes_helper(node_a, node_b):
@@ -836,6 +851,13 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
except ImportError:
raise SkipTest("python3-zmq module not available.")
+ def skip_if_no_py_sqlite3(self):
+ """Attempt to import the sqlite3 package and skip the test if the import fails."""
+ try:
+ import sqlite3 # noqa
+ except ImportError:
+ raise SkipTest("sqlite3 module not available.")
+
def skip_if_no_python_bcc(self):
"""Attempt to import the bcc package and skip the tests if the import fails."""
try:
@@ -859,6 +881,11 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
if platform.system() != "Linux":
raise SkipTest("not on a Linux system")
+ def skip_if_platform_not_posix(self):
+ """Skip the running test if we are not on a POSIX platform"""
+ if os.name != 'posix':
+ raise SkipTest("not on a POSIX system")
+
def skip_if_no_bitcoind_zmq(self):
"""Skip the running test if bitcoind has not been compiled with zmq support."""
if not self.is_zmq_compiled():
@@ -866,7 +893,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def skip_if_no_wallet(self):
"""Skip the running test if wallet has not been compiled."""
- self.requires_wallet = True
+ self._requires_wallet = True
if not self.is_wallet_compiled():
raise SkipTest("wallet has not been compiled.")
if self.options.descriptors:
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index e35cae006f..882f82e0f2 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Class for bitcoind node under test"""
@@ -102,8 +102,12 @@ class TestNode():
"-debug",
"-debugexclude=libevent",
"-debugexclude=leveldb",
+ "-debugexclude=rand",
"-uacomment=testnode%d" % i,
]
+ if self.descriptors is None:
+ self.args.append("-disablewallet")
+
if use_valgrind:
default_suppressions_file = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
@@ -333,7 +337,7 @@ class TestNode():
return
self.log.debug("Stopping node")
try:
- # Do not use wait argument when testing older nodes, e.g. in feature_backwards_compatibility.py
+ # Do not use wait argument when testing older nodes, e.g. in wallet_backwards_compatibility.py
if self.version_is_at_least(180000):
self.stop(wait=wait)
else:
@@ -383,6 +387,21 @@ class TestNode():
def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
wait_until_helper(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_factor)
+ def replace_in_config(self, replacements):
+ """
+ Perform replacements in the configuration file.
+ The substitutions are passed as a list of search-replace-tuples, e.g.
+ [("old", "new"), ("foo", "bar"), ...]
+ """
+ with open(self.bitcoinconf, 'r', encoding='utf8') as conf:
+ conf_data = conf.read()
+ for replacement in replacements:
+ assert_equal(len(replacement), 2)
+ old, new = replacement[0], replacement[1]
+ conf_data = conf_data.replace(old, new)
+ with open(self.bitcoinconf, 'w', encoding='utf8') as conf:
+ conf.write(conf_data)
+
@property
def chain_path(self) -> Path:
return Path(self.datadir) / self.chain
@@ -618,12 +637,16 @@ class TestNode():
return p2p_conn
- def add_outbound_p2p_connection(self, p2p_conn, *, p2p_idx, connection_type="outbound-full-relay", **kwargs):
+ def add_outbound_p2p_connection(self, p2p_conn, *, wait_for_verack=True, p2p_idx, connection_type="outbound-full-relay", **kwargs):
"""Add an outbound p2p connection from node. Must be an
"outbound-full-relay", "block-relay-only", "addr-fetch" or "feeler" connection.
This method adds the p2p connection to the self.p2ps list and returns
the connection to the caller.
+
+ p2p_idx must be different for simultaneously connected peers. When reusing it for the next peer
+ after disconnecting the previous one, it is necessary to wait for the disconnect to finish to avoid
+ a race condition.
"""
def addconnection_callback(address, port):
@@ -640,8 +663,9 @@ class TestNode():
p2p_conn.wait_for_connect()
self.p2ps.append(p2p_conn)
- p2p_conn.wait_for_verack()
- p2p_conn.sync_with_ping()
+ if wait_for_verack:
+ p2p_conn.wait_for_verack()
+ p2p_conn.sync_with_ping()
return p2p_conn
@@ -650,7 +674,8 @@ class TestNode():
return len([peer for peer in self.getpeerinfo() if peer['subver'] == P2P_SUBVERSION])
def disconnect_p2ps(self):
- """Close all p2p connections to the node."""
+ """Close all p2p connections to the node.
+ Use only after each p2p has sent a version message to ensure the wait works."""
for p in self.p2ps:
p.peer_disconnect()
del self.p2ps[:]
@@ -713,7 +738,6 @@ class TestNodeCLI():
"""Run bitcoin-cli command. Deserializes returned string as python object."""
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:
p_args += ["-named"]
@@ -721,7 +745,7 @@ class TestNodeCLI():
p_args += [command]
p_args += pos_args + named_args
self.log.debug("Running bitcoin-cli {}".format(p_args[2:]))
- process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+ process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
cli_stdout, cli_stderr = process.communicate(input=self.input)
returncode = process.poll()
if returncode:
@@ -805,7 +829,7 @@ class RPCOverloadWrapper():
int(address ,16)
is_hex = True
desc = descsum_create('raw(' + address + ')')
- except:
+ except Exception:
desc = descsum_create('addr(' + address + ')')
reqs = [{
'desc': desc,
diff --git a/test/functional/test_framework/test_shell.py b/test/functional/test_framework/test_shell.py
index 26df128f1f..09ccec28a1 100644
--- a/test/functional/test_framework/test_shell.py
+++ b/test/functional/test_framework/test_shell.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,6 +16,9 @@ class TestShell:
start a single TestShell at a time."""
class __TestShell(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
pass
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index bfc835f272..9048a915b2 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Helpful routines for regression testing."""
@@ -488,28 +488,6 @@ def find_output(node, txid, amount, *, blockhash=None):
raise RuntimeError("find_output txid %s : %s not found" % (txid, str(amount)))
-def chain_transaction(node, parent_txids, vouts, value, fee, num_outputs):
- """Build and send a transaction that spends the given inputs (specified
- by lists of parent_txid:vout each), with the desired total value and fee,
- equally divided up to the desired number of outputs.
-
- Returns a tuple with the txid and the amount sent per output.
- """
- send_value = satoshi_round((value - fee)/num_outputs)
- inputs = []
- for (txid, vout) in zip(parent_txids, vouts):
- inputs.append({'txid' : txid, 'vout' : vout})
- outputs = {}
- for _ in range(num_outputs):
- outputs[node.getnewaddress()] = send_value
- rawtx = node.createrawtransaction(inputs, outputs, 0, True)
- signedtx = node.signrawtransactionwithwallet(rawtx)
- txid = node.sendrawtransaction(signedtx['hex'])
- fulltx = node.getrawtransaction(txid, 1)
- assert len(fulltx['vout']) == num_outputs # make sure we didn't generate a change output
- return (txid, send_value)
-
-
# Create large OP_RETURN txouts that can be appended to a transaction
# to make it large (helper for constructing large transactions). The
# total serialized size of the txouts is about 66k vbytes.
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 374fda5c23..f3253630c4 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""A limited-functionality wallet, which may replace a real wallet in tests"""
@@ -32,7 +32,6 @@ from test_framework.messages import (
CTxIn,
CTxInWitness,
CTxOut,
- tx_from_hex,
)
from test_framework.script import (
CScript,
@@ -56,6 +55,7 @@ from test_framework.util import (
assert_equal,
assert_greater_than_or_equal,
)
+from test_framework.blocktools import COINBASE_MATURITY
DEFAULT_FEE = Decimal("0.0001")
@@ -101,8 +101,15 @@ class MiniWallet:
self._address, self._internal_key = create_deterministic_address_bcrt1_p2tr_op_true()
self._scriptPubKey = bytes.fromhex(self._test_node.validateaddress(self._address)['scriptPubKey'])
- def _create_utxo(self, *, txid, vout, value, height):
- return {"txid": txid, "vout": vout, "value": value, "height": height}
+ # When the pre-mined test framework chain is used, it contains coinbase
+ # outputs to the MiniWallet's default address in blocks 76-100
+ # (see method BitcoinTestFramework._initialize_chain())
+ # The MiniWallet needs to rescan_utxos() in order to account
+ # for those mature UTXOs, so that all txs spend confirmed coins
+ self.rescan_utxos()
+
+ def _create_utxo(self, *, txid, vout, value, height, coinbase, confirmations):
+ return {"txid": txid, "vout": vout, "value": value, "height": height, "coinbase": coinbase, "confirmations": confirmations}
def _bulk_tx(self, tx, target_weight):
"""Pad a transaction with extra outputs until it reaches a target weight (or higher).
@@ -119,13 +126,25 @@ class MiniWallet:
def get_balance(self):
return sum(u['value'] for u in self._utxos)
- def rescan_utxos(self):
+ def rescan_utxos(self, *, include_mempool=True):
"""Drop all utxos and rescan the utxo set"""
self._utxos = []
res = self._test_node.scantxoutset(action="start", scanobjects=[self.get_descriptor()])
assert_equal(True, res['success'])
for utxo in res['unspents']:
- self._utxos.append(self._create_utxo(txid=utxo["txid"], vout=utxo["vout"], value=utxo["amount"], height=utxo["height"]))
+ self._utxos.append(
+ self._create_utxo(txid=utxo["txid"],
+ vout=utxo["vout"],
+ value=utxo["amount"],
+ height=utxo["height"],
+ coinbase=utxo["coinbase"],
+ confirmations=res["height"] - utxo["height"] + 1))
+ if include_mempool:
+ mempool = self._test_node.getrawmempool(verbose=True)
+ # Sort tx by ancestor count. See BlockAssembler::SortForBlock in src/node/miner.cpp
+ sorted_mempool = sorted(mempool.items(), key=lambda item: (item[1]["ancestorcount"], int(item[0], 16)))
+ for txid, _ in sorted_mempool:
+ self.scan_tx(self._test_node.getrawtransaction(txid=txid, verbose=True))
def scan_tx(self, tx):
"""Scan the tx and adjust the internal list of owned utxos"""
@@ -140,23 +159,35 @@ class MiniWallet:
pass
for out in tx['vout']:
if out['scriptPubKey']['hex'] == self._scriptPubKey.hex():
- self._utxos.append(self._create_utxo(txid=tx["txid"], vout=out["n"], value=out["value"], height=0))
+ self._utxos.append(self._create_utxo(txid=tx["txid"], vout=out["n"], value=out["value"], height=0, coinbase=False, confirmations=0))
+
+ def scan_txs(self, txs):
+ for tx in txs:
+ self.scan_tx(tx)
def sign_tx(self, tx, fixed_length=True):
- """Sign tx that has been created by MiniWallet in P2PK mode"""
- assert_equal(self._mode, MiniWalletMode.RAW_P2PK)
- (sighash, err) = LegacySignatureHash(CScript(self._scriptPubKey), tx, 0, SIGHASH_ALL)
- assert err is None
- # for exact fee calculation, create only signatures with fixed size by default (>49.89% probability):
- # 65 bytes: high-R val (33 bytes) + low-S val (32 bytes)
- # with the DER header/skeleton data of 6 bytes added, this leads to a target size of 71 bytes
- der_sig = b''
- while not len(der_sig) == 71:
- der_sig = self._priv_key.sign_ecdsa(sighash)
- if not fixed_length:
- break
- tx.vin[0].scriptSig = CScript([der_sig + bytes(bytearray([SIGHASH_ALL]))])
- tx.rehash()
+ if self._mode == MiniWalletMode.RAW_P2PK:
+ (sighash, err) = LegacySignatureHash(CScript(self._scriptPubKey), tx, 0, SIGHASH_ALL)
+ assert err is None
+ # for exact fee calculation, create only signatures with fixed size by default (>49.89% probability):
+ # 65 bytes: high-R val (33 bytes) + low-S val (32 bytes)
+ # with the DER header/skeleton data of 6 bytes added, this leads to a target size of 71 bytes
+ der_sig = b''
+ while not len(der_sig) == 71:
+ der_sig = self._priv_key.sign_ecdsa(sighash)
+ if not fixed_length:
+ break
+ tx.vin[0].scriptSig = CScript([der_sig + bytes(bytearray([SIGHASH_ALL]))])
+ tx.rehash()
+ elif self._mode == MiniWalletMode.RAW_OP_TRUE:
+ for i in tx.vin:
+ i.scriptSig = CScript([OP_NOP] * 43) # pad to identical size
+ elif self._mode == MiniWalletMode.ADDRESS_OP_TRUE:
+ tx.wit.vtxinwit = [CTxInWitness()] * len(tx.vin)
+ for i in tx.wit.vtxinwit:
+ i.scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key]
+ else:
+ assert False
def generate(self, num_blocks, **kwargs):
"""Generate blocks with coinbase outputs to the internal address, and call rescan_utxos"""
@@ -201,9 +232,13 @@ class MiniWallet:
else:
return self._utxos[index]
- def get_utxos(self, *, mark_as_spent=True):
+ def get_utxos(self, *, include_immature_coinbase=False, mark_as_spent=True):
"""Returns the list of all utxos and optionally mark them as spent"""
- utxos = deepcopy(self._utxos)
+ if not include_immature_coinbase:
+ utxo_filter = filter(lambda utxo: not utxo['coinbase'] or COINBASE_MATURITY <= utxo['confirmations'], self._utxos)
+ else:
+ utxo_filter = self._utxos
+ utxos = deepcopy(list(utxo_filter))
if mark_as_spent:
self._utxos = []
return utxos
@@ -245,6 +280,7 @@ class MiniWallet:
utxos_to_spend: Optional[List[dict]] = None,
num_outputs=1,
amount_per_output=0,
+ locktime=0,
sequence=0,
fee_per_output=1000,
target_weight=0
@@ -257,27 +293,22 @@ class MiniWallet:
utxos_to_spend = utxos_to_spend or [self.get_utxo()]
sequence = [sequence] * len(utxos_to_spend) if type(sequence) is int else sequence
assert_equal(len(utxos_to_spend), len(sequence))
- # create simple tx template (1 input, 1 output)
- tx = self.create_self_transfer(
- fee_rate=0,
- utxo_to_spend=utxos_to_spend[0])["tx"]
-
- # duplicate inputs, witnesses and outputs
- tx.vin = [deepcopy(tx.vin[0]) for _ in range(len(utxos_to_spend))]
- for txin, seq in zip(tx.vin, sequence):
- txin.nSequence = seq
- tx.wit.vtxinwit = [deepcopy(tx.wit.vtxinwit[0]) for _ in range(len(utxos_to_spend))]
- tx.vout = [deepcopy(tx.vout[0]) for _ in range(num_outputs)]
-
- # adapt input prevouts
- for i, utxo in enumerate(utxos_to_spend):
- tx.vin[i] = CTxIn(COutPoint(int(utxo['txid'], 16), utxo['vout']))
-
- # adapt output amounts (use fixed fee per output)
+
+ # calculate output amount
inputs_value_total = sum([int(COIN * utxo['value']) for utxo in utxos_to_spend])
outputs_value_total = inputs_value_total - fee_per_output * num_outputs
- for o in tx.vout:
- o.nValue = amount_per_output or (outputs_value_total // num_outputs)
+ amount_per_output = amount_per_output or (outputs_value_total // num_outputs)
+ assert amount_per_output > 0
+ outputs_value_total = amount_per_output * num_outputs
+ fee = Decimal(inputs_value_total - outputs_value_total) / COIN
+
+ # create tx
+ tx = CTransaction()
+ tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=seq) for utxo_to_spend, seq in zip(utxos_to_spend, sequence)]
+ tx.vout = [CTxOut(amount_per_output, bytearray(self._scriptPubKey)) for _ in range(num_outputs)]
+ tx.nLockTime = locktime
+
+ self.sign_tx(tx)
if target_weight:
self._bulk_tx(tx, target_weight)
@@ -289,8 +320,12 @@ class MiniWallet:
vout=i,
value=Decimal(tx.vout[i].nValue) / COIN,
height=0,
+ coinbase=False,
+ confirmations=0,
) for i in range(len(tx.vout))],
+ "fee": fee,
"txid": txid,
+ "wtxid": tx.getwtxid(),
"hex": tx.serialize().hex(),
"tx": tx,
}
@@ -300,6 +335,7 @@ class MiniWallet:
utxo_to_spend = utxo_to_spend or self.get_utxo()
assert fee_rate >= 0
assert fee >= 0
+ # calculate fee
if self._mode in (MiniWalletMode.RAW_OP_TRUE, MiniWalletMode.ADDRESS_OP_TRUE):
vsize = Decimal(104) # anyone-can-spend
elif self._mode == MiniWalletMode.RAW_P2PK:
@@ -307,47 +343,45 @@ class MiniWallet:
else:
assert False
send_value = utxo_to_spend["value"] - (fee or (fee_rate * vsize / 1000))
- assert send_value > 0
-
- tx = CTransaction()
- tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=sequence)]
- tx.vout = [CTxOut(int(COIN * send_value), bytearray(self._scriptPubKey))]
- tx.nLockTime = locktime
- if self._mode == MiniWalletMode.RAW_P2PK:
- self.sign_tx(tx)
- elif self._mode == MiniWalletMode.RAW_OP_TRUE:
- tx.vin[0].scriptSig = CScript([OP_NOP] * 43) # pad to identical size
- elif self._mode == MiniWalletMode.ADDRESS_OP_TRUE:
- tx.wit.vtxinwit = [CTxInWitness()]
- tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key]
- else:
- assert False
- assert_equal(tx.get_vsize(), vsize)
+ # create tx
+ tx = self.create_self_transfer_multi(utxos_to_spend=[utxo_to_spend], locktime=locktime, sequence=sequence, amount_per_output=int(COIN * send_value), target_weight=target_weight)
+ if not target_weight:
+ assert_equal(tx["tx"].get_vsize(), vsize)
+ tx["new_utxo"] = tx.pop("new_utxos")[0]
- if target_weight:
- self._bulk_tx(tx, target_weight)
-
- tx_hex = tx.serialize().hex()
- new_utxo = self._create_utxo(txid=tx.rehash(), vout=0, value=send_value, height=0)
-
- return {"txid": new_utxo["txid"], "wtxid": tx.getwtxid(), "hex": tx_hex, "tx": tx, "new_utxo": new_utxo}
+ return tx
def sendrawtransaction(self, *, from_node, tx_hex, maxfeerate=0, **kwargs):
txid = from_node.sendrawtransaction(hexstring=tx_hex, maxfeerate=maxfeerate, **kwargs)
self.scan_tx(from_node.decoderawtransaction(tx_hex))
return txid
- def send_self_transfer_chain(self, *, from_node, chain_length, utxo_to_spend=None):
- """Create and send a "chain" of chain_length transactions. The nth transaction in
+ def create_self_transfer_chain(self, *, chain_length, utxo_to_spend=None):
+ """
+ Create a "chain" of chain_length transactions. The nth transaction in
the chain is a child of the n-1th transaction and parent of the n+1th transaction.
-
- Returns the chaintip (nth) utxo
"""
chaintip_utxo = utxo_to_spend or self.get_utxo()
+ chain = []
+
for _ in range(chain_length):
- chaintip_utxo = self.send_self_transfer(utxo_to_spend=chaintip_utxo, from_node=from_node)["new_utxo"]
- return chaintip_utxo
+ tx = self.create_self_transfer(utxo_to_spend=chaintip_utxo)
+ chaintip_utxo = tx["new_utxo"]
+ chain.append(tx)
+
+ return chain
+
+ def send_self_transfer_chain(self, *, from_node, **kwargs):
+ """Create and send a "chain" of chain_length transactions. The nth transaction in
+ the chain is a child of the n-1th transaction and parent of the n+1th transaction.
+
+ Returns a list of objects for each tx (see create_self_transfer_multi).
+ """
+ chain = self.create_self_transfer_chain(**kwargs)
+ for t in chain:
+ self.sendrawtransaction(from_node=from_node, tx_hex=t["hex"])
+ return chain
def getnewdestination(address_type='bech32m'):
@@ -388,56 +422,3 @@ def address_to_scriptpubkey(address):
# TODO: also support other address formats
else:
assert False
-
-
-def make_chain(node, address, privkeys, parent_txid, parent_value, n=0, parent_locking_script=None, fee=DEFAULT_FEE):
- """Build a transaction that spends parent_txid.vout[n] and produces one output with
- amount = parent_value with a fee deducted.
- Return tuple (CTransaction object, raw hex, nValue, scriptPubKey of the output created).
- """
- inputs = [{"txid": parent_txid, "vout": n}]
- my_value = parent_value - fee
- outputs = {address : my_value}
- rawtx = node.createrawtransaction(inputs, outputs)
- prevtxs = [{
- "txid": parent_txid,
- "vout": n,
- "scriptPubKey": parent_locking_script,
- "amount": parent_value,
- }] if parent_locking_script else None
- signedtx = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=privkeys, prevtxs=prevtxs)
- assert signedtx["complete"]
- tx = tx_from_hex(signedtx["hex"])
- return (tx, signedtx["hex"], my_value, tx.vout[0].scriptPubKey.hex())
-
-def create_child_with_parents(node, address, privkeys, parents_tx, values, locking_scripts, fee=DEFAULT_FEE):
- """Creates a transaction that spends the first output of each parent in parents_tx."""
- num_parents = len(parents_tx)
- total_value = sum(values)
- inputs = [{"txid": tx.rehash(), "vout": 0} for tx in parents_tx]
- outputs = {address : total_value - fee}
- rawtx_child = node.createrawtransaction(inputs, outputs)
- prevtxs = []
- for i in range(num_parents):
- prevtxs.append({"txid": parents_tx[i].rehash(), "vout": 0, "scriptPubKey": locking_scripts[i], "amount": values[i]})
- signedtx_child = node.signrawtransactionwithkey(hexstring=rawtx_child, privkeys=privkeys, prevtxs=prevtxs)
- assert signedtx_child["complete"]
- return signedtx_child["hex"]
-
-def create_raw_chain(node, first_coin, address, privkeys, chain_length=25):
- """Helper function: create a "chain" of chain_length transactions. The nth transaction in the
- chain is a child of the n-1th transaction and parent of the n+1th transaction.
- """
- parent_locking_script = None
- txid = first_coin["txid"]
- chain_hex = []
- chain_txns = []
- value = first_coin["amount"]
-
- for _ in range(chain_length):
- (tx, txhex, value, parent_locking_script) = make_chain(node, address, privkeys, txid, value, 0, parent_locking_script)
- txid = tx.rehash()
- chain_hex.append(txhex)
- chain_txns.append(tx)
-
- return (chain_hex, chain_txns)
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index d78c1c634f..f8869ae6bc 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Run regression test suite.
@@ -27,6 +27,8 @@ import re
import logging
import unittest
+os.environ["REQUIRE_WALLET_TYPE_SET"] = "1"
+
# Formatting. Default colors to empty strings.
DEFAULT, BOLD, GREEN, RED = ("", ""), ("", ""), ("", ""), ("", "")
try:
@@ -83,60 +85,87 @@ EXTENDED_SCRIPTS = [
'feature_pruning.py',
'feature_dbcrash.py',
'feature_index_prune.py',
+ 'wallet_pruning.py --legacy-wallet',
]
BASE_SCRIPTS = [
# Scripts that are run by default.
# Longest test should go first, to favor running tests in parallel
- 'wallet_hd.py --legacy-wallet',
- 'wallet_hd.py --descriptors',
- 'wallet_backup.py --legacy-wallet',
- 'wallet_backup.py --descriptors',
# vv Tests less than 5m vv
+ 'feature_fee_estimation.py',
+ 'feature_taproot.py',
+ 'feature_block.py',
+ # vv Tests less than 2m vv
'mining_getblocktemplate_longpoll.py',
+ 'p2p_segwit.py',
'feature_maxuploadtarget.py',
- 'feature_block.py',
- 'rpc_fundrawtransaction.py --legacy-wallet',
- 'rpc_fundrawtransaction.py --descriptors',
- 'p2p_compactblocks.py',
- 'p2p_compactblocks_blocksonly.py',
+ 'mempool_updatefromblock.py',
+ 'mempool_persist.py --descriptors',
+ # vv Tests less than 60s vv
+ 'rpc_psbt.py --legacy-wallet',
+ 'rpc_psbt.py --descriptors',
+ 'wallet_fundrawtransaction.py --legacy-wallet',
+ 'wallet_fundrawtransaction.py --descriptors',
+ 'wallet_bumpfee.py --legacy-wallet',
+ 'wallet_bumpfee.py --descriptors',
+ 'wallet_import_rescan.py --legacy-wallet',
+ 'wallet_backup.py --legacy-wallet',
+ 'wallet_backup.py --descriptors',
'feature_segwit.py --legacy-wallet',
'feature_segwit.py --descriptors',
- # vv Tests less than 2m vv
+ 'p2p_tx_download.py',
+ 'wallet_avoidreuse.py --legacy-wallet',
+ 'wallet_avoidreuse.py --descriptors',
+ 'feature_abortnode.py',
+ 'wallet_address_types.py --legacy-wallet',
+ 'wallet_address_types.py --descriptors',
'wallet_basic.py --legacy-wallet',
'wallet_basic.py --descriptors',
- 'wallet_labels.py --legacy-wallet',
- 'wallet_labels.py --descriptors',
- 'p2p_segwit.py',
+ 'feature_maxtipage.py',
+ 'wallet_multiwallet.py --legacy-wallet',
+ 'wallet_multiwallet.py --descriptors',
+ 'wallet_multiwallet.py --usecli',
+ 'p2p_dns_seeds.py',
+ 'wallet_groups.py --legacy-wallet',
+ 'wallet_groups.py --descriptors',
+ 'p2p_blockfilters.py',
+ 'feature_assumevalid.py',
+ 'wallet_taproot.py --descriptors',
+ 'feature_bip68_sequence.py',
+ 'rpc_packages.py',
+ 'rpc_bind.py --ipv4',
+ 'rpc_bind.py --ipv6',
+ 'rpc_bind.py --nonloopback',
+ 'p2p_headers_sync_with_minchainwork.py',
+ 'p2p_feefilter.py',
+ 'feature_csv_activation.py',
+ 'p2p_sendheaders.py',
+ 'wallet_listtransactions.py --legacy-wallet',
+ 'wallet_listtransactions.py --descriptors',
+ # vv Tests less than 30s vv
+ 'p2p_invalid_messages.py',
+ 'rpc_createmultisig.py',
'p2p_timeouts.py',
- 'p2p_tx_download.py',
- 'mempool_updatefromblock.py',
'wallet_dump.py --legacy-wallet',
- 'feature_taproot.py',
'rpc_signer.py',
'wallet_signer.py --descriptors',
- # vv Tests less than 60s vv
- 'p2p_sendheaders.py',
'wallet_importmulti.py --legacy-wallet',
'mempool_limit.py',
'rpc_txoutproof.py',
'wallet_listreceivedby.py --legacy-wallet',
'wallet_listreceivedby.py --descriptors',
'wallet_abandonconflict.py --legacy-wallet',
- 'p2p_dns_seeds.py',
'wallet_abandonconflict.py --descriptors',
- 'feature_csv_activation.py',
- 'wallet_address_types.py --legacy-wallet',
- 'wallet_address_types.py --descriptors',
- 'feature_bip68_sequence.py',
- 'p2p_feefilter.py',
- 'rpc_packages.py',
'feature_reindex.py',
- 'feature_abortnode.py',
- # vv Tests less than 30s vv
+ 'wallet_labels.py --legacy-wallet',
+ 'wallet_labels.py --descriptors',
+ 'p2p_compactblocks.py',
+ 'p2p_compactblocks_blocksonly.py',
+ 'wallet_hd.py --legacy-wallet',
+ 'wallet_hd.py --descriptors',
'wallet_keypool_topup.py --legacy-wallet',
'wallet_keypool_topup.py --descriptors',
- 'feature_fee_estimation.py',
+ 'wallet_fast_rescan.py --descriptors',
'interface_zmq.py',
'rpc_invalid_address_message.py',
'interface_bitcoin_cli.py --legacy-wallet',
@@ -154,20 +183,12 @@ BASE_SCRIPTS = [
'rpc_misc.py',
'interface_rest.py',
'mempool_spend_coinbase.py',
- 'wallet_avoidreuse.py --legacy-wallet',
- 'wallet_avoidreuse.py --descriptors',
'wallet_avoid_mixing_output_types.py --descriptors',
'mempool_reorg.py',
- 'mempool_persist.py',
'p2p_block_sync.py',
- 'wallet_multiwallet.py --legacy-wallet',
- 'wallet_multiwallet.py --descriptors',
- 'wallet_multiwallet.py --usecli',
'wallet_createwallet.py --legacy-wallet',
'wallet_createwallet.py --usecli',
'wallet_createwallet.py --descriptors',
- 'wallet_listtransactions.py --legacy-wallet',
- 'wallet_listtransactions.py --descriptors',
'wallet_watchonly.py --legacy-wallet',
'wallet_watchonly.py --usecli --legacy-wallet',
'wallet_reorgsrestore.py',
@@ -177,8 +198,6 @@ BASE_SCRIPTS = [
'interface_usdt_net.py',
'interface_usdt_utxocache.py',
'interface_usdt_validation.py',
- 'rpc_psbt.py --legacy-wallet',
- 'rpc_psbt.py --descriptors',
'rpc_users.py',
'rpc_whitelist.py',
'feature_proxy.py',
@@ -186,19 +205,19 @@ BASE_SCRIPTS = [
'wallet_signrawtransactionwithwallet.py --legacy-wallet',
'wallet_signrawtransactionwithwallet.py --descriptors',
'rpc_signrawtransactionwithkey.py',
- 'p2p_headers_sync_with_minchainwork.py',
'rpc_rawtransaction.py --legacy-wallet',
- 'wallet_groups.py --legacy-wallet',
'wallet_transactiontime_rescan.py --descriptors',
'wallet_transactiontime_rescan.py --legacy-wallet',
'p2p_addrv2_relay.py',
- 'wallet_groups.py --descriptors',
'p2p_compactblocks_hb.py',
'p2p_disconnect_ban.py',
+ 'feature_posix_fs_permissions.py',
'rpc_decodescript.py',
'rpc_blockchain.py',
'rpc_deprecated.py',
'wallet_disable.py',
+ 'wallet_change_address.py --legacy-wallet',
+ 'wallet_change_address.py --descriptors',
'p2p_addr_relay.py',
'p2p_getaddr_caching.py',
'p2p_getdata.py',
@@ -207,8 +226,7 @@ BASE_SCRIPTS = [
'wallet_keypool.py --legacy-wallet',
'wallet_keypool.py --descriptors',
'wallet_descriptor.py --descriptors',
- 'wallet_miniscript.py',
- 'feature_maxtipage.py',
+ 'wallet_miniscript.py --descriptors',
'p2p_nobloomfilter_messages.py',
'p2p_filter.py',
'rpc_setban.py',
@@ -216,15 +234,13 @@ BASE_SCRIPTS = [
'mining_prioritisetransaction.py',
'p2p_invalid_locator.py',
'p2p_invalid_block.py',
- 'p2p_invalid_messages.py',
'p2p_invalid_tx.py',
- 'feature_assumevalid.py',
'example_test.py',
'wallet_txn_doublespend.py --legacy-wallet',
- 'wallet_multisig_descriptor_psbt.py',
+ 'wallet_multisig_descriptor_psbt.py --descriptors',
'wallet_txn_doublespend.py --descriptors',
- 'feature_backwards_compatibility.py --legacy-wallet',
- 'feature_backwards_compatibility.py --descriptors',
+ 'wallet_backwards_compatibility.py --legacy-wallet',
+ 'wallet_backwards_compatibility.py --descriptors',
'wallet_txn_clone.py --mineblock',
'feature_notifications.py',
'rpc_getblockfilter.py',
@@ -234,7 +250,6 @@ BASE_SCRIPTS = [
'feature_rbf.py',
'mempool_packages.py',
'mempool_package_onemore.py',
- 'rpc_createmultisig.py',
'mempool_package_limits.py',
'feature_versionbits_warning.py',
'rpc_preciousblock.py',
@@ -242,6 +257,7 @@ BASE_SCRIPTS = [
'wallet_importprunedfunds.py --descriptors',
'p2p_leak_tx.py',
'p2p_eviction.py',
+ 'p2p_ibd_stalling.py',
'wallet_signmessagewithaddress.py',
'rpc_signmessagewithprivkey.py',
'rpc_generate.py',
@@ -251,18 +267,12 @@ BASE_SCRIPTS = [
'feature_nulldummy.py',
'mempool_accept.py',
'mempool_expiry.py',
- 'wallet_import_rescan.py --legacy-wallet',
'wallet_import_with_label.py --legacy-wallet',
'wallet_importdescriptors.py --descriptors',
'wallet_upgradewallet.py --legacy-wallet',
- 'rpc_bind.py --ipv4',
- 'rpc_bind.py --ipv6',
- 'rpc_bind.py --nonloopback',
'wallet_crosschain.py',
'mining_basic.py',
'feature_signet.py',
- 'wallet_bumpfee.py --legacy-wallet',
- 'wallet_bumpfee.py --descriptors',
'wallet_implicitsegwit.py --legacy-wallet',
'rpc_named_arguments.py',
'feature_startupnotify.py',
@@ -277,6 +287,7 @@ BASE_SCRIPTS = [
'feature_dersig.py',
'feature_cltv.py',
'rpc_uptime.py',
+ 'feature_discover.py',
'wallet_resendwallettransactions.py --legacy-wallet',
'wallet_resendwallettransactions.py --descriptors',
'wallet_fallbackfee.py --legacy-wallet',
@@ -292,8 +303,7 @@ BASE_SCRIPTS = [
'wallet_sendall.py --legacy-wallet',
'wallet_sendall.py --descriptors',
'wallet_create_tx.py --descriptors',
- 'wallet_taproot.py',
- 'wallet_inactive_hdchains.py',
+ 'wallet_inactive_hdchains.py --legacy-wallet',
'p2p_fingerprint.py',
'feature_uacomment.py',
'feature_init.py',
@@ -305,7 +315,6 @@ BASE_SCRIPTS = [
'p2p_add_connections.py',
'feature_bind_port_discover.py',
'p2p_unrequested_blocks.py',
- 'p2p_blockfilters.py',
'p2p_message_capture.py',
'feature_includeconf.py',
'feature_addrman.py',
@@ -313,9 +322,14 @@ BASE_SCRIPTS = [
'mempool_unbroadcast.py',
'mempool_compatibility.py',
'mempool_accept_wtxid.py',
+ 'mempool_dust.py',
+ 'mempool_sigoplimit.py',
'rpc_deriveaddresses.py',
'rpc_deriveaddresses.py --usecli',
'p2p_ping.py',
+ 'p2p_tx_privacy.py',
+ 'rpc_scanblocks.py',
+ 'p2p_sendtxrcncl.py',
'rpc_scantxoutset.py',
'feature_txindex_compatibility.py',
'feature_unsupported_utxo_db.py',
@@ -329,6 +343,7 @@ BASE_SCRIPTS = [
'p2p_permissions.py',
'feature_blocksdir.py',
'wallet_startup.py',
+ 'feature_remove_pruned_files_on_startup.py',
'p2p_i2p_ports.py',
'p2p_i2p_sessions.py',
'feature_config_args.py',
@@ -576,7 +591,7 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir]
if BOLD[0]:
combined_logs_args += ['--color']
- combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate()
+ combined_logs, _ = subprocess.Popen(combined_logs_args, text=True, stdout=subprocess.PIPE).communicate()
print("\n".join(deque(combined_logs.splitlines(), combined_logs_len)))
if failfast:
@@ -661,7 +676,7 @@ class TestHandler:
self.jobs.append((test,
time.time(),
subprocess.Popen([sys.executable, self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + portseed_arg + tmpdir_arg,
- universal_newlines=True,
+ text=True,
stdout=log_stdout,
stderr=log_stderr),
testdir,
diff --git a/test/functional/tool_signet_miner.py b/test/functional/tool_signet_miner.py
index e6fc9072ab..1ad2a579bf 100755
--- a/test/functional/tool_signet_miner.py
+++ b/test/functional/tool_signet_miner.py
@@ -20,6 +20,9 @@ CHALLENGE_PRIVATE_KEY = (42).to_bytes(32, 'big')
class SignetMinerTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.chain = "signet"
self.setup_clean_chain = True
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index 1e5ce513cb..a888f93b03 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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."""
@@ -19,6 +19,9 @@ BUFFER_SIZE = 16 * 1024
class ToolWalletTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
@@ -34,7 +37,7 @@ class ToolWalletTest(BitcoinTestFramework):
if not self.options.descriptors and 'create' in args:
default_args.append('-legacy')
- return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+ return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
def assert_raises_tool_error(self, error, *args):
p = self.bitcoin_wallet_process(*args)
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index d7850b41ac..934f44588d 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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.
@@ -21,6 +21,9 @@ from test_framework.util import (
class AbandonConflictTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [["-minrelaytxfee=0.00001"], []]
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index 5b836f693f..ebeb5620e5 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 that the wallet can send and receive using all combinations of address types.
@@ -66,6 +66,9 @@ from test_framework.util import (
)
class AddressTypeTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 6
self.extra_args = [
diff --git a/test/functional/wallet_avoid_mixing_output_types.py b/test/functional/wallet_avoid_mixing_output_types.py
index cad9d02808..861765f452 100755
--- a/test/functional/wallet_avoid_mixing_output_types.py
+++ b/test/functional/wallet_avoid_mixing_output_types.py
@@ -106,6 +106,9 @@ def generate_payment_values(n, m):
class AddressInputTypeGrouping(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py
index f663666f57..5601d81227 100755
--- a/test/functional/wallet_avoidreuse.py
+++ b/test/functional/wallet_avoidreuse.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 avoid_reuse and setwalletflag features."""
@@ -63,6 +63,8 @@ def assert_balances(node, mine, margin=0.001):
assert_approx(got[k], v, margin)
class AvoidReuseTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
def set_test_params(self):
self.num_nodes = 2
@@ -118,6 +120,8 @@ class AvoidReuseTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Wallet flag is already set to false", self.nodes[0].setwalletflag, 'avoid_reuse', False)
assert_raises_rpc_error(-8, "Wallet flag is already set to true", self.nodes[1].setwalletflag, 'avoid_reuse', True)
+ assert_raises_rpc_error(-8, "Unknown wallet flag: abc", self.nodes[0].setwalletflag, 'abc', True)
+
# Create a wallet with avoid reuse, and test that disabling it afterwards persists
self.nodes[1].createwallet(wallet_name="avoid_reuse_persist", avoid_reuse=True)
w = self.nodes[1].get_wallet_rpc("avoid_reuse_persist")
@@ -191,7 +195,7 @@ class AvoidReuseTest(BitcoinTestFramework):
# getbalances should show no used, 10 btc trusted
assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})
# node 0 should not show a used entry, as it does not enable avoid_reuse
- assert("used" not in self.nodes[0].getbalances()["mine"])
+ assert "used" not in self.nodes[0].getbalances()["mine"]
self.nodes[1].sendtoaddress(retaddr, 5)
self.generate(self.nodes[0], 1)
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index 292fe3a310..4ad25d964e 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 backup features.
@@ -44,6 +44,9 @@ from test_framework.util import (
class WalletBackupTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 4
self.setup_clean_chain = True
diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/wallet_backwards_compatibility.py
index 59a12193fd..76aac3e486 100755
--- a/test/functional/feature_backwards_compatibility.py
+++ b/test/functional/wallet_backwards_compatibility.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Backwards compatibility functional test
@@ -7,10 +7,6 @@
Test various backwards compatibility scenarios. Requires previous releases binaries,
see test/README.md.
-v0.15.2 is not required by this test, but it is used in wallet_upgradewallet.py.
-Due to a hardfork in regtest, it can't be used to sync nodes.
-
-
Due to RPC changes introduced in various versions the below tests
won't work for older versions without some patches or workarounds.
@@ -32,13 +28,17 @@ from test_framework.util import (
class BackwardsCompatibilityTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
- self.num_nodes = 10
+ self.num_nodes = 11
# Add new version after each release:
self.extra_args = [
["-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # Pre-release: use to mine blocks. noban for immediate tx relay
["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # Pre-release: use to receive coins, swap wallets, etc
+ ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # v24.0.1
["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # v23.0
["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # v22.0
["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # v0.21.0
@@ -58,6 +58,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[
None,
None,
+ 240001,
230000,
220000,
210000,
@@ -194,18 +195,18 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
assert_equal(txs[1]["txid"], tx1_id)
assert_equal(txs[2]["walletconflicts"], [tx1_id])
assert_equal(txs[1]["replaced_by_txid"], tx2_id)
- assert not(txs[1]["abandoned"])
+ assert not txs[1]["abandoned"]
assert_equal(txs[1]["confirmations"], -1)
assert_equal(txs[2]["blockindex"], 1)
assert txs[3]["abandoned"]
assert_equal(txs[4]["walletconflicts"], [tx3_id])
assert_equal(txs[3]["replaced_by_txid"], tx4_id)
- assert not(hasattr(txs[3], "blockindex"))
+ assert not hasattr(txs[3], "blockindex")
elif wallet_name == "w2":
- assert(info['private_keys_enabled'] == False)
+ assert info['private_keys_enabled'] == False
assert info['keypoolsize'] == 0
else:
- assert(info['private_keys_enabled'] == True)
+ assert info['private_keys_enabled'] == True
assert info['keypoolsize'] == 0
else:
for node in legacy_nodes:
@@ -271,6 +272,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
assert_equal(info["desc"], descsum_create(descriptor))
# Now copy that same wallet back to 0.16 to make sure no automatic upgrade breaks it
+ node_master.unloadwallet("u1_v16")
os.remove(os.path.join(node_v16_wallets_dir, "wallets/u1_v16"))
shutil.copyfile(
os.path.join(node_master_wallets_dir, "u1_v16"),
diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py
index ec58ace4a2..9ed2caefb7 100755
--- a/test/functional/wallet_balance.py
+++ b/test/functional/wallet_balance.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 balance RPC methods."""
@@ -46,6 +46,9 @@ def create_transactions(node, address, amt, fees):
return txs
class WalletTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
@@ -77,8 +80,18 @@ class WalletTest(BitcoinTestFramework):
self.log.info("Mining blocks ...")
self.generate(self.nodes[0], 1)
self.generate(self.nodes[1], 1)
+
+ # Verify listunspent returns immature coinbase if 'include_immature_coinbase' is set
+ assert_equal(len(self.nodes[0].listunspent(query_options={'include_immature_coinbase': True})), 1)
+ assert_equal(len(self.nodes[0].listunspent(query_options={'include_immature_coinbase': False})), 0)
+
self.generatetoaddress(self.nodes[1], COINBASE_MATURITY + 1, ADDRESS_WATCHONLY)
+ # Verify listunspent returns all immature coinbases if 'include_immature_coinbase' is set
+ # For now, only the legacy wallet will see the coinbases going to the imported 'ADDRESS_WATCHONLY'
+ assert_equal(len(self.nodes[0].listunspent(query_options={'include_immature_coinbase': False})), 1 if self.options.descriptors else 2)
+ assert_equal(len(self.nodes[0].listunspent(query_options={'include_immature_coinbase': True})), 1 if self.options.descriptors else COINBASE_MATURITY + 2)
+
if not self.options.descriptors:
# Tests legacy watchonly behavior which is not present (and does not need to be tested) in descriptor wallets
assert_equal(self.nodes[0].getbalances()['mine']['trusted'], 50)
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 20c577ceb3..53ac01686a 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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."""
@@ -23,6 +23,9 @@ OUT_OF_RANGE = "Amount out of range"
class WalletTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 4
self.extra_args = [[
@@ -629,7 +632,7 @@ class WalletTest(BitcoinTestFramework):
assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999)))
# Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py
- assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
+ assert_raises_rpc_error(-5, "Invalid or unsupported Base58-encoded address.", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")
@@ -728,6 +731,45 @@ class WalletTest(BitcoinTestFramework):
assert_equal(coin_b["parent_descs"][0], multi_b)
self.nodes[0].unloadwallet("wo")
+ self.log.info("Test -spendzeroconfchange")
+ self.restart_node(0, ["-spendzeroconfchange=0"])
+
+ # create new wallet and fund it with a confirmed UTXO
+ self.nodes[0].createwallet(wallet_name="zeroconf", load_on_startup=True)
+ zeroconf_wallet = self.nodes[0].get_wallet_rpc("zeroconf")
+ default_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ default_wallet.sendtoaddress(zeroconf_wallet.getnewaddress(), Decimal('1.0'))
+ self.generate(self.nodes[0], 1, sync_fun=self.no_op)
+ utxos = zeroconf_wallet.listunspent(minconf=0)
+ assert_equal(len(utxos), 1)
+ assert_equal(utxos[0]['confirmations'], 1)
+
+ # spend confirmed UTXO to ourselves
+ zeroconf_wallet.sendall(recipients=[zeroconf_wallet.getnewaddress()])
+ utxos = zeroconf_wallet.listunspent(minconf=0)
+ assert_equal(len(utxos), 1)
+ assert_equal(utxos[0]['confirmations'], 0)
+ # accounts for untrusted pending balance
+ bal = zeroconf_wallet.getbalances()
+ assert_equal(bal['mine']['trusted'], 0)
+ assert_equal(bal['mine']['untrusted_pending'], utxos[0]['amount'])
+
+ # spending an unconfirmed UTXO sent to ourselves should fail
+ assert_raises_rpc_error(-6, "Insufficient funds", zeroconf_wallet.sendtoaddress, zeroconf_wallet.getnewaddress(), Decimal('0.5'))
+
+ # check that it works again with -spendzeroconfchange set (=default)
+ self.restart_node(0, ["-spendzeroconfchange=1"])
+ zeroconf_wallet = self.nodes[0].get_wallet_rpc("zeroconf")
+ utxos = zeroconf_wallet.listunspent(minconf=0)
+ assert_equal(len(utxos), 1)
+ assert_equal(utxos[0]['confirmations'], 0)
+ # accounts for trusted balance
+ bal = zeroconf_wallet.getbalances()
+ assert_equal(bal['mine']['trusted'], utxos[0]['amount'])
+ assert_equal(bal['mine']['untrusted_pending'], 0)
+
+ zeroconf_wallet.sendtoaddress(zeroconf_wallet.getnewaddress(), Decimal('0.5'))
+
if __name__ == '__main__':
WalletTest().main()
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index 158ef66110..ad79e0288c 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 bumpfee RPC.
@@ -17,10 +17,6 @@ from decimal import Decimal
from test_framework.blocktools import (
COINBASE_MATURITY,
- add_witness_commitment,
- create_block,
- create_coinbase,
- send_to_witness,
)
from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
@@ -46,6 +42,9 @@ TOO_HIGH = 100000
class BumpFeeTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
@@ -82,13 +81,14 @@ class BumpFeeTest(BitcoinTestFramework):
self.log.info("Running tests")
dest_address = peer_node.getnewaddress()
- for mode in ["default", "fee_rate"]:
+ for mode in ["default", "fee_rate", "new_outputs"]:
test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address)
self.test_invalid_parameters(rbf_node, peer_node, dest_address)
test_segwit_bumpfee_succeeds(self, rbf_node, dest_address)
test_nonrbf_bumpfee_fails(self, peer_node, dest_address)
test_notmine_bumpfee(self, rbf_node, peer_node, dest_address)
test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_address)
+ test_bumpfee_with_abandoned_descendant_succeeds(self, rbf_node, rbf_node_address, dest_address)
test_dust_to_fee(self, rbf_node, dest_address)
test_watchonly_psbt(self, peer_node, rbf_node, dest_address)
test_rebumping(self, rbf_node, dest_address)
@@ -151,12 +151,20 @@ class BumpFeeTest(BitcoinTestFramework):
self.log.info("Test invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
- assert_raises_rpc_error(-3, "Expected type string for estimate_mode, got {}".format(k),
+ assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string",
rbf_node.bumpfee, rbfid, {"estimate_mode": v})
for mode in ["foo", Decimal("3.1415"), "sat/B", "BTC/kB"]:
assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"',
rbf_node.bumpfee, rbfid, {"estimate_mode": mode})
+ self.log.info("Test invalid outputs values")
+ assert_raises_rpc_error(-8, "Invalid parameter, output argument cannot be an empty array",
+ rbf_node.bumpfee, rbfid, {"outputs": []})
+ assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: " + dest_address,
+ rbf_node.bumpfee, rbfid, {"outputs": [{dest_address: 0.1}, {dest_address: 0.2}]})
+ assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
+ rbf_node.bumpfee, rbfid, {"outputs": [{"data": "deadbeef"}, {"data": "deadbeef"}]})
+
self.clear_mempool()
@@ -169,6 +177,10 @@ def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address):
if mode == "fee_rate":
bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"fee_rate": str(NORMAL)})
bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": NORMAL})
+ elif mode == "new_outputs":
+ new_address = peer_node.getnewaddress()
+ bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"outputs": {new_address: 0.0003}})
+ bumped_tx = rbf_node.bumpfee(rbfid, {"outputs": {new_address: 0.0003}})
else:
bumped_psbt = rbf_node.psbtbumpfee(rbfid)
bumped_tx = rbf_node.bumpfee(rbfid)
@@ -192,6 +204,10 @@ def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address):
bumpedwtx = rbf_node.gettransaction(bumped_tx["txid"])
assert_equal(oldwtx["replaced_by_txid"], bumped_tx["txid"])
assert_equal(bumpedwtx["replaces_txid"], rbfid)
+ # if this is a new_outputs test, check that outputs were indeed replaced
+ if mode == "new_outputs":
+ assert len(bumpedwtx["details"]) == 1
+ assert bumpedwtx["details"][0]["address"] == new_address
self.clear_mempool()
@@ -200,16 +216,8 @@ def test_segwit_bumpfee_succeeds(self, rbf_node, dest_address):
# Create a transaction with segwit output, then create an RBF transaction
# which spends it, and make sure bumpfee can be called on it.
- segwit_in = next(u for u in rbf_node.listunspent() if u["amount"] == Decimal("0.001"))
- segwit_out = rbf_node.getaddressinfo(rbf_node.getnewaddress(address_type='bech32'))
- segwitid = send_to_witness(
- use_p2wsh=False,
- node=rbf_node,
- utxo=segwit_in,
- pubkey=segwit_out["pubkey"],
- encode_p2sh=False,
- amount=Decimal("0.0009"),
- sign=True)
+ segwit_out = rbf_node.getnewaddress(address_type='bech32')
+ segwitid = rbf_node.send({segwit_out: "0.0009"}, options={"change_position": 1})["txid"]
rbfraw = rbf_node.createrawtransaction([{
'txid': segwitid,
@@ -295,6 +303,35 @@ def test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_ad
self.clear_mempool()
+def test_bumpfee_with_abandoned_descendant_succeeds(self, rbf_node, rbf_node_address, dest_address):
+ self.log.info('Test that fee can be bumped when it has abandoned descendant')
+ # parent is send-to-self, so we don't have to check which output is change when creating the child tx
+ parent_id = spend_one_input(rbf_node, rbf_node_address)
+ # Submit child transaction with low fee
+ child_id = rbf_node.send(outputs={dest_address: 0.00020000},
+ options={"inputs": [{"txid": parent_id, "vout": 0}], "fee_rate": 2})["txid"]
+ assert child_id in rbf_node.getrawmempool()
+
+ # Restart the node with higher min relay fee so the descendant tx is no longer in mempool so that we can abandon it
+ self.restart_node(1, ['-minrelaytxfee=0.00005'] + self.extra_args[1])
+ rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
+ self.connect_nodes(1, 0)
+ assert parent_id in rbf_node.getrawmempool()
+ assert child_id not in rbf_node.getrawmempool()
+ # Should still raise an error even if not in mempool
+ assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
+ # Now abandon the child transaction and bump the original
+ rbf_node.abandontransaction(child_id)
+ bumped_result = rbf_node.bumpfee(parent_id, {"fee_rate": HIGH})
+ assert bumped_result['txid'] in rbf_node.getrawmempool()
+ assert parent_id not in rbf_node.getrawmempool()
+ # Cleanup
+ self.restart_node(1, self.extra_args[1])
+ rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
+ self.connect_nodes(1, 0)
+ self.clear_mempool()
+
+
def test_small_output_with_feerate_succeeds(self, rbf_node, dest_address):
self.log.info('Testing small output with feerate bump succeeds')
@@ -541,10 +578,10 @@ def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address):
# then invalidate the block so the rbf tx will be put back in the mempool.
# This makes it possible to check whether the rbf tx outputs are
# spendable before the rbf tx is confirmed.
- block = submit_block_with_tx(rbf_node, rbftx)
+ block = self.generateblock(rbf_node, output="raw(51)", transactions=[rbftx])
# Can not abandon conflicted tx
assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: rbf_node.abandontransaction(txid=bumpid))
- rbf_node.invalidateblock(block.hash)
+ rbf_node.invalidateblock(block["hash"])
# Call abandon to make sure the wallet doesn't attempt to resubmit
# the bump tx and hope the wallet does not rebroadcast before we call.
rbf_node.abandontransaction(bumpid)
@@ -566,7 +603,7 @@ def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address):
def test_bumpfee_metadata(self, rbf_node, dest_address):
self.log.info('Test that bumped txn metadata persists to new txn record')
- assert(rbf_node.getbalance() < 49)
+ assert rbf_node.getbalance() < 49
self.generatetoaddress(rbf_node, 101, rbf_node.getnewaddress())
rbfid = rbf_node.sendtoaddress(dest_address, 49, "comment value", "to value")
bumped_tx = rbf_node.bumpfee(rbfid)
@@ -607,29 +644,20 @@ def test_change_script_match(self, rbf_node, dest_address):
self.clear_mempool()
-def spend_one_input(node, dest_address, change_size=Decimal("0.00049000")):
+def spend_one_input(node, dest_address, change_size=Decimal("0.00049000"), data=None):
tx_input = dict(
sequence=MAX_BIP125_RBF_SEQUENCE, **next(u for u in node.listunspent() if u["amount"] == Decimal("0.00100000")))
destinations = {dest_address: Decimal("0.00050000")}
if change_size > 0:
destinations[node.getrawchangeaddress()] = change_size
+ if data:
+ destinations['data'] = data
rawtx = node.createrawtransaction([tx_input], destinations)
signedtx = node.signrawtransactionwithwallet(rawtx)
txid = node.sendrawtransaction(signedtx["hex"])
return txid
-def submit_block_with_tx(node, tx):
- tip = node.getbestblockhash()
- height = node.getblockcount() + 1
- block_time = node.getblockheader(tip)["mediantime"] + 1
- block = create_block(int(tip, 16), create_coinbase(height), block_time, txlist=[tx])
- add_witness_commitment(block)
- block.solve()
- node.submitblock(block.serialize().hex())
- return block
-
-
def test_no_more_inputs_fails(self, rbf_node, dest_address):
self.log.info('Test that bumpfee fails when there are no available confirmed outputs')
# feerate rbf requires confirmed outputs when change output doesn't exist or is insufficient
diff --git a/test/functional/wallet_change_address.py b/test/functional/wallet_change_address.py
new file mode 100755
index 0000000000..f8bfe9eebf
--- /dev/null
+++ b/test/functional/wallet_change_address.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023 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 wallet change address selection"""
+
+import re
+
+from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+)
+
+
+class WalletChangeAddressTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+ # discardfee is used to make change outputs less likely in the change_pos test
+ self.extra_args = [
+ [],
+ ["-discardfee=1"],
+ ["-avoidpartialspends", "-discardfee=1"]
+ ]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def assert_change_index(self, node, tx, index):
+ change_index = None
+ for vout in tx["vout"]:
+ info = node.getaddressinfo(vout["scriptPubKey"]["address"])
+ if (info["ismine"] and info["ischange"]):
+ change_index = int(re.findall(r'\d+', info["hdkeypath"])[-1])
+ break
+ assert_equal(change_index, index)
+
+ def assert_change_pos(self, wallet, tx, pos):
+ change_pos = None
+ for index, output in enumerate(tx["vout"]):
+ info = wallet.getaddressinfo(output["scriptPubKey"]["address"])
+ if (info["ismine"] and info["ischange"]):
+ change_pos = index
+ break
+ assert_equal(change_pos, pos)
+
+ def run_test(self):
+ self.log.info("Setting up")
+ # Mine some coins
+ self.generate(self.nodes[0], COINBASE_MATURITY + 1)
+
+ # Get some addresses from the two nodes
+ addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
+ addr2 = [self.nodes[2].getnewaddress() for _ in range(3)]
+ addrs = addr1 + addr2
+
+ # Send 1 + 0.5 coin to each address
+ [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]
+ [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]
+ self.generate(self.nodes[0], 1)
+
+ for i in range(20):
+ for n in [1, 2]:
+ self.log.debug(f"Send transaction from node {n}: expected change index {i}")
+ txid = self.nodes[n].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
+ tx = self.nodes[n].getrawtransaction(txid, True)
+ # find the change output and ensure that expected change index was used
+ self.assert_change_index(self.nodes[n], tx, i)
+
+ # Start next test with fresh wallets and new coins
+ self.nodes[1].createwallet("w1")
+ self.nodes[2].createwallet("w2")
+ w1 = self.nodes[1].get_wallet_rpc("w1")
+ w2 = self.nodes[2].get_wallet_rpc("w2")
+ addr1 = w1.getnewaddress()
+ addr2 = w2.getnewaddress()
+ self.nodes[0].sendtoaddress(addr1, 3.0)
+ self.nodes[0].sendtoaddress(addr1, 0.1)
+ self.nodes[0].sendtoaddress(addr2, 3.0)
+ self.nodes[0].sendtoaddress(addr2, 0.1)
+ self.generate(self.nodes[0], 1)
+
+ sendTo1 = self.nodes[0].getnewaddress()
+ sendTo2 = self.nodes[0].getnewaddress()
+ sendTo3 = self.nodes[0].getnewaddress()
+
+ # The avoid partial spends wallet will always create a change output
+ node = self.nodes[2]
+ res = w2.send({sendTo1: "1.0", sendTo2: "1.0", sendTo3: "0.9999"}, options={"change_position": 0})
+ tx = node.getrawtransaction(res["txid"], True)
+ self.assert_change_pos(w2, tx, 0)
+
+ # The default wallet will internally create a tx without change first,
+ # then create a second candidate using APS that requires a change output.
+ # Ensure that the user-configured change position is kept
+ node = self.nodes[1]
+ res = w1.send({sendTo1: "1.0", sendTo2: "1.0", sendTo3: "0.9999"}, options={"change_position": 0})
+ tx = node.getrawtransaction(res["txid"], True)
+ # If the wallet ignores the user's change_position there is still a 25%
+ # that the random change position passes the test
+ self.assert_change_pos(w1, tx, 0)
+
+if __name__ == '__main__':
+ WalletChangeAddressTest().main()
diff --git a/test/functional/wallet_coinbase_category.py b/test/functional/wallet_coinbase_category.py
index c2a8e612cf..c2cb0bf3b0 100755
--- a/test/functional/wallet_coinbase_category.py
+++ b/test/functional/wallet_coinbase_category.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 coinbase transactions return the correct categories.
@@ -13,6 +13,9 @@ from test_framework.util import (
)
class CoinbaseCategoryTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py
index a213a261ef..2d9bb38fcc 100755
--- a/test/functional/wallet_create_tx.py
+++ b/test/functional/wallet_create_tx.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,6 +14,9 @@ from test_framework.blocktools import (
class CreateTxWalletTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index 12480d4d1e..22c491441b 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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.
@@ -16,6 +16,9 @@ from test_framework.util import (
from test_framework.wallet_util import bytes_to_wif, generate_wif_key
class CreateWalletTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
diff --git a/test/functional/wallet_crosschain.py b/test/functional/wallet_crosschain.py
index b6d0c87985..7a1297e65f 100755
--- a/test/functional/wallet_crosschain.py
+++ b/test/functional/wallet_crosschain.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,6 +9,9 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_raises_rpc_error
class WalletCrossChain(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
@@ -21,37 +24,41 @@ class WalletCrossChain(BitcoinTestFramework):
# Switch node 1 to testnet before starting it.
self.nodes[1].chain = 'testnet3'
- self.nodes[1].extra_args = ['-maxconnections=0'] # disable testnet sync
- with open(self.nodes[1].bitcoinconf, 'r', encoding='utf8') as conf:
- conf_data = conf.read()
- with open (self.nodes[1].bitcoinconf, 'w', encoding='utf8') as conf:
- conf.write(conf_data.replace('regtest=', 'testnet=').replace('[regtest]', '[test]'))
-
+ self.nodes[1].extra_args = ['-maxconnections=0', '-prune=550'] # disable testnet sync
+ self.nodes[1].replace_in_config([('regtest=', 'testnet='), ('[regtest]', '[test]')])
self.start_nodes()
def run_test(self):
self.log.info("Creating wallets")
node0_wallet = os.path.join(self.nodes[0].datadir, 'node0_wallet')
+ node0_wallet_backup = os.path.join(self.nodes[0].datadir, 'node0_wallet.bak')
self.nodes[0].createwallet(node0_wallet)
+ self.nodes[0].backupwallet(node0_wallet_backup)
self.nodes[0].unloadwallet(node0_wallet)
node1_wallet = os.path.join(self.nodes[1].datadir, 'node1_wallet')
+ node1_wallet_backup = os.path.join(self.nodes[0].datadir, 'node1_wallet.bak')
self.nodes[1].createwallet(node1_wallet)
+ self.nodes[1].backupwallet(node1_wallet_backup)
self.nodes[1].unloadwallet(node1_wallet)
- self.log.info("Loading wallets into nodes with a different genesis blocks")
+ self.log.info("Loading/restoring wallets into nodes with a different genesis block")
if self.options.descriptors:
assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[0].loadwallet, node1_wallet)
assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].loadwallet, node0_wallet)
+ assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[0].restorewallet, 'w', node1_wallet_backup)
+ assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].restorewallet, 'w', node0_wallet_backup)
else:
assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[0].loadwallet, node1_wallet)
assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].loadwallet, node0_wallet)
+ assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[0].restorewallet, 'w', node1_wallet_backup)
+ assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].restorewallet, 'w', node0_wallet_backup)
if not self.options.descriptors:
self.log.info("Override cross-chain wallet load protection")
self.stop_nodes()
- self.start_nodes([['-walletcrosschain']] * self.num_nodes)
+ self.start_nodes([['-walletcrosschain', '-prune=550']] * self.num_nodes)
self.nodes[0].loadwallet(node1_wallet)
self.nodes[1].loadwallet(node0_wallet)
diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
index 5dc23ba245..b0e93df36a 100755
--- a/test/functional/wallet_descriptor.py
+++ b/test/functional/wallet_descriptor.py
@@ -1,8 +1,14 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 descriptor wallet function."""
+import os
+
+try:
+ import sqlite3
+except ImportError:
+ pass
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
@@ -13,6 +19,9 @@ from test_framework.util import (
class WalletDescriptorTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
@@ -22,6 +31,7 @@ class WalletDescriptorTest(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
self.skip_if_no_sqlite()
+ self.skip_if_no_py_sqlite3()
def run_test(self):
if self.is_bdb_compiled():
@@ -62,6 +72,11 @@ class WalletDescriptorTest(BitcoinTestFramework):
assert addr_info['desc'].startswith('wpkh(')
assert_equal(addr_info['hdkeypath'], 'm/84\'/1\'/0\'/0/0')
+ addr = self.nodes[0].getnewaddress("", "bech32m")
+ addr_info = self.nodes[0].getaddressinfo(addr)
+ assert addr_info['desc'].startswith('tr(')
+ assert_equal(addr_info['hdkeypath'], 'm/86\'/1\'/0\'/0/0')
+
# Check that getrawchangeaddress works
addr = self.nodes[0].getrawchangeaddress("legacy")
addr_info = self.nodes[0].getaddressinfo(addr)
@@ -78,6 +93,11 @@ class WalletDescriptorTest(BitcoinTestFramework):
assert addr_info['desc'].startswith('wpkh(')
assert_equal(addr_info['hdkeypath'], 'm/84\'/1\'/0\'/1/0')
+ addr = self.nodes[0].getrawchangeaddress("bech32m")
+ addr_info = self.nodes[0].getaddressinfo(addr)
+ assert addr_info['desc'].startswith('tr(')
+ assert_equal(addr_info['hdkeypath'], 'm/86\'/1\'/0\'/1/0')
+
# Make a wallet to receive coins at
self.nodes[0].createwallet(wallet_name="desc2", descriptors=True)
recv_wrpc = self.nodes[0].get_wallet_rpc("desc2")
@@ -94,7 +114,7 @@ class WalletDescriptorTest(BitcoinTestFramework):
# Make sure things are disabled
self.log.info("Test disabled RPCs")
assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importprivkey, "cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW")
- assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importpubkey, send_wrpc.getaddressinfo(send_wrpc.getnewaddress()))
+ assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importpubkey, send_wrpc.getaddressinfo(send_wrpc.getnewaddress())["pubkey"])
assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importaddress, recv_wrpc.getnewaddress())
assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importmulti, [])
assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.addmultisigaddress, 1, [recv_wrpc.getnewaddress()])
@@ -161,9 +181,11 @@ class WalletDescriptorTest(BitcoinTestFramework):
addr_types = [('legacy', False, 'pkh(', '44\'/1\'/0\'', -13),
('p2sh-segwit', False, 'sh(wpkh(', '49\'/1\'/0\'', -14),
('bech32', False, 'wpkh(', '84\'/1\'/0\'', -13),
+ ('bech32m', False, 'tr(', '86\'/1\'/0\'', -13),
('legacy', True, 'pkh(', '44\'/1\'/0\'', -13),
('p2sh-segwit', True, 'sh(wpkh(', '49\'/1\'/0\'', -14),
- ('bech32', True, 'wpkh(', '84\'/1\'/0\'', -13)]
+ ('bech32', True, 'wpkh(', '84\'/1\'/0\'', -13),
+ ('bech32m', True, 'tr(', '86\'/1\'/0\'', -13)]
for addr_type, internal, desc_prefix, deriv_path, int_idx in addr_types:
int_str = 'internal' if internal else 'external'
@@ -209,5 +231,15 @@ class WalletDescriptorTest(BitcoinTestFramework):
imp_addr = imp_rpc.getnewaddress(address_type=addr_type)
assert_equal(exp_addr, imp_addr)
+ self.log.info("Test that loading descriptor wallet containing legacy key types throws error")
+ self.nodes[0].createwallet(wallet_name="crashme", descriptors=True)
+ self.nodes[0].unloadwallet("crashme")
+ wallet_db = os.path.join(self.nodes[0].datadir, self.chain, "wallets", "crashme", self.wallet_data_filename)
+ with sqlite3.connect(wallet_db) as conn:
+ # add "cscript" entry: key type is uint160 (20 bytes), value type is CScript (zero-length here)
+ conn.execute('INSERT INTO main VALUES(?, ?)', (b'\x07cscript' + b'\x00'*20, b'\x00'))
+ assert_raises_rpc_error(-4, "Unexpected legacy entry in descriptor wallet found.", self.nodes[0].loadwallet, "crashme")
+
+
if __name__ == '__main__':
WalletDescriptorTest().main ()
diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py
index 74cddf2738..9c73f7dead 100755
--- a/test/functional/wallet_disable.py
+++ b/test/functional/wallet_disable.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 a node with the -disablewallet option.
diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py
index 9f0d666270..cf20ff1239 100755
--- a/test/functional/wallet_dump.py
+++ b/test/functional/wallet_dump.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 dumpwallet RPC."""
@@ -93,6 +93,9 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old):
class WalletDumpTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=False)
+
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [["-keypool=90", "-addresstype=legacy"]]
diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py
index 37c1c4bff3..88b9ebbddd 100755
--- a/test/functional/wallet_encryption.py
+++ b/test/functional/wallet_encryption.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 Wallet encryption"""
@@ -14,6 +14,9 @@ from test_framework.util import (
class WalletEncryptionTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
@@ -87,6 +90,17 @@ class WalletEncryptionTest(BitcoinTestFramework):
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE + 1000)
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
assert_equal(actual_time, expected_time)
+ self.nodes[0].walletlock()
+
+ # Test passphrase with null characters
+ passphrase_with_nulls = "Phrase\0With\0Nulls"
+ self.nodes[0].walletpassphrasechange(passphrase2, passphrase_with_nulls)
+ # walletpassphrasechange should not stop at null characters
+ assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase_with_nulls.partition("\0")[0], 10)
+ self.nodes[0].walletpassphrase(passphrase_with_nulls, 10)
+ sig = self.nodes[0].signmessage(address, msg)
+ assert self.nodes[0].verifymessage(address, sig, msg)
+ self.nodes[0].walletlock()
if __name__ == '__main__':
diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py
index acd92097ff..f0740b72fd 100755
--- a/test/functional/wallet_fallbackfee.py
+++ b/test/functional/wallet_fallbackfee.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 wallet replace-by-fee capabilities in conjunction with the fallbackfee."""
@@ -9,6 +9,9 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_raises_rpc_error
class WalletRBFTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
diff --git a/test/functional/wallet_fast_rescan.py b/test/functional/wallet_fast_rescan.py
new file mode 100755
index 0000000000..1ab24f1a96
--- /dev/null
+++ b/test/functional/wallet_fast_rescan.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 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 that fast rescan using block filters for descriptor wallets detects
+ top-ups correctly and finds the same transactions than the slow variant."""
+import os
+from typing import List
+
+from test_framework.descriptors import descsum_create
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.test_node import TestNode
+from test_framework.util import assert_equal
+from test_framework.wallet import MiniWallet
+from test_framework.wallet_util import get_generate_key
+
+
+KEYPOOL_SIZE = 100 # smaller than default size to speed-up test
+NUM_DESCRIPTORS = 9 # number of descriptors (8 default ranged ones + 1 fixed non-ranged one)
+NUM_BLOCKS = 6 # number of blocks to mine
+
+
+class WalletFastRescanTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.extra_args = [[f'-keypool={KEYPOOL_SIZE}', '-blockfilterindex=1']]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+ self.skip_if_no_sqlite()
+
+ def get_wallet_txids(self, node: TestNode, wallet_name: str) -> List[str]:
+ w = node.get_wallet_rpc(wallet_name)
+ txs = w.listtransactions('*', 1000000)
+ return [tx['txid'] for tx in txs]
+
+ def run_test(self):
+ node = self.nodes[0]
+ wallet = MiniWallet(node)
+
+ self.log.info("Create descriptor wallet with backup")
+ WALLET_BACKUP_FILENAME = os.path.join(node.datadir, 'wallet.bak')
+ node.createwallet(wallet_name='topup_test', descriptors=True)
+ w = node.get_wallet_rpc('topup_test')
+ fixed_key = get_generate_key()
+ print(w.importdescriptors([{"desc": descsum_create(f"wpkh({fixed_key.privkey})"), "timestamp": "now"}]))
+ descriptors = w.listdescriptors()['descriptors']
+ assert_equal(len(descriptors), NUM_DESCRIPTORS)
+ w.backupwallet(WALLET_BACKUP_FILENAME)
+
+ self.log.info(f"Create txs sending to end range address of each descriptor, triggering top-ups")
+ for i in range(NUM_BLOCKS):
+ self.log.info(f"Block {i+1}/{NUM_BLOCKS}")
+ for desc_info in w.listdescriptors()['descriptors']:
+ if 'range' in desc_info:
+ start_range, end_range = desc_info['range']
+ addr = w.deriveaddresses(desc_info['desc'], [end_range, end_range])[0]
+ spk = bytes.fromhex(w.getaddressinfo(addr)['scriptPubKey'])
+ self.log.info(f"-> range [{start_range},{end_range}], last address {addr}")
+ else:
+ spk = bytes.fromhex(fixed_key.p2wpkh_script)
+ self.log.info(f"-> fixed non-range descriptor address {fixed_key.p2wpkh_addr}")
+ wallet.send_to(from_node=node, scriptPubKey=spk, amount=10000)
+ self.generate(node, 1)
+
+ self.log.info("Import wallet backup with block filter index")
+ with node.assert_debug_log(['fast variant using block filters']):
+ node.restorewallet('rescan_fast', WALLET_BACKUP_FILENAME)
+ txids_fast = self.get_wallet_txids(node, 'rescan_fast')
+
+ self.log.info("Import non-active descriptors with block filter index")
+ node.createwallet(wallet_name='rescan_fast_nonactive', descriptors=True, disable_private_keys=True, blank=True)
+ with node.assert_debug_log(['fast variant using block filters']):
+ w = node.get_wallet_rpc('rescan_fast_nonactive')
+ w.importdescriptors([{"desc": descriptor['desc'], "timestamp": 0} for descriptor in descriptors])
+ txids_fast_nonactive = self.get_wallet_txids(node, 'rescan_fast_nonactive')
+
+ self.restart_node(0, [f'-keypool={KEYPOOL_SIZE}', '-blockfilterindex=0'])
+ self.log.info("Import wallet backup w/o block filter index")
+ with node.assert_debug_log(['slow variant inspecting all blocks']):
+ node.restorewallet("rescan_slow", WALLET_BACKUP_FILENAME)
+ txids_slow = self.get_wallet_txids(node, 'rescan_slow')
+
+ self.log.info("Import non-active descriptors w/o block filter index")
+ node.createwallet(wallet_name='rescan_slow_nonactive', descriptors=True, disable_private_keys=True, blank=True)
+ with node.assert_debug_log(['slow variant inspecting all blocks']):
+ w = node.get_wallet_rpc('rescan_slow_nonactive')
+ w.importdescriptors([{"desc": descriptor['desc'], "timestamp": 0} for descriptor in descriptors])
+ txids_slow_nonactive = self.get_wallet_txids(node, 'rescan_slow_nonactive')
+
+ self.log.info("Verify that all rescans found the same txs in slow and fast variants")
+ assert_equal(len(txids_slow), NUM_DESCRIPTORS * NUM_BLOCKS)
+ assert_equal(len(txids_fast), NUM_DESCRIPTORS * NUM_BLOCKS)
+ assert_equal(len(txids_slow_nonactive), NUM_DESCRIPTORS * NUM_BLOCKS)
+ assert_equal(len(txids_fast_nonactive), NUM_DESCRIPTORS * NUM_BLOCKS)
+ assert_equal(sorted(txids_slow), sorted(txids_fast))
+ assert_equal(sorted(txids_slow_nonactive), sorted(txids_fast_nonactive))
+
+
+if __name__ == '__main__':
+ WalletFastRescanTest().main()
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py
index 17c6fce9c2..29ddb77b41 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/wallet_fundrawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 fundrawtransaction RPC."""
@@ -27,6 +27,8 @@ from test_framework.util import (
)
from test_framework.wallet_util import bytes_to_wif
+ERR_NOT_ENOUGH_PRESET_INPUTS = "The preselected coins total amount does not cover the transaction target. " \
+ "Please allow other inputs to be automatically selected or include more coins manually"
def get_unspent(listunspent, amount):
for utx in listunspent:
@@ -35,6 +37,9 @@ def get_unspent(listunspent, amount):
raise AssertionError('Could not find unspent with amount={}'.format(amount))
class RawTransactionsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 4
self.setup_clean_chain = True
@@ -107,6 +112,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.generate(self.nodes[0], 121)
self.test_add_inputs_default_value()
+ self.test_preset_inputs_selection()
self.test_weight_calculation()
self.test_change_position()
self.test_simple()
@@ -142,6 +148,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.test_external_inputs()
self.test_22670()
self.test_feerate_rounding()
+ self.test_input_confs_control()
def test_change_position(self):
"""Ensure setting changePosition in fundraw with an exact match is handled properly."""
@@ -324,7 +331,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])
# Should fail without add_inputs:
- assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False})
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False})
# add_inputs is enabled by default
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
@@ -356,7 +363,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
# Should fail without add_inputs:
- assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False})
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False})
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {"add_inputs": True})
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
@@ -390,7 +397,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
# Should fail without add_inputs:
- assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False})
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False})
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {"add_inputs": True})
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
@@ -406,7 +413,9 @@ class RawTransactionsTest(BitcoinTestFramework):
def test_invalid_input(self):
self.log.info("Test fundrawtxn with an invalid vin")
- inputs = [ {'txid' : "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout' : 0} ] #invalid vin!
+ txid = "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1"
+ vout = 0
+ inputs = [ {'txid' : txid, 'vout' : vout} ] #invalid vin!
outputs = { self.nodes[0].getnewaddress() : 1.0}
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
assert_raises_rpc_error(-4, "Unable to find UTXO for external input", self.nodes[2].fundrawtransaction, rawtx)
@@ -793,7 +802,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.log.info("Test fundrawtxn with invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
- assert_raises_rpc_error(-3, "Expected type string for estimate_mode, got {}".format(k),
+ assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string",
node.fundrawtransaction, rawtx, {"estimate_mode": v, "conf_target": 0.1, "add_inputs": True})
for mode in ["", "foo", Decimal("3.141592")]:
assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"',
@@ -803,7 +812,7 @@ class RawTransactionsTest(BitcoinTestFramework):
for mode in ["unset", "economical", "conservative"]:
self.log.debug("{}".format(mode))
for k, v in {"string": "", "object": {"foo": "bar"}}.items():
- assert_raises_rpc_error(-3, "Expected type number for conf_target, got {}".format(k),
+ assert_raises_rpc_error(-3, f"JSON value of type {k} for field conf_target is not of expected type number",
node.fundrawtransaction, rawtx, {"estimate_mode": mode, "conf_target": v, "add_inputs": True})
for n in [-1, 0, 1009]:
assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees.h
@@ -977,11 +986,15 @@ class RawTransactionsTest(BitcoinTestFramework):
# are selected, the transaction will end up being too large, so it
# shouldn't use BnB and instead fall back to Knapsack but that behavior
# is not implemented yet. For now we just check that we get an error.
+ # First, force the wallet to bulk-generate the addresses we'll need.
+ recipient.keypoolrefill(1500)
for _ in range(1500):
outputs[recipient.getnewaddress()] = 0.1
wallet.sendmany("", outputs)
self.generate(self.nodes[0], 10)
- assert_raises_rpc_error(-4, "Transaction too large", recipient.fundrawtransaction, rawtx)
+ assert_raises_rpc_error(-4, "The inputs size exceeds the maximum weight. "
+ "Please try sending a smaller amount or manually consolidating your wallet's UTXOs",
+ recipient.fundrawtransaction, rawtx)
self.nodes[0].unloadwallet("large")
def test_external_inputs(self):
@@ -1011,7 +1024,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# An external input without solving data should result in an error
raw_tx = wallet.createrawtransaction([ext_utxo], {self.nodes[0].getnewaddress(): ext_utxo["amount"] / 2})
- assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, raw_tx)
+ assert_raises_rpc_error(-4, "Not solvable pre-selected input COutPoint(%s, %s)" % (ext_utxo["txid"][0:10], ext_utxo["vout"]), wallet.fundrawtransaction, raw_tx)
# Error conditions
assert_raises_rpc_error(-5, "'not a pubkey' is not hex", wallet.fundrawtransaction, raw_tx, {"solving_data": {"pubkeys":["not a pubkey"]}})
@@ -1095,6 +1108,8 @@ class RawTransactionsTest(BitcoinTestFramework):
# Expect: only preset inputs are used.
# 5. Explicit add_inputs=true, no preset inputs (same as (1) but with an explicit set):
# Expect: include inputs from the wallet.
+ # 6. Explicit add_inputs=false, no preset inputs:
+ # Expect: failure as we did not provide inputs and the process cannot automatically select coins.
# Case (1), 'send' command
# 'add_inputs' value is true unless "inputs" are specified, in such case, add_inputs=false.
@@ -1120,7 +1135,7 @@ class RawTransactionsTest(BitcoinTestFramework):
}
]
}
- assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{addr1: 8}], options=options)
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 8}], options=options)
# Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount)
options["add_inputs"] = True
@@ -1146,6 +1161,10 @@ class RawTransactionsTest(BitcoinTestFramework):
tx = wallet.send(outputs=[{addr1: 8}], options=options)
assert tx["complete"]
+ # 6. Explicit add_inputs=false, no preset inputs:
+ options = {"add_inputs": False}
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 3}], options=options)
+
################################################
# Case (1), 'walletcreatefundedpsbt' command
@@ -1161,11 +1180,10 @@ class RawTransactionsTest(BitcoinTestFramework):
"vout": 1 # change position was hardcoded to index 0
}]
outputs = {self.nodes[1].getnewaddress(): 8}
- assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, inputs=inputs, outputs=outputs)
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.walletcreatefundedpsbt, inputs=inputs, outputs=outputs)
# Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount)
options["add_inputs"] = True
- options["add_to_wallet"] = False
assert "psbt" in wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, options=options)
# Case (4), Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount)
@@ -1187,8 +1205,56 @@ class RawTransactionsTest(BitcoinTestFramework):
}
assert "psbt" in wallet.walletcreatefundedpsbt(inputs=[], outputs=outputs, options=options)
+ # Case (6). Explicit add_inputs=false, no preset inputs:
+ options = {"add_inputs": False}
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.walletcreatefundedpsbt, inputs=[], outputs=outputs, options=options)
+
self.nodes[2].unloadwallet("test_preset_inputs")
+ def test_preset_inputs_selection(self):
+ self.log.info('Test wallet preset inputs are not double-counted or reused in coin selection')
+
+ # Create and fund the wallet with 4 UTXO of 5 BTC each (20 BTC total)
+ self.nodes[2].createwallet("test_preset_inputs_selection")
+ wallet = self.nodes[2].get_wallet_rpc("test_preset_inputs_selection")
+ outputs = {}
+ for _ in range(4):
+ outputs[wallet.getnewaddress(address_type="bech32")] = 5
+ self.nodes[0].sendmany("", outputs)
+ self.generate(self.nodes[0], 1)
+
+ # Select the preset inputs
+ coins = wallet.listunspent()
+ preset_inputs = [coins[0], coins[1], coins[2]]
+
+ # Now let's create the tx creation options
+ options = {
+ "inputs": preset_inputs,
+ "add_inputs": True, # automatically add coins from the wallet to fulfill the target
+ "subtract_fee_from_outputs": [0], # deduct fee from first output
+ "add_to_wallet": False
+ }
+
+ # Attempt to send 29 BTC from a wallet that only has 20 BTC. The wallet should exclude
+ # the preset inputs from the pool of available coins, realize that there is not enough
+ # money to fund the 29 BTC payment, and fail with "Insufficient funds".
+ #
+ # Even with SFFO, the wallet can only afford to send 20 BTC.
+ # If the wallet does not properly exclude preset inputs from the pool of available coins
+ # prior to coin selection, it may create a transaction that does not fund the full payment
+ # amount or, through SFFO, incorrectly reduce the recipient's amount by the difference
+ # between the original target and the wrongly counted inputs (in this case 9 BTC)
+ # so that the recipient's amount is no longer equal to the user's selected target of 29 BTC.
+
+ # First case, use 'subtract_fee_from_outputs = true'
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{wallet.getnewaddress(address_type="bech32"): 29}], options=options)
+
+ # Second case, don't use 'subtract_fee_from_outputs'
+ del options["subtract_fee_from_outputs"]
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{wallet.getnewaddress(address_type="bech32"): 29}], options=options)
+
+ self.nodes[2].unloadwallet("test_preset_inputs_selection")
+
def test_weight_calculation(self):
self.log.info("Test weight calculation with external inputs")
@@ -1338,6 +1404,66 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = w.createrawtransaction(inputs=[], outputs=[{self.nodes[0].getnewaddress(address_type="bech32"): 1 - 0.00000202}])
assert_raises_rpc_error(-4, "Insufficient funds", w.fundrawtransaction, rawtx, {"fee_rate": 1.85})
+ def test_input_confs_control(self):
+ self.nodes[0].createwallet("minconf")
+ wallet = self.nodes[0].get_wallet_rpc("minconf")
+
+ # Fund the wallet with different chain heights
+ for _ in range(2):
+ self.nodes[2].sendmany("", {wallet.getnewaddress():1, wallet.getnewaddress():1})
+ self.generate(self.nodes[2], 1)
+
+ unconfirmed_txid = wallet.sendtoaddress(wallet.getnewaddress(), 0.5)
+
+ self.log.info("Crafting TX using an unconfirmed input")
+ target_address = self.nodes[2].getnewaddress()
+ raw_tx1 = wallet.createrawtransaction([], {target_address: 0.1}, 0, True)
+ funded_tx1 = wallet.fundrawtransaction(raw_tx1, {'fee_rate': 1, 'maxconf': 0})['hex']
+
+ # Make sure we only had the one input
+ tx1_inputs = self.nodes[0].decoderawtransaction(funded_tx1)['vin']
+ assert_equal(len(tx1_inputs), 1)
+
+ utxo1 = tx1_inputs[0]
+ assert unconfirmed_txid == utxo1['txid']
+
+ final_tx1 = wallet.signrawtransactionwithwallet(funded_tx1)['hex']
+ txid1 = self.nodes[0].sendrawtransaction(final_tx1)
+
+ mempool = self.nodes[0].getrawmempool()
+ assert txid1 in mempool
+
+ self.log.info("Fail to craft a new TX with minconf above highest one")
+ # Create a replacement tx to 'final_tx1' that has 1 BTC target instead of 0.1.
+ raw_tx2 = wallet.createrawtransaction([{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1})
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, raw_tx2, {'add_inputs': True, 'minconf': 3, 'fee_rate': 10})
+
+ self.log.info("Fail to broadcast a new TX with maxconf 0 due to BIP125 rules to verify it actually chose unconfirmed outputs")
+ # Now fund 'raw_tx2' to fulfill the total target (1 BTC) by using all the wallet unconfirmed outputs.
+ # As it was created with the first unconfirmed output, 'raw_tx2' only has 0.1 BTC covered (need to fund 0.9 BTC more).
+ # So, the selection process, to cover the amount, will pick up the 'final_tx1' output as well, which is an output of the tx that this
+ # new tx is replacing!. So, once we send it to the mempool, it will return a "bad-txns-spends-conflicting-tx"
+ # because the input will no longer exist once the first tx gets replaced by this new one).
+ funded_invalid = wallet.fundrawtransaction(raw_tx2, {'add_inputs': True, 'maxconf': 0, 'fee_rate': 10})['hex']
+ final_invalid = wallet.signrawtransactionwithwallet(funded_invalid)['hex']
+ assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, final_invalid)
+
+ self.log.info("Craft a replacement adding inputs with highest depth possible")
+ funded_tx2 = wallet.fundrawtransaction(raw_tx2, {'add_inputs': True, 'minconf': 2, 'fee_rate': 10})['hex']
+ tx2_inputs = self.nodes[0].decoderawtransaction(funded_tx2)['vin']
+ assert_greater_than_or_equal(len(tx2_inputs), 2)
+ for vin in tx2_inputs:
+ if vin['txid'] != unconfirmed_txid:
+ assert_greater_than_or_equal(self.nodes[0].gettxout(vin['txid'], vin['vout'])['confirmations'], 2)
+
+ final_tx2 = wallet.signrawtransactionwithwallet(funded_tx2)['hex']
+ txid2 = self.nodes[0].sendrawtransaction(final_tx2)
+
+ mempool = self.nodes[0].getrawmempool()
+ assert txid1 not in mempool
+ assert txid2 in mempool
+
+ wallet.unloadwallet()
if __name__ == '__main__':
RawTransactionsTest().main()
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
index e5e4cf03bf..bdb9081261 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 wallet group functionality."""
@@ -16,6 +16,9 @@ from test_framework.util import (
class WalletGroupTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 5
@@ -38,6 +41,11 @@ class WalletGroupTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Setting up")
+ # To take full use of immediate tx relay, all nodes need to be reachable
+ # via inbound peers, i.e. connect first to last to close the circle
+ # (the default test network topology looks like this:
+ # node0 <-- node1 <-- node2 <-- node3 <-- node4 <-- node5)
+ self.connect_nodes(0, self.num_nodes - 1)
# Mine some coins
self.generate(self.nodes[0], COINBASE_MATURITY + 1)
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index 220c856498..0f79df6e5d 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 Hierarchical Deterministic wallet function."""
@@ -16,6 +16,9 @@ from test_framework.util import (
class WalletHDTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
diff --git a/test/functional/wallet_implicitsegwit.py b/test/functional/wallet_implicitsegwit.py
index a8583e2879..baa9bafb00 100755
--- a/test/functional/wallet_implicitsegwit.py
+++ b/test/functional/wallet_implicitsegwit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 implicit segwit feature."""
@@ -36,9 +36,12 @@ def check_implicit_transactions(implicit_keys, implicit_node):
pubkey = implicit_keys[a]
for b in address_types:
b_address = key_to_address(pubkey, b)
- assert(('receive', b_address) in tuple((tx['category'], tx['address']) for tx in txs))
+ assert ('receive', b_address) in tuple((tx['category'], tx['address']) for tx in txs)
class ImplicitSegwitTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=False)
+
def set_test_params(self):
self.num_nodes = 2
self.supports_cli = False
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index 085ad51c79..211e939a39 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 wallet import RPCs.
@@ -147,6 +147,9 @@ def get_rand_amount():
class ImportRescanTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=False)
+
def set_test_params(self):
self.num_nodes = 2 + len(IMPORT_NODES)
self.supports_cli = False
@@ -176,7 +179,16 @@ class ImportRescanTest(BitcoinTestFramework):
# Create one transaction on node 0 with a unique amount for
# each possible type of wallet import RPC.
+ last_variants = []
for i, variant in enumerate(IMPORT_VARIANTS):
+ if i % 10 == 0:
+ blockhash = self.generate(self.nodes[0], 1)[0]
+ conf_height = self.nodes[0].getblockcount()
+ timestamp = self.nodes[0].getblockheader(blockhash)["time"]
+ for var in last_variants:
+ var.confirmation_height = conf_height
+ var.timestamp = timestamp
+ last_variants.clear()
variant.label = "label {} {}".format(i, variant)
variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(
label=variant.label,
@@ -185,9 +197,15 @@ class ImportRescanTest(BitcoinTestFramework):
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
variant.initial_amount = get_rand_amount()
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
- self.generate(self.nodes[0], 1) # Generate one block for each send
- variant.confirmation_height = self.nodes[0].getblockcount()
- variant.timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"]
+ last_variants.append(variant)
+
+ blockhash = self.generate(self.nodes[0], 1)[0]
+ conf_height = self.nodes[0].getblockcount()
+ timestamp = self.nodes[0].getblockheader(blockhash)["time"]
+ for var in last_variants:
+ var.confirmation_height = conf_height
+ var.timestamp = timestamp
+ last_variants.clear()
# Generate a block further in the future (past the rescan window).
assert_equal(self.nodes[0].getrawmempool(), [])
@@ -214,11 +232,14 @@ class ImportRescanTest(BitcoinTestFramework):
variant.check()
# Create new transactions sending to each address.
- for variant in IMPORT_VARIANTS:
+ for i, variant in enumerate(IMPORT_VARIANTS):
+ if i % 10 == 0:
+ blockhash = self.generate(self.nodes[0], 1)[0]
+ conf_height = self.nodes[0].getblockcount() + 1
variant.sent_amount = get_rand_amount()
variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
- self.generate(self.nodes[0], 1) # Generate one block for each send
- variant.confirmation_height = self.nodes[0].getblockcount()
+ variant.confirmation_height = conf_height
+ self.generate(self.nodes[0], 1)
assert_equal(self.nodes[0].getrawmempool(), [])
self.sync_all()
diff --git a/test/functional/wallet_import_with_label.py b/test/functional/wallet_import_with_label.py
index 6a9d2e8290..0a1fc31ebc 100755
--- a/test/functional/wallet_import_with_label.py
+++ b/test/functional/wallet_import_with_label.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 behavior of RPC importprivkey on set and unset labels of
@@ -15,6 +15,9 @@ from test_framework.wallet_util import test_address
class ImportWithLabel(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=False)
+
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py
index 9744009af8..b4f20f0344 100755
--- a/test/functional/wallet_importdescriptors.py
+++ b/test/functional/wallet_importdescriptors.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 importdescriptors RPC.
@@ -15,7 +15,9 @@ variants.
- `test_address()` is called to call getaddressinfo for an address on node1
and test the values returned."""
-from test_framework.address import key_to_p2pkh
+import threading
+
+from test_framework.authproxy import JSONRPCException
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.descriptors import descsum_create
@@ -30,6 +32,9 @@ from test_framework.wallet_util import (
)
class ImportDescriptorsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [["-addresstype=legacy"],
@@ -117,12 +122,11 @@ class ImportDescriptorsTest(BitcoinTestFramework):
self.log.info("Internal addresses should be detected as such")
key = get_generate_key()
- addr = key_to_p2pkh(key.pubkey)
self.test_importdesc({"desc": descsum_create("pkh(" + key.pubkey + ")"),
"timestamp": "now",
"internal": True},
success=True)
- info = w1.getaddressinfo(addr)
+ info = w1.getaddressinfo(key.p2pkh_addr)
assert_equal(info["ismine"], True)
assert_equal(info["ischange"], True)
@@ -447,14 +451,14 @@ class ImportDescriptorsTest(BitcoinTestFramework):
wallet=wmulti_priv)
assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1001) # Range end (1000) is inclusive, so 1001 addresses generated
- addr = wmulti_priv.getnewaddress('', 'bech32')
+ addr = wmulti_priv.getnewaddress('', 'bech32') # uses receive 0
assert_equal(addr, 'bcrt1qdt0qy5p7dzhxzmegnn4ulzhard33s2809arjqgjndx87rv5vd0fq2czhy8') # Derived at m/84'/0'/0'/0
- change_addr = wmulti_priv.getrawchangeaddress('bech32')
- assert_equal(change_addr, 'bcrt1qt9uhe3a9hnq7vajl7a094z4s3crm9ttf8zw3f5v9gr2nyd7e3lnsy44n8e')
+ change_addr = wmulti_priv.getrawchangeaddress('bech32') # uses change 0
+ assert_equal(change_addr, 'bcrt1qt9uhe3a9hnq7vajl7a094z4s3crm9ttf8zw3f5v9gr2nyd7e3lnsy44n8e') # Derived at m/84'/1'/0'/0
assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1000)
txid = w0.sendtoaddress(addr, 10)
self.generate(self.nodes[0], 6)
- send_txid = wmulti_priv.sendtoaddress(w0.getnewaddress(), 8)
+ send_txid = wmulti_priv.sendtoaddress(w0.getnewaddress(), 8) # uses change 1
decoded = wmulti_priv.gettransaction(txid=send_txid, verbose=True)['decoded']
assert_equal(len(decoded['vin'][0]['txinwitness']), 4)
self.sync_all()
@@ -480,12 +484,12 @@ class ImportDescriptorsTest(BitcoinTestFramework):
wallet=wmulti_pub)
assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 1000) # The first one was already consumed by previous import and is detected as used
- addr = wmulti_pub.getnewaddress('', 'bech32')
+ addr = wmulti_pub.getnewaddress('', 'bech32') # uses receive 1
assert_equal(addr, 'bcrt1qp8s25ckjl7gr6x2q3dx3tn2pytwp05upkjztk6ey857tt50r5aeqn6mvr9') # Derived at m/84'/0'/0'/1
- change_addr = wmulti_pub.getrawchangeaddress('bech32')
- assert_equal(change_addr, 'bcrt1qzxl0qz2t88kljdnkzg4n4gapr6kte26390gttrg79x66nt4p04fssj53nl')
- assert(send_txid in self.nodes[0].getrawmempool(True))
- assert(send_txid in (x['txid'] for x in wmulti_pub.listunspent(0)))
+ change_addr = wmulti_pub.getrawchangeaddress('bech32') # uses change 2
+ assert_equal(change_addr, 'bcrt1qp6j3jw8yetefte7kw6v5pc89rkgakzy98p6gf7ayslaveaxqyjusnw580c') # Derived at m/84'/1'/0'/2
+ assert send_txid in self.nodes[0].getrawmempool(True)
+ assert send_txid in (x['txid'] for x in wmulti_pub.listunspent(0))
assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 999)
# generate some utxos for next tests
@@ -666,5 +670,48 @@ class ImportDescriptorsTest(BitcoinTestFramework):
success=True,
warnings=["Unknown output type, cannot set descriptor to active."])
+ self.log.info("Test importing a descriptor to an encrypted wallet")
+
+ descriptor = {"desc": descsum_create("pkh(" + xpriv + "/1h/*h)"),
+ "timestamp": "now",
+ "active": True,
+ "range": [0,4000],
+ "next_index": 4000}
+
+ self.nodes[0].createwallet("temp_wallet", blank=True, descriptors=True)
+ temp_wallet = self.nodes[0].get_wallet_rpc("temp_wallet")
+ temp_wallet.importdescriptors([descriptor])
+ self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, temp_wallet.getnewaddress())
+ self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, temp_wallet.getnewaddress())
+
+ self.nodes[0].createwallet("encrypted_wallet", blank=True, descriptors=True, passphrase="passphrase")
+ encrypted_wallet = self.nodes[0].get_wallet_rpc("encrypted_wallet")
+
+ descriptor["timestamp"] = 0
+ descriptor["next_index"] = 0
+
+ encrypted_wallet.walletpassphrase("passphrase", 99999)
+ t = threading.Thread(target=encrypted_wallet.importdescriptors, args=([descriptor],))
+
+ with self.nodes[0].assert_debug_log(expected_msgs=[f'Rescan started from block 0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206... (slow variant inspecting all blocks)'], timeout=5):
+ t.start()
+
+ # Set the passphrase timeout to 1 to test that the wallet remains unlocked during the rescan
+ self.nodes[0].cli("-rpcwallet=encrypted_wallet").walletpassphrase("passphrase", 1)
+
+ try:
+ self.nodes[0].cli("-rpcwallet=encrypted_wallet").walletlock()
+ except JSONRPCException as e:
+ assert e.error['code'] == -4 and "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before locking the wallet." in e.error['message']
+
+ try:
+ self.nodes[0].cli("-rpcwallet=encrypted_wallet").walletpassphrasechange("passphrase", "newpassphrase")
+ except JSONRPCException as e:
+ assert e.error['code'] == -4 and "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before changing the passphrase." in e.error['message']
+
+ t.join()
+
+ assert_equal(temp_wallet.getbalance(), encrypted_wallet.getbalance())
+
if __name__ == '__main__':
ImportDescriptorsTest().main()
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index 62a1a3341d..31013f6323 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 importmulti RPC.
@@ -35,6 +35,9 @@ from test_framework.wallet_util import (
class ImportMultiTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=False)
+
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"]]
diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py
index 2a4d0981c7..77b407579f 100755
--- a/test/functional/wallet_importprunedfunds.py
+++ b/test/functional/wallet_importprunedfunds.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 importprunedfunds and removeprunedfunds RPCs."""
@@ -21,6 +21,9 @@ from test_framework.wallet_util import bytes_to_wif
class ImportPrunedFundsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
diff --git a/test/functional/wallet_inactive_hdchains.py b/test/functional/wallet_inactive_hdchains.py
index e1dad00876..c0b3fea1c0 100755
--- a/test/functional/wallet_inactive_hdchains.py
+++ b/test/functional/wallet_inactive_hdchains.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
@@ -17,6 +17,9 @@ from test_framework.wallet_util import (
class InactiveHDChainsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=False)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index 54c47511a9..bd97851153 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 keypool and interaction with wallet encryption/locking."""
@@ -11,6 +11,9 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
class KeyPoolTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
@@ -201,6 +204,9 @@ class KeyPoolTest(BitcoinTestFramework):
res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010, "changeAddress": addr.pop()})
assert_equal("psbt" in res, True)
+ if not self.options.descriptors:
+ msg = "Error: Private keys are disabled for this wallet"
+ assert_raises_rpc_error(-4, msg, w2.keypoolrefill, 100)
if __name__ == '__main__':
KeyPoolTest().main()
diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py
index 4c965b7160..18c3ae1f7c 100755
--- a/test/functional/wallet_keypool_topup.py
+++ b/test/functional/wallet_keypool_topup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 HD Wallet keypool restore function.
@@ -21,6 +21,9 @@ from test_framework.util import (
class KeypoolRestoreTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 4
diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py
index c29b02e661..a39700f73a 100755
--- a/test/functional/wallet_labels.py
+++ b/test/functional/wallet_labels.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 label RPCs.
@@ -18,13 +18,54 @@ from test_framework.wallet_util import test_address
class WalletLabelsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
- self.num_nodes = 1
+ self.num_nodes = 2
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
+ def invalid_label_name_test(self):
+ node = self.nodes[0]
+ address = node.getnewaddress()
+ pubkey = node.getaddressinfo(address)['pubkey']
+ rpc_calls = [
+ [node.getnewaddress],
+ [node.setlabel, address],
+ [node.getaddressesbylabel],
+ [node.importpubkey, pubkey],
+ [node.addmultisigaddress, 1, [pubkey]],
+ [node.getreceivedbylabel],
+ [node.listsinceblock, node.getblockhash(0), 1, False, True, False],
+ ]
+ if self.options.descriptors:
+ response = node.importdescriptors([{
+ 'desc': f'pkh({pubkey})',
+ 'label': '*',
+ 'timestamp': 'now',
+ }])
+ else:
+ rpc_calls.extend([
+ [node.importprivkey, node.dumpprivkey(address)],
+ [node.importaddress, address],
+ ])
+
+ response = node.importmulti([{
+ 'scriptPubKey': {'address': address},
+ 'label': '*',
+ 'timestamp': 'now',
+ }])
+
+ assert_equal(response[0]['success'], False)
+ assert_equal(response[0]['error']['code'], -11)
+ assert_equal(response[0]['error']['message'], "Invalid label name")
+
+ for rpc_call in rpc_calls:
+ assert_raises_rpc_error(-11, "Invalid label name", *rpc_call, "*")
+
def run_test(self):
# Check that there's no UTXO on the node
node = self.nodes[0]
@@ -80,8 +121,14 @@ class WalletLabelsTest(BitcoinTestFramework):
label.add_receive_address(address)
label.verify(node)
+ # Check listlabels when passing 'purpose'
+ node2_addr = self.nodes[1].getnewaddress()
+ node.setlabel(node2_addr, "node2_addr")
+ assert_equal(node.listlabels(purpose="send"), ["node2_addr"])
+ assert_equal(node.listlabels(purpose="receive"), sorted(['coinbase'] + [label.name for label in labels]))
+
# Check all labels are returned by listlabels.
- assert_equal(node.listlabels(), sorted(['coinbase'] + [label.name for label in labels]))
+ assert_equal(node.listlabels(), sorted(['coinbase'] + [label.name for label in labels] + ["node2_addr"]))
# Send a transaction to each label.
for label in labels:
@@ -135,6 +182,8 @@ class WalletLabelsTest(BitcoinTestFramework):
# in the label. This is a no-op.
change_label(node, labels[2].addresses[0], labels[2], labels[2])
+ self.invalid_label_name_test()
+
if self.options.descriptors:
# This is a descriptor wallet test because of segwit v1+ addresses
self.log.info('Check watchonly labels')
diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py
index d5372f5aee..c5479089c6 100755
--- a/test/functional/wallet_listdescriptors.py
+++ b/test/functional/wallet_listdescriptors.py
@@ -1,11 +1,14 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 listdescriptors RPC."""
+from test_framework.blocktools import (
+ TIME_GENESIS_BLOCK,
+)
from test_framework.descriptors import (
- descsum_create
+ descsum_create,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -15,6 +18,9 @@ from test_framework.util import (
class ListDescriptorsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
def set_test_params(self):
self.num_nodes = 1
@@ -48,7 +54,7 @@ class ListDescriptorsTest(BitcoinTestFramework):
assert_equal(4, len([d for d in result['descriptors'] if d['internal']]))
for item in result['descriptors']:
assert item['desc'] != ''
- assert item['next'] == 0
+ assert item['next_index'] == 0
assert item['range'] == [0, 0]
assert item['timestamp'] is not None
@@ -63,16 +69,17 @@ class ListDescriptorsTest(BitcoinTestFramework):
wallet = node.get_wallet_rpc('w2')
wallet.importdescriptors([{
'desc': descsum_create('wpkh(' + xprv + hardened_path + '/0/*)'),
- 'timestamp': 1296688602,
+ 'timestamp': TIME_GENESIS_BLOCK,
}])
expected = {
'wallet_name': 'w2',
'descriptors': [
{'desc': descsum_create('wpkh([80002067' + hardened_path + ']' + xpub_acc + '/0/*)'),
- 'timestamp': 1296688602,
+ 'timestamp': TIME_GENESIS_BLOCK,
'active': False,
'range': [0, 0],
- 'next': 0},
+ 'next': 0,
+ 'next_index': 0},
],
}
assert_equal(expected, wallet.listdescriptors())
@@ -83,10 +90,11 @@ class ListDescriptorsTest(BitcoinTestFramework):
'wallet_name': 'w2',
'descriptors': [
{'desc': descsum_create('wpkh(' + xprv + hardened_path + '/0/*)'),
- 'timestamp': 1296688602,
+ 'timestamp': TIME_GENESIS_BLOCK,
'active': False,
'range': [0, 0],
- 'next': 0},
+ 'next': 0,
+ 'next_index': 0},
],
}
assert_equal(expected_private, wallet.listdescriptors(True))
@@ -105,7 +113,7 @@ class ListDescriptorsTest(BitcoinTestFramework):
watch_only_wallet = node.get_wallet_rpc('watch-only')
watch_only_wallet.importdescriptors([{
'desc': descsum_create('wpkh(' + xpub_acc + ')'),
- 'timestamp': 1296688602,
+ 'timestamp': TIME_GENESIS_BLOCK,
}])
assert_raises_rpc_error(-4, 'Can\'t get descriptor string', watch_only_wallet.listdescriptors, True)
@@ -114,14 +122,14 @@ class ListDescriptorsTest(BitcoinTestFramework):
wallet = node.get_wallet_rpc('w4')
wallet.importdescriptors([{
'desc': descsum_create('combo(' + node.get_deterministic_priv_key().key + ')'),
- 'timestamp': 1296688602,
+ 'timestamp': TIME_GENESIS_BLOCK,
}])
expected = {
'wallet_name': 'w4',
'descriptors': [
{'active': False,
'desc': 'combo(0227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3f)#np574htj',
- 'timestamp': 1296688602},
+ 'timestamp': TIME_GENESIS_BLOCK},
]
}
assert_equal(expected, wallet.listdescriptors())
diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py
index f1d7de2f27..8ec21484d1 100755
--- a/test/functional/wallet_listreceivedby.py
+++ b/test/functional/wallet_listreceivedby.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 listreceivedbyaddress, listreceivedbylabel, getreceivedybaddress, and getreceivedbylabel RPCs."""
@@ -16,6 +16,9 @@ from test_framework.wallet_util import test_address
class ReceivedByTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
# whitelist peers to speed up tx relay / mempool sync
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index f259449bef..bfca344fd1 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 listsinceblock RPC."""
@@ -20,6 +20,9 @@ from test_framework.wallet_util import bytes_to_wif
from decimal import Decimal
class ListSinceBlockTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 4
self.setup_clean_chain = True
@@ -45,6 +48,8 @@ class ListSinceBlockTest(BitcoinTestFramework):
if self.options.descriptors:
self.test_desc()
self.test_send_to_self()
+ self.test_op_return()
+ self.test_label()
def test_no_blockhash(self):
self.log.info("Test no blockhash")
@@ -448,6 +453,33 @@ class ListSinceBlockTest(BitcoinTestFramework):
assert any(c["address"] == addr for c in coins)
assert all(self.nodes[2].getaddressinfo(c["address"])["ischange"] for c in coins)
+ def test_op_return(self):
+ """Test if OP_RETURN outputs will be displayed correctly."""
+ block_hash = self.nodes[2].getbestblockhash()
+
+ raw_tx = self.nodes[2].createrawtransaction([], [{'data': 'aa'}])
+ funded_tx = self.nodes[2].fundrawtransaction(raw_tx)
+ signed_tx = self.nodes[2].signrawtransactionwithwallet(funded_tx['hex'])
+ tx_id = self.nodes[2].sendrawtransaction(signed_tx['hex'])
+
+ op_ret_tx = [tx for tx in self.nodes[2].listsinceblock(blockhash=block_hash)["transactions"] if tx['txid'] == tx_id][0]
+
+ assert 'address' not in op_ret_tx
+
+ def test_label(self):
+ self.log.info('Test passing "label" argument fetches incoming transactions having the specified label')
+ new_addr = self.nodes[1].getnewaddress(label="new_addr", address_type="bech32")
+
+ self.nodes[2].sendtoaddress(address=new_addr, amount="0.001")
+ self.generate(self.nodes[2], 1)
+
+ for label in ["new_addr", ""]:
+ new_addr_transactions = self.nodes[1].listsinceblock(label=label)["transactions"]
+ assert_equal(len(new_addr_transactions), 1)
+ assert_equal(new_addr_transactions[0]["label"], label)
+ if label == "new_addr":
+ assert_equal(new_addr_transactions[0]["address"], new_addr)
+
if __name__ == '__main__':
ListSinceBlockTest().main()
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 7c16b6328d..a44c129c87 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 listtransactions API."""
@@ -21,6 +21,9 @@ from test_framework.util import (
class ListTransactionsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 3
# This test isn't testing txn relay/timing, so set whitelist on the
@@ -109,6 +112,7 @@ class ListTransactionsTest(BitcoinTestFramework):
self.run_rbf_opt_in_test()
self.run_externally_generated_address_test()
self.run_invalid_parameters_test()
+ self.test_op_return()
def run_rbf_opt_in_test(self):
"""Test the opt-in-rbf flag for sent and received transactions."""
@@ -284,6 +288,17 @@ class ListTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Negative count", self.nodes[0].listtransactions, count=-1)
assert_raises_rpc_error(-8, "Negative from", self.nodes[0].listtransactions, skip=-1)
+ def test_op_return(self):
+ """Test if OP_RETURN outputs will be displayed correctly."""
+ raw_tx = self.nodes[0].createrawtransaction([], [{'data': 'aa'}])
+ funded_tx = self.nodes[0].fundrawtransaction(raw_tx)
+ signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
+ tx_id = self.nodes[0].sendrawtransaction(signed_tx['hex'])
+
+ op_ret_tx = [tx for tx in self.nodes[0].listtransactions() if tx['txid'] == tx_id][0]
+
+ assert 'address' not in op_ret_tx
+
if __name__ == '__main__':
ListTransactionsTest().main()
diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py
index 3c1cb6ac32..7c2959bb89 100755
--- a/test/functional/wallet_migration.py
+++ b/test/functional/wallet_migration.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 Migrating a wallet from legacy to descriptor."""
@@ -19,6 +19,9 @@ from test_framework.wallet_util import (
class WalletMigrationTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
@@ -37,11 +40,13 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_equal(file_magic, b'SQLite format 3\x00')
assert_equal(self.nodes[0].get_wallet_rpc(wallet_name).getwalletinfo()["format"], "sqlite")
- def create_legacy_wallet(self, wallet_name):
- self.nodes[0].createwallet(wallet_name=wallet_name)
+ def create_legacy_wallet(self, wallet_name, disable_private_keys=False):
+ self.nodes[0].createwallet(wallet_name=wallet_name, descriptors=False, disable_private_keys=disable_private_keys)
wallet = self.nodes[0].get_wallet_rpc(wallet_name)
- assert_equal(wallet.getwalletinfo()["descriptors"], False)
- assert_equal(wallet.getwalletinfo()["format"], "bdb")
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["format"], "bdb")
+ assert_equal(info["private_keys_enabled"], not disable_private_keys)
return wallet
def assert_addr_info_equal(self, addr_info, addr_info_old):
@@ -158,6 +163,10 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_equal(basic2.getbalance(), basic2_balance)
self.assert_list_txs_equal(basic2.listtransactions(), basic2_txs)
+ # Now test migration on a descriptor wallet
+ self.log.info("Test \"nothing to migrate\" when the user tries to migrate a wallet with no legacy data")
+ assert_raises_rpc_error(-4, "Error: This wallet is already a descriptor wallet", basic2.migratewallet)
+
def test_multisig(self):
default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
@@ -184,11 +193,9 @@ class WalletMigrationTest(BitcoinTestFramework):
# Some keys in multisig do not belong to this wallet
self.log.info("Test migration of a wallet that has some keys in a multisig")
- self.nodes[0].createwallet(wallet_name="multisig1")
- multisig1 = self.nodes[0].get_wallet_rpc("multisig1")
+ multisig1 = self.create_legacy_wallet("multisig1")
ms_info = multisig1.addmultisigaddress(2, [multisig1.getnewaddress(), pub1, pub2])
ms_info2 = multisig1.addmultisigaddress(2, [multisig1.getnewaddress(), pub1, pub2])
- assert_equal(multisig1.getwalletinfo()["descriptors"], False)
addr1 = ms_info["address"]
addr2 = ms_info2["address"]
@@ -253,11 +260,9 @@ class WalletMigrationTest(BitcoinTestFramework):
# Wallet with an imported address. Should be the same thing as the multisig test
self.log.info("Test migration of a wallet with watchonly imports")
- self.nodes[0].createwallet(wallet_name="imports0")
- imports0 = self.nodes[0].get_wallet_rpc("imports0")
- assert_equal(imports0.getwalletinfo()["descriptors"], False)
+ imports0 = self.create_legacy_wallet("imports0")
- # Exteranl address label
+ # External address label
imports0.setlabel(default.getnewaddress(), "external")
# Normal non-watchonly tx
@@ -310,16 +315,19 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", watchonly.gettransaction, received_txid)
assert_equal(len(watchonly.listtransactions(include_watchonly=True)), 3)
+ # Check that labels were migrated and persisted to watchonly wallet
+ self.nodes[0].unloadwallet("imports0_watchonly")
+ self.nodes[0].loadwallet("imports0_watchonly")
+ labels = watchonly.listlabels()
+ assert "external" in labels
+ assert "imported" in labels
+
def test_no_privkeys(self):
default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
# Migrating an actual watchonly wallet should not create a new watchonly wallet
self.log.info("Test migration of a pure watchonly wallet")
- self.nodes[0].createwallet(wallet_name="watchonly0", disable_private_keys=True)
- watchonly0 = self.nodes[0].get_wallet_rpc("watchonly0")
- info = watchonly0.getwalletinfo()
- assert_equal(info["descriptors"], False)
- assert_equal(info["private_keys_enabled"], False)
+ watchonly0 = self.create_legacy_wallet("watchonly0", disable_private_keys=True)
addr = default.getnewaddress()
desc = default.getaddressinfo(addr)["desc"]
@@ -342,11 +350,7 @@ class WalletMigrationTest(BitcoinTestFramework):
# Migrating a wallet with pubkeys added to the keypool
self.log.info("Test migration of a pure watchonly wallet with pubkeys in keypool")
- self.nodes[0].createwallet(wallet_name="watchonly1", disable_private_keys=True)
- watchonly1 = self.nodes[0].get_wallet_rpc("watchonly1")
- info = watchonly1.getwalletinfo()
- assert_equal(info["descriptors"], False)
- assert_equal(info["private_keys_enabled"], False)
+ watchonly1 = self.create_legacy_wallet("watchonly1", disable_private_keys=True)
addr1 = default.getnewaddress(address_type="bech32")
addr2 = default.getnewaddress(address_type="bech32")
@@ -393,6 +397,79 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_equal(bals, wallet.getbalances())
+ def test_encrypted(self):
+ self.log.info("Test migration of an encrypted wallet")
+ wallet = self.create_legacy_wallet("encrypted")
+ default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ wallet.encryptwallet("pass")
+ addr = wallet.getnewaddress()
+ txid = default.sendtoaddress(addr, 1)
+ self.generate(self.nodes[0], 1)
+ bals = wallet.getbalances()
+
+ assert_raises_rpc_error(-4, "Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect", wallet.migratewallet)
+ assert_raises_rpc_error(-4, "Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect", wallet.migratewallet, None, "badpass")
+ assert_raises_rpc_error(-4, "The passphrase contains a null character", wallet.migratewallet, None, "pass\0with\0null")
+
+ wallet.migratewallet(passphrase="pass")
+
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["format"], "sqlite")
+ assert_equal(info["unlocked_until"], 0)
+ wallet.gettransaction(txid)
+
+ assert_equal(bals, wallet.getbalances())
+
+ def test_unloaded(self):
+ self.log.info("Test migration of a wallet that isn't loaded")
+ wallet = self.create_legacy_wallet("notloaded")
+ default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ addr = wallet.getnewaddress()
+ txid = default.sendtoaddress(addr, 1)
+ self.generate(self.nodes[0], 1)
+ bals = wallet.getbalances()
+
+ wallet.unloadwallet()
+
+ assert_raises_rpc_error(-8, "RPC endpoint wallet and wallet_name parameter specify different wallets", wallet.migratewallet, "someotherwallet")
+ assert_raises_rpc_error(-8, "Either RPC endpoint wallet or wallet_name parameter must be provided", self.nodes[0].migratewallet)
+ self.nodes[0].migratewallet("notloaded")
+
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["format"], "sqlite")
+ wallet.gettransaction(txid)
+
+ assert_equal(bals, wallet.getbalances())
+
+ def test_unloaded_by_path(self):
+ self.log.info("Test migration of a wallet that isn't loaded, specified by path")
+ wallet = self.create_legacy_wallet("notloaded2")
+ default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ addr = wallet.getnewaddress()
+ txid = default.sendtoaddress(addr, 1)
+ self.generate(self.nodes[0], 1)
+ bals = wallet.getbalances()
+
+ wallet.unloadwallet()
+
+ wallet_file_path = os.path.join(self.nodes[0].datadir, "regtest", "wallets", "notloaded2")
+ self.nodes[0].migratewallet(wallet_file_path)
+
+ # Because we gave the name by full path, the loaded wallet's name is that path too.
+ wallet = self.nodes[0].get_wallet_rpc(wallet_file_path)
+
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["format"], "sqlite")
+ wallet.gettransaction(txid)
+
+ assert_equal(bals, wallet.getbalances())
+
def run_test(self):
self.generate(self.nodes[0], 101)
@@ -402,6 +479,9 @@ class WalletMigrationTest(BitcoinTestFramework):
self.test_other_watchonly()
self.test_no_privkeys()
self.test_pk_coinbases()
+ self.test_encrypted()
+ self.test_unloaded()
+ self.test_unloaded_by_path()
if __name__ == '__main__':
WalletMigrationTest().main()
diff --git a/test/functional/wallet_miniscript.py b/test/functional/wallet_miniscript.py
index 2252f1e424..7bc3424bf4 100755
--- a/test/functional/wallet_miniscript.py
+++ b/test/functional/wallet_miniscript.py
@@ -5,23 +5,144 @@
"""Test Miniscript descriptors integration in the wallet."""
from test_framework.descriptors import descsum_create
+from test_framework.psbt import PSBT, PSBT_IN_SHA256
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
+TPRVS = [
+ "tprv8ZgxMBicQKsPerQj6m35no46amfKQdjY7AhLnmatHYXs8S4MTgeZYkWAn4edSGwwL3vkSiiGqSZQrmy5D3P5gBoqgvYP2fCUpBwbKTMTAkL",
+ "tprv8ZgxMBicQKsPd3cbrKjE5GKKJLDEidhtzSSmPVtSPyoHQGL2LZw49yt9foZsN9BeiC5VqRaESUSDV2PS9w7zAVBSK6EQH3CZW9sMKxSKDwD",
+ "tprv8iF7W37EHnVEtDr9EFeyFjQJFL6SfGby2AnZ2vQARxTQHQXy9tdzZvBBVp8a19e5vXhskczLkJ1AZjqgScqWL4FpmXVp8LLjiorcrFK63Sr",
+]
+TPUBS = [
+ "tpubD6NzVbkrYhZ4YPAbyf6urxqqnmJF79PzQtyERAmvkSVS9fweCTjxjDh22Z5St9fGb1a5DUCv8G27nYupKP1Ctr1pkamJossoetzws1moNRn",
+ "tpubD6NzVbkrYhZ4YMQC15JS7QcrsAyfGrGiykweqMmPxTkEVScu7vCZLNpPXW1XphHwzsgmqdHWDQAfucbM72EEB1ZEyfgZxYvkZjYVXx1xS9p",
+ "tpubD6NzVbkrYhZ4YU9vM1s53UhD75UyJatx8EMzMZ3VUjR2FciNfLLkAw6a4pWACChzobTseNqdWk4G7ZdBqRDLtLSACKykTScmqibb1ZrCvJu",
+ "tpubD6NzVbkrYhZ4XRMcMFMMFvzVt6jaDAtjZhD7JLwdPdMm9xa76DnxYYP7w9TZGJDVFkek3ArwVsuacheqqPog8TH5iBCX1wuig8PLXim4n9a",
+ "tpubD6NzVbkrYhZ4WsqRzDmkL82SWcu42JzUvKWzrJHQ8EC2vEHRHkXj1De93sD3biLrKd8XGnamXURGjMbYavbszVDXpjXV2cGUERucLJkE6cy",
+ "tpubDEFLeBkKTm8aiYkySz8hXAXPVnPSfxMi7Fxhg9sejUrkwJuRWvPdLEiXjTDbhGbjLKCZUDUUibLxTnK5UP1q7qYrSnPqnNe7M8mvAW1STcc",
+]
+PUBKEYS = [
+ "02aebf2d10b040eb936a6f02f44ee82f8b34f5c1ccb20ff3949c2b28206b7c1068",
+ "030f64b922aee2fd597f104bc6cb3b670f1ca2c6c49b1071a1a6c010575d94fe5a",
+ "02abe475b199ec3d62fa576faee16a334fdb86ffb26dce75becebaaedf328ac3fe",
+ "0314f3dc33595b0d016bb522f6fe3a67680723d842c1b9b8ae6b59fdd8ab5cccb4",
+ "025eba3305bd3c829e4e1551aac7358e4178832c739e4fc4729effe428de0398ab",
+ "029ffbe722b147f3035c87cb1c60b9a5947dd49c774cc31e94773478711a929ac0",
+ "0211c7b2e18b6fd330f322de087da62da92ae2ae3d0b7cec7e616479cce175f183",
+]
+
MINISCRIPTS = [
# One of two keys
- "or_b(pk(tpubD6NzVbkrYhZ4XRMcMFMMFvzVt6jaDAtjZhD7JLwdPdMm9xa76DnxYYP7w9TZGJDVFkek3ArwVsuacheqqPog8TH5iBCX1wuig8PLXim4n9a/*),s:pk(tpubD6NzVbkrYhZ4WsqRzDmkL82SWcu42JzUvKWzrJHQ8EC2vEHRHkXj1De93sD3biLrKd8XGnamXURGjMbYavbszVDXpjXV2cGUERucLJkE6cy/*))",
+ f"or_b(pk({TPUBS[0]}/*),s:pk({TPUBS[1]}/*))",
# A script similar (same spending policy) to BOLT3's offered HTLC (with anchor outputs)
- "or_d(pk(tpubD6NzVbkrYhZ4XRMcMFMMFvzVt6jaDAtjZhD7JLwdPdMm9xa76DnxYYP7w9TZGJDVFkek3ArwVsuacheqqPog8TH5iBCX1wuig8PLXim4n9a/*),and_v(and_v(v:pk(tpubD6NzVbkrYhZ4WsqRzDmkL82SWcu42JzUvKWzrJHQ8EC2vEHRHkXj1De93sD3biLrKd8XGnamXURGjMbYavbszVDXpjXV2cGUERucLJkE6cy/*),or_c(pk(tpubD6NzVbkrYhZ4YNwtTWrKRJQzQX3PjPKeUQg1gYh1hiLMkk1cw8SRLgB1yb7JzE8bHKNt6EcZXkJ6AqpCZL1aaRSjnG36mLgbQvJZBNsjWnG/*),v:hash160(7f999c905d5e35cefd0a37673f746eb13fba3640))),older(1)))",
+ f"or_d(pk({TPUBS[0]}/*),and_v(and_v(v:pk({TPUBS[1]}/*),or_c(pk({TPUBS[2]}/*),v:hash160(7f999c905d5e35cefd0a37673f746eb13fba3640))),older(1)))",
# A Revault Unvault policy with the older() replaced by an after()
- "andor(multi(2,tpubD6NzVbkrYhZ4YMQC15JS7QcrsAyfGrGiykweqMmPxTkEVScu7vCZLNpPXW1XphHwzsgmqdHWDQAfucbM72EEB1ZEyfgZxYvkZjYVXx1xS9p/*,tpubD6NzVbkrYhZ4WkCyc7E3z6g6NkypHMiecnwc4DpWHTPqFdteRGkEKukdrSSyJGNnGrHNMfy4BCw2UXo5soYRCtCDDfy4q8pc8oyB7RgTFv8/*),and_v(v:multi(4,030f64b922aee2fd597f104bc6cb3b670f1ca2c6c49b1071a1a6c010575d94fe5a,02abe475b199ec3d62fa576faee16a334fdb86ffb26dce75becebaaedf328ac3fe,0314f3dc33595b0d016bb522f6fe3a67680723d842c1b9b8ae6b59fdd8ab5cccb4,025eba3305bd3c829e4e1551aac7358e4178832c739e4fc4729effe428de0398ab),after(424242)),thresh(4,pkh(tpubD6NzVbkrYhZ4YVrNggiT2ptVHwnFbLBqDkCtV5HkxR4WtcRLAQReKTkqZGNcV6GE7cQsmpBzzSzhk16DUwB1gn1L7ZPnJF2dnNePP1uMBCY/*),a:pkh(tpubD6NzVbkrYhZ4YU9vM1s53UhD75UyJatx8EMzMZ3VUjR2FciNfLLkAw6a4pWACChzobTseNqdWk4G7ZdBqRDLtLSACKykTScmqibb1ZrCvJu/*),a:pkh(tpubD6NzVbkrYhZ4YUHcFfuH9iEBLiH8CBRJTpS7X3qjHmh82m1KCNbzs6w9gyK8oWHSZmKHWcakAXCGfbKg6xoCvKzQCWAHyxaC7QcWfmzyBf4/*),a:pkh(tpubD6NzVbkrYhZ4XXEmQtS3sgxpJbMyMg4McqRR1Af6ULzyrTRnhwjyr1etPD7svap9oFtJf4MM72brUb5o7uvF2Jyszc5c1t836fJW7SX2e8D/*)))",
+ f"andor(multi(2,{TPUBS[0]}/*,{TPUBS[1]}/*),and_v(v:multi(4,{PUBKEYS[0]},{PUBKEYS[1]},{PUBKEYS[2]},{PUBKEYS[3]}),after(424242)),thresh(4,pkh({TPUBS[2]}/*),a:pkh({TPUBS[3]}/*),a:pkh({TPUBS[4]}/*),a:pkh({TPUBS[5]}/*)))",
# Liquid-like federated pegin with emergency recovery keys
- "or_i(and_b(pk(029ffbe722b147f3035c87cb1c60b9a5947dd49c774cc31e94773478711a929ac0),a:and_b(pk(025f05815e3a1a8a83bfbb03ce016c9a2ee31066b98f567f6227df1d76ec4bd143),a:and_b(pk(025625f41e4a065efc06d5019cbbd56fe8c07595af1231e7cbc03fafb87ebb71ec),a:and_b(pk(02a27c8b850a00f67da3499b60562673dcf5fdfb82b7e17652a7ac54416812aefd),s:pk(03e618ec5f384d6e19ca9ebdb8e2119e5bef978285076828ce054e55c4daf473e2))))),and_v(v:thresh(2,pkh(tpubD6NzVbkrYhZ4YK67cd5fDe4fBVmGB2waTDrAt1q4ey9HPq9veHjWkw3VpbaCHCcWozjkhgAkWpFrxuPMUrmXVrLHMfEJ9auoZA6AS1g3grC/*),a:pkh(033841045a531e1adf9910a6ec279589a90b3b8a904ee64ffd692bd08a8996c1aa),a:pkh(02aebf2d10b040eb936a6f02f44ee82f8b34f5c1ccb20ff3949c2b28206b7c1068)),older(4209713)))",
+ f"or_i(and_b(pk({PUBKEYS[0]}),a:and_b(pk({PUBKEYS[1]}),a:and_b(pk({PUBKEYS[2]}),a:and_b(pk({PUBKEYS[3]}),s:pk({PUBKEYS[4]}))))),and_v(v:thresh(2,pkh({TPUBS[0]}/*),a:pkh({PUBKEYS[5]}),a:pkh({PUBKEYS[6]})),older(4209713)))",
+]
+
+MINISCRIPTS_PRIV = [
+ # One of two keys, of which one private key is known
+ {
+ "ms": f"or_i(pk({TPRVS[0]}/*),pk({TPUBS[0]}/*))",
+ "sequence": None,
+ "locktime": None,
+ "sigs_count": 1,
+ "stack_size": 3,
+ },
+ # A more complex policy, that can't be satisfied through the first branch (need for a preimage)
+ {
+ "ms": f"andor(ndv:older(2),and_v(v:pk({TPRVS[0]}),sha256(2a8ce30189b2ec3200b47aeb4feaac8fcad7c0ba170389729f4898b0b7933bcb)),and_v(v:pkh({TPRVS[1]}),pk({TPRVS[2]}/*)))",
+ "sequence": 2,
+ "locktime": None,
+ "sigs_count": 3,
+ "stack_size": 5,
+ },
+ # The same policy but we provide the preimage. This path will be chosen as it's a smaller witness.
+ {
+ "ms": f"andor(ndv:older(2),and_v(v:pk({TPRVS[0]}),sha256(61e33e9dbfefc45f6a194187684d278f789fd4d5e207a357e79971b6519a8b12)),and_v(v:pkh({TPRVS[1]}),pk({TPRVS[2]}/*)))",
+ "sequence": 2,
+ "locktime": None,
+ "sigs_count": 3,
+ "stack_size": 4,
+ "sha256_preimages": {
+ "61e33e9dbfefc45f6a194187684d278f789fd4d5e207a357e79971b6519a8b12": "e8774f330f5f330c23e8bbefc5595cb87009ddb7ac3b8deaaa8e9e41702d919c"
+ },
+ },
+ # Signature with a relative timelock
+ {
+ "ms": f"and_v(v:older(2),pk({TPRVS[0]}/*))",
+ "sequence": 2,
+ "locktime": None,
+ "sigs_count": 1,
+ "stack_size": 2,
+ },
+ # Signature with an absolute timelock
+ {
+ "ms": f"and_v(v:after(20),pk({TPRVS[0]}/*))",
+ "sequence": None,
+ "locktime": 20,
+ "sigs_count": 1,
+ "stack_size": 2,
+ },
+ # Signature with both
+ {
+ "ms": f"and_v(v:older(4),and_v(v:after(30),pk({TPRVS[0]}/*)))",
+ "sequence": 4,
+ "locktime": 30,
+ "sigs_count": 1,
+ "stack_size": 2,
+ },
+ # We have one key on each branch; Core signs both (can't finalize)
+ {
+ "ms": f"c:andor(pk({TPRVS[0]}/*),pk_k({TPUBS[0]}),and_v(v:pk({TPRVS[1]}),pk_k({TPUBS[1]})))",
+ "sequence": None,
+ "locktime": None,
+ "sigs_count": 2,
+ "stack_size": None,
+ },
+ # We have all the keys, wallet selects the timeout path to sign since it's smaller and sequence is set
+ {
+ "ms": f"andor(pk({TPRVS[0]}/*),pk({TPRVS[2]}),and_v(v:pk({TPRVS[1]}),older(10)))",
+ "sequence": 10,
+ "locktime": None,
+ "sigs_count": 3,
+ "stack_size": 3,
+ },
+ # We have all the keys, wallet selects the primary path to sign unconditionally since nsequence wasn't set to be valid for timeout path
+ {
+ "ms": f"andor(pk({TPRVS[0]}/*),pk({TPRVS[2]}),and_v(v:pkh({TPRVS[1]}),older(10)))",
+ "sequence": None,
+ "locktime": None,
+ "sigs_count": 3,
+ "stack_size": 3,
+ },
+ # Finalizes to the smallest valid witness, regardless of sequence
+ {
+ "ms": f"or_d(pk({TPRVS[0]}/*),and_v(v:pk({TPRVS[1]}),and_v(v:pk({TPRVS[2]}),older(10))))",
+ "sequence": 12,
+ "locktime": None,
+ "sigs_count": 3,
+ "stack_size": 2,
+ },
+ # Liquid-like federated pegin with emergency recovery privkeys
+ {
+ "ms": f"or_i(and_b(pk({TPUBS[0]}/*),a:and_b(pk({TPUBS[1]}),a:and_b(pk({TPUBS[2]}),a:and_b(pk({TPUBS[3]}),s:pk({PUBKEYS[0]}))))),and_v(v:thresh(2,pkh({TPRVS[0]}),a:pkh({TPRVS[1]}),a:pkh({TPUBS[4]})),older(42)))",
+ "sequence": 42,
+ "locktime": None,
+ "sigs_count": 2,
+ "stack_size": 8,
+ },
]
class WalletMiniscriptTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
def set_test_params(self):
self.num_nodes = 1
@@ -59,7 +180,77 @@ class WalletMiniscriptTest(BitcoinTestFramework):
lambda: len(self.ms_wo_wallet.listunspent(minconf=0, addresses=[addr])) == 1
)
utxo = self.ms_wo_wallet.listunspent(minconf=0, addresses=[addr])[0]
- assert utxo["txid"] == txid and not utxo["solvable"] # No satisfaction logic (yet)
+ assert utxo["txid"] == txid and utxo["solvable"]
+
+ def signing_test(
+ self, ms, sequence, locktime, sigs_count, stack_size, sha256_preimages
+ ):
+ self.log.info(f"Importing private Miniscript '{ms}'")
+ desc = descsum_create(f"wsh({ms})")
+ res = self.ms_sig_wallet.importdescriptors(
+ [
+ {
+ "desc": desc,
+ "active": True,
+ "range": 0,
+ "next_index": 0,
+ "timestamp": "now",
+ }
+ ]
+ )
+ assert res[0]["success"], res
+
+ self.log.info("Generating an address for it and testing it detects funds")
+ addr = self.ms_sig_wallet.getnewaddress()
+ txid = self.funder.sendtoaddress(addr, 0.01)
+ self.wait_until(lambda: txid in self.funder.getrawmempool())
+ self.funder.generatetoaddress(1, self.funder.getnewaddress())
+ utxo = self.ms_sig_wallet.listunspent(addresses=[addr])[0]
+ assert txid == utxo["txid"] and utxo["solvable"]
+
+ self.log.info("Creating a transaction spending these funds")
+ dest_addr = self.funder.getnewaddress()
+ seq = sequence if sequence is not None else 0xFFFFFFFF - 2
+ lt = locktime if locktime is not None else 0
+ psbt = self.ms_sig_wallet.createpsbt(
+ [
+ {
+ "txid": txid,
+ "vout": utxo["vout"],
+ "sequence": seq,
+ }
+ ],
+ [{dest_addr: 0.009}],
+ lt,
+ )
+
+ self.log.info("Signing it and checking the satisfaction.")
+ if sha256_preimages is not None:
+ psbt = PSBT.from_base64(psbt)
+ for (h, preimage) in sha256_preimages.items():
+ k = PSBT_IN_SHA256.to_bytes(1, "big") + bytes.fromhex(h)
+ psbt.i[0].map[k] = bytes.fromhex(preimage)
+ psbt = psbt.to_base64()
+ res = self.ms_sig_wallet.walletprocesspsbt(psbt=psbt, finalize=False)
+ psbtin = self.nodes[0].rpc.decodepsbt(res["psbt"])["inputs"][0]
+ assert len(psbtin["partial_signatures"]) == sigs_count
+ res = self.ms_sig_wallet.finalizepsbt(res["psbt"])
+ assert res["complete"] == (stack_size is not None)
+
+ if stack_size is not None:
+ txin = self.nodes[0].rpc.decoderawtransaction(res["hex"])["vin"][0]
+ assert len(txin["txinwitness"]) == stack_size, txin["txinwitness"]
+ self.log.info("Broadcasting the transaction.")
+ # If necessary, satisfy a relative timelock
+ if sequence is not None:
+ self.funder.generatetoaddress(sequence, self.funder.getnewaddress())
+ # If necessary, satisfy an absolute timelock
+ height = self.funder.getblockcount()
+ if locktime is not None and height < locktime:
+ self.funder.generatetoaddress(
+ locktime - height, self.funder.getnewaddress()
+ )
+ self.ms_sig_wallet.sendrawtransaction(res["hex"])
def run_test(self):
self.log.info("Making a descriptor wallet")
@@ -68,6 +259,8 @@ class WalletMiniscriptTest(BitcoinTestFramework):
wallet_name="ms_wo", descriptors=True, disable_private_keys=True
)
self.ms_wo_wallet = self.nodes[0].get_wallet_rpc("ms_wo")
+ self.nodes[0].createwallet(wallet_name="ms_sig", descriptors=True)
+ self.ms_sig_wallet = self.nodes[0].get_wallet_rpc("ms_sig")
# Sanity check we wouldn't let an insane Miniscript descriptor in
res = self.ms_wo_wallet.importdescriptors(
@@ -88,6 +281,17 @@ class WalletMiniscriptTest(BitcoinTestFramework):
for ms in MINISCRIPTS:
self.watchonly_test(ms)
+ # Test we can sign for any Miniscript.
+ for ms in MINISCRIPTS_PRIV:
+ self.signing_test(
+ ms["ms"],
+ ms["sequence"],
+ ms["locktime"],
+ ms["sigs_count"],
+ ms["stack_size"],
+ ms.get("sha256_preimages"),
+ )
+
if __name__ == "__main__":
WalletMiniscriptTest().main()
diff --git a/test/functional/wallet_multisig_descriptor_psbt.py b/test/functional/wallet_multisig_descriptor_psbt.py
index 2b565db137..12069fb00d 100755
--- a/test/functional/wallet_multisig_descriptor_psbt.py
+++ b/test/functional/wallet_multisig_descriptor_psbt.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 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 a basic M-of-N multisig setup between multiple people using descriptor wallets and PSBTs, as well as a signing flow.
@@ -16,6 +16,9 @@ from test_framework.util import (
class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
def set_test_params(self):
self.num_nodes = 3
self.setup_clean_chain = True
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index 1c890d7207..2faf6cad8b 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 multiwallet.
@@ -52,6 +52,7 @@ class MultiWalletTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def add_options(self, parser):
+ self.add_wallet_options(parser)
parser.add_argument(
'--data_wallets_dir',
default=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/wallets/'),
@@ -302,12 +303,8 @@ class MultiWalletTest(BitcoinTestFramework):
assert_raises_rpc_error(-18, "Wallet file verification failed. Failed to load database path '{}'. Path does not exist.".format(path), self.nodes[0].loadwallet, 'wallets')
# Fail to load duplicate wallets
- path = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets", "w1", "wallet.dat")
- if self.options.descriptors:
- assert_raises_rpc_error(-4, f"Wallet file verification failed. SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of {self.config['environment']['PACKAGE_NAME']}?", self.nodes[0].loadwallet, wallet_names[0])
- else:
- assert_raises_rpc_error(-35, "Wallet file verification failed. Refusing to load database. Data file '{}' is already loaded.".format(path), self.nodes[0].loadwallet, wallet_names[0])
-
+ assert_raises_rpc_error(-35, "Wallet \"w1\" is already loaded.", self.nodes[0].loadwallet, wallet_names[0])
+ if not self.options.descriptors:
# This tests the default wallet that BDB makes, so SQLite wallet doesn't need to test this
# Fail to load duplicate wallets by different ways (directory and filepath)
path = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets", "wallet.dat")
diff --git a/test/functional/wallet_orphanedreward.py b/test/functional/wallet_orphanedreward.py
index 7295db4653..d8931fa620 100755
--- a/test/functional/wallet_orphanedreward.py
+++ b/test/functional/wallet_orphanedreward.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 orphaned block rewards in the wallet."""
@@ -8,6 +8,9 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
class OrphanedBlockRewardTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
@@ -31,29 +34,40 @@ class OrphanedBlockRewardTest(BitcoinTestFramework):
# the existing balance and the block reward.
self.generate(self.nodes[0], 150)
assert_equal(self.nodes[1].getbalance(), 10 + 25)
+ pre_reorg_conf_bals = self.nodes[1].getbalances()
txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 30)
+ orig_chain_tip = self.nodes[0].getbestblockhash()
+ self.sync_mempools()
# Orphan the block reward and make sure that the original coins
# from the wallet can still be spent.
self.nodes[0].invalidateblock(blk)
- self.generate(self.nodes[0], 152)
- # Without the following abandontransaction call, the coins are
- # not considered available yet.
- assert_equal(self.nodes[1].getbalances()["mine"], {
- "trusted": 0,
- "untrusted_pending": 0,
- "immature": 0,
- })
- # The following abandontransaction is necessary to make the later
- # lines succeed, and probably should not be needed; see
- # https://github.com/bitcoin/bitcoin/issues/14148.
- self.nodes[1].abandontransaction(txid)
+ blocks = self.generate(self.nodes[0], 152)
+ conflict_block = blocks[0]
+ # We expect the descendants of orphaned rewards to no longer be considered
assert_equal(self.nodes[1].getbalances()["mine"], {
"trusted": 10,
"untrusted_pending": 0,
"immature": 0,
})
- self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 9)
+ # And the unconfirmed tx to be abandoned
+ assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True)
+
+ # The abandoning should persist through reloading
+ self.nodes[1].unloadwallet(self.default_wallet_name)
+ self.nodes[1].loadwallet(self.default_wallet_name)
+ assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True)
+
+ # If the orphaned reward is reorged back into the main chain, any unconfirmed
+ # descendant txs at the time of the original reorg remain abandoned.
+ self.nodes[0].invalidateblock(conflict_block)
+ self.nodes[0].reconsiderblock(blk)
+ assert_equal(self.nodes[0].getbestblockhash(), orig_chain_tip)
+ self.generate(self.nodes[0], 3)
+
+ assert_equal(self.nodes[1].getbalances(), pre_reorg_conf_bals)
+ assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True)
+
if __name__ == '__main__':
OrphanedBlockRewardTest().main()
diff --git a/test/functional/wallet_pruning.py b/test/functional/wallet_pruning.py
new file mode 100755
index 0000000000..1ceceaee93
--- /dev/null
+++ b/test/functional/wallet_pruning.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 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 wallet import on pruned node."""
+import os
+
+from test_framework.util import assert_equal, assert_raises_rpc_error
+from test_framework.blocktools import (
+ COINBASE_MATURITY,
+ create_block
+)
+from test_framework.blocktools import create_coinbase
+from test_framework.test_framework import BitcoinTestFramework
+
+from test_framework.script import (
+ CScript,
+ OP_RETURN,
+ OP_TRUE,
+)
+
+class WalletPruningTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=False)
+
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 2
+ self.wallet_names = []
+ self.extra_args = [
+ [], # node dedicated to mining
+ ['-prune=550'], # node dedicated to testing pruning
+ ]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+ self.skip_if_no_bdb()
+
+ def mine_large_blocks(self, node, n):
+ # Get the block parameters for the first block
+ best_block = node.getblockheader(node.getbestblockhash())
+ height = int(best_block["height"]) + 1
+ self.nTime = max(self.nTime, int(best_block["time"])) + 1
+ previousblockhash = int(best_block["hash"], 16)
+ big_script = CScript([OP_RETURN] + [OP_TRUE] * 950000)
+ # Set mocktime to accept all future blocks
+ for i in self.nodes:
+ if i.running:
+ i.setmocktime(self.nTime + 600 * n)
+ for _ in range(n):
+ block = create_block(hashprev=previousblockhash, ntime=self.nTime, coinbase=create_coinbase(height, script_pubkey=big_script))
+ block.solve()
+
+ # Submit to the node
+ node.submitblock(block.serialize().hex())
+
+ previousblockhash = block.sha256
+ height += 1
+
+ # Simulate 10 minutes of work time per block
+ # Important for matching a timestamp with a block +- some window
+ self.nTime += 600
+ self.sync_all()
+
+ def test_wallet_import_pruned(self, wallet_name):
+ self.log.info("Make sure we can import wallet when pruned and required blocks are still available")
+
+ wallet_file = wallet_name + ".dat"
+ wallet_birthheight = self.get_birthheight(wallet_file)
+
+ # Verify that the block at wallet's birthheight is available at the pruned node
+ self.nodes[1].getblock(self.nodes[1].getblockhash(wallet_birthheight))
+
+ # Import wallet into pruned node
+ self.nodes[1].createwallet(wallet_name="wallet_pruned", descriptors=False, load_on_startup=True)
+ self.nodes[1].importwallet(os.path.join(self.nodes[0].datadir, wallet_file))
+
+ # Make sure that prune node's wallet correctly accounts for balances
+ assert_equal(self.nodes[1].getbalance(), self.nodes[0].getbalance())
+
+ self.log.info("- Done")
+
+ def test_wallet_import_pruned_with_missing_blocks(self, wallet_name):
+ self.log.info("Make sure we cannot import wallet when pruned and required blocks are not available")
+
+ wallet_file = wallet_name + ".dat"
+ wallet_birthheight = self.get_birthheight(wallet_file)
+
+ # Verify that the block at wallet's birthheight is not available at the pruned node
+ assert_raises_rpc_error(-1, "Block not available (pruned data)", self.nodes[1].getblock, self.nodes[1].getblockhash(wallet_birthheight))
+
+ # Make sure wallet cannot be imported because of missing blocks
+ # This will try to rescan blocks `TIMESTAMP_WINDOW` (2h) before the wallet birthheight.
+ # There are 6 blocks an hour, so 11 blocks (excluding birthheight).
+ assert_raises_rpc_error(-4, f"Pruned blocks from height {wallet_birthheight - 11} required to import keys. Use RPC call getblockchaininfo to determine your pruned height.", self.nodes[1].importwallet, os.path.join(self.nodes[0].datadir, wallet_file))
+ self.log.info("- Done")
+
+ def get_birthheight(self, wallet_file):
+ """Gets birthheight of a wallet on node0"""
+ with open(os.path.join(self.nodes[0].datadir, wallet_file), 'r', encoding="utf8") as f:
+ for line in f:
+ if line.startswith('# * Best block at time of backup'):
+ wallet_birthheight = int(line.split(' ')[9])
+ return wallet_birthheight
+
+ def has_block(self, block_index):
+ """Checks if the pruned node has the specific blk0000*.dat file"""
+ return os.path.isfile(os.path.join(self.nodes[1].datadir, self.chain, "blocks", f"blk{block_index:05}.dat"))
+
+ def create_wallet(self, wallet_name, *, unload=False):
+ """Creates and dumps a wallet on the non-pruned node0 to be later import by the pruned node"""
+ self.nodes[0].createwallet(wallet_name=wallet_name, descriptors=False, load_on_startup=True)
+ self.nodes[0].dumpwallet(os.path.join(self.nodes[0].datadir, wallet_name + ".dat"))
+ if (unload):
+ self.nodes[0].unloadwallet(wallet_name)
+
+ def run_test(self):
+ self.nTime = 0
+ self.log.info("Warning! This test requires ~1.3GB of disk space")
+
+ self.log.info("Generating a long chain of blocks...")
+
+ # A blk*.dat file is 128MB
+ # Generate 250 light blocks
+ self.generate(self.nodes[0], 250)
+ # Generate 50MB worth of large blocks in the blk00000.dat file
+ self.mine_large_blocks(self.nodes[0], 50)
+
+ # Create a wallet which birth's block is in the blk00000.dat file
+ wallet_birthheight_1 = "wallet_birthheight_1"
+ assert_equal(self.has_block(1), False)
+ self.create_wallet(wallet_birthheight_1, unload=True)
+
+ # Generate enough large blocks to reach pruning disk limit
+ # Not pruning yet because we are still below PruneAfterHeight
+ self.mine_large_blocks(self.nodes[0], 600)
+ self.log.info("- Long chain created")
+
+ # Create a wallet with birth height > wallet_birthheight_1
+ wallet_birthheight_2 = "wallet_birthheight_2"
+ self.create_wallet(wallet_birthheight_2)
+
+ # Fund wallet to later verify that importwallet correctly accounts for balances
+ self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, self.nodes[0].getnewaddress(), sync_fun=self.no_op)
+
+ # We've reached pruning storage & height limit but
+ # pruning doesn't run until another chunk (blk*.dat file) is allocated.
+ # That's why we are generating another 5 large blocks
+ self.mine_large_blocks(self.nodes[0], 5)
+
+ # blk00000.dat file is now pruned from node1
+ assert_equal(self.has_block(0), False)
+
+ self.test_wallet_import_pruned(wallet_birthheight_2)
+ self.test_wallet_import_pruned_with_missing_blocks(wallet_birthheight_1)
+
+if __name__ == '__main__':
+ WalletPruningTest().main()
diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py
index f2bdb114b7..1c79c6816c 100755
--- a/test/functional/wallet_reorgsrestore.py
+++ b/test/functional/wallet_reorgsrestore.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2021 The Bitcoin Core developers
+# Copyright (c) 2019-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -23,6 +23,9 @@ from test_framework.util import (
)
class ReorgsRestoreTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 3
@@ -91,11 +94,11 @@ class ReorgsRestoreTest(BitcoinTestFramework):
tx_after_reorg = self.nodes[1].gettransaction(txid)
# Check that normal confirmed tx is confirmed again but with different blockhash
assert_equal(tx_after_reorg["confirmations"], 2)
- assert(tx_before_reorg["blockhash"] != tx_after_reorg["blockhash"])
+ assert tx_before_reorg["blockhash"] != tx_after_reorg["blockhash"]
conflicted_after_reorg = self.nodes[1].gettransaction(conflicted_txid)
# Check that conflicted tx is confirmed again with blockhash different than previously conflicting tx
assert_equal(conflicted_after_reorg["confirmations"], 1)
- assert(conflicting["blockhash"] != conflicted_after_reorg["blockhash"])
+ assert conflicting["blockhash"] != conflicted_after_reorg["blockhash"]
if __name__ == '__main__':
ReorgsRestoreTest().main()
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index b3d02fbfc9..7e4a4002b2 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 that the wallet resends transactions periodically."""
@@ -18,6 +18,9 @@ from test_framework.util import (
)
class ResendWalletTransactionsTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py
index 07baa0595e..ac3ec06eec 100755
--- a/test/functional/wallet_send.py
+++ b/test/functional/wallet_send.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Copyright (c) 2020-2022 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 send RPC command."""
@@ -25,6 +25,9 @@ from test_framework.util import (
from test_framework.wallet_util import bytes_to_wif
class WalletSendTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 2
# whitelist all peers to speed up tx relay / mempool sync
@@ -42,7 +45,7 @@ class WalletSendTest(BitcoinTestFramework):
conf_target=None, estimate_mode=None, fee_rate=None, add_to_wallet=None, psbt=None,
inputs=None, add_inputs=None, include_unsafe=None, change_address=None, change_position=None, change_type=None,
include_watching=None, locktime=None, lock_unspents=None, replaceable=None, subtract_fee_from_outputs=None,
- expect_error=None, solving_data=None):
+ expect_error=None, solving_data=None, minconf=None):
assert (amount is None) != (data is None)
from_balance_before = from_wallet.getbalances()["mine"]["trusted"]
@@ -103,6 +106,8 @@ class WalletSendTest(BitcoinTestFramework):
options["subtract_fee_from_outputs"] = subtract_fee_from_outputs
if solving_data is not None:
options["solving_data"] = solving_data
+ if minconf is not None:
+ options["minconf"] = minconf
if len(options.keys()) == 0:
options = None
@@ -276,11 +281,11 @@ class WalletSendTest(BitcoinTestFramework):
self.log.info("Don't broadcast...")
res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, add_to_wallet=False)
- assert(res["hex"])
+ assert res["hex"]
self.log.info("Return PSBT...")
res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, psbt=True)
- assert(res["psbt"])
+ assert res["psbt"]
self.log.info("Create transaction that spends to address, but don't broadcast...")
self.test_send(from_wallet=w0, to_wallet=w1, amount=1, add_to_wallet=False)
@@ -362,7 +367,7 @@ class WalletSendTest(BitcoinTestFramework):
for mode in ["economical", "conservative"]:
for k, v in {"string": "true", "bool": True, "object": {"foo": "bar"}}.items():
self.test_send(from_wallet=w0, to_wallet=w1, amount=1, conf_target=v, estimate_mode=mode,
- expect_error=(-3, f"Expected type number for conf_target, got {k}"))
+ expect_error=(-3, f"JSON value of type {k} for field conf_target is not of expected type number"))
# Test setting explicit fee rate just below the minimum of 1 sat/vB.
self.log.info("Explicit fee rate raises RPC error 'fee rate too low' if fee_rate of 0.99999999 is passed")
@@ -409,10 +414,12 @@ class WalletSendTest(BitcoinTestFramework):
assert res["complete"]
utxo1 = w0.listunspent()[0]
assert_equal(utxo1["amount"], 50)
+ ERR_NOT_ENOUGH_PRESET_INPUTS = "The preselected coins total amount does not cover the transaction target. " \
+ "Please allow other inputs to be automatically selected or include more coins manually"
self.test_send(from_wallet=w0, to_wallet=w1, amount=51, inputs=[utxo1],
- expect_error=(-4, "Insufficient funds"))
+ expect_error=(-4, ERR_NOT_ENOUGH_PRESET_INPUTS))
self.test_send(from_wallet=w0, to_wallet=w1, amount=51, inputs=[utxo1], add_inputs=False,
- expect_error=(-4, "Insufficient funds"))
+ expect_error=(-4, ERR_NOT_ENOUGH_PRESET_INPUTS))
res = self.test_send(from_wallet=w0, to_wallet=w1, amount=51, inputs=[utxo1], add_inputs=True, add_to_wallet=False)
assert res["complete"]
@@ -482,6 +489,16 @@ class WalletSendTest(BitcoinTestFramework):
res = self.test_send(from_wallet=w5, to_wallet=w0, amount=1, include_unsafe=True)
assert res["complete"]
+ self.log.info("Minconf")
+ self.nodes[1].createwallet(wallet_name="minconfw")
+ minconfw= self.nodes[1].get_wallet_rpc("minconfw")
+ self.test_send(from_wallet=w0, to_wallet=minconfw, amount=2)
+ self.generate(self.nodes[0], 3)
+ self.test_send(from_wallet=minconfw, to_wallet=w0, amount=1, minconf=4, expect_error=(-4, "Insufficient funds"))
+ self.test_send(from_wallet=minconfw, to_wallet=w0, amount=1, minconf=-4, expect_error=(-8, "Negative minconf"))
+ res = self.test_send(from_wallet=minconfw, to_wallet=w0, amount=1, minconf=3)
+ assert res["complete"]
+
self.log.info("External outputs")
eckey = ECKey()
eckey.generate()
@@ -508,7 +525,7 @@ class WalletSendTest(BitcoinTestFramework):
ext_utxo = ext_fund.listunspent(addresses=[addr])[0]
# An external input without solving data should result in an error
- self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, expect_error=(-4, "Insufficient funds"))
+ self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, expect_error=(-4, "Not solvable pre-selected input COutPoint(%s, %s)" % (ext_utxo["txid"][0:10], ext_utxo["vout"])))
# But funding should work when the solving data is provided
res = self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, solving_data={"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"], addr_info["embedded"]["embedded"]["scriptPubKey"]]})
diff --git a/test/functional/wallet_sendall.py b/test/functional/wallet_sendall.py
index db4f32fe16..f6440f07d7 100755
--- a/test/functional/wallet_sendall.py
+++ b/test/functional/wallet_sendall.py
@@ -26,6 +26,9 @@ def cleanup(func):
class SendallTest(BitcoinTestFramework):
# Setup and helpers
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -221,6 +224,11 @@ class SendallTest(BitcoinTestFramework):
self.add_utxos([16, 5])
spent_utxo = self.wallet.listunspent()[0]
+ # fails on out of bounds vout
+ assert_raises_rpc_error(-8,
+ "Input not found. UTXO ({}:{}) is not part of wallet.".format(spent_utxo["txid"], 1000),
+ self.wallet.sendall, recipients=[self.remainder_target], options={"inputs": [{"txid": spent_utxo["txid"], "vout": 1000}]})
+
# fails on unconfirmed spent UTXO
self.wallet.sendall(recipients=[self.remainder_target])
assert_raises_rpc_error(-8,
@@ -276,9 +284,108 @@ class SendallTest(BitcoinTestFramework):
recipients=[self.remainder_target],
fee_rate=100000)
+ @cleanup
+ def sendall_fails_on_low_fee(self):
+ self.log.info("Test sendall fails if the transaction fee is lower than the minimum fee rate setting")
+ assert_raises_rpc_error(-8, "Fee rate (0.999 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)",
+ self.wallet.sendall, recipients=[self.recipient], fee_rate=0.999)
+
+ @cleanup
+ def sendall_watchonly_specific_inputs(self):
+ self.log.info("Test sendall with a subset of UTXO pool in a watchonly wallet")
+ self.add_utxos([17, 4])
+ utxo = self.wallet.listunspent()[0]
+
+ self.nodes[0].createwallet(wallet_name="watching", disable_private_keys=True)
+ watchonly = self.nodes[0].get_wallet_rpc("watching")
+
+ import_req = [{
+ "desc": utxo["desc"],
+ "timestamp": 0,
+ }]
+ if self.options.descriptors:
+ watchonly.importdescriptors(import_req)
+ else:
+ watchonly.importmulti(import_req)
+
+ sendall_tx_receipt = watchonly.sendall(recipients=[self.remainder_target], options={"inputs": [utxo]})
+ psbt = sendall_tx_receipt["psbt"]
+ decoded = self.nodes[0].decodepsbt(psbt)
+ assert_equal(len(decoded["inputs"]), 1)
+ assert_equal(len(decoded["outputs"]), 1)
+ assert_equal(decoded["tx"]["vin"][0]["txid"], utxo["txid"])
+ assert_equal(decoded["tx"]["vin"][0]["vout"], utxo["vout"])
+ assert_equal(decoded["tx"]["vout"][0]["scriptPubKey"]["address"], self.remainder_target)
+
+ @cleanup
+ def sendall_with_minconf(self):
+ # utxo of 17 bicoin has 6 confirmations, utxo of 4 has 3
+ self.add_utxos([17])
+ self.generate(self.nodes[0], 2)
+ self.add_utxos([4])
+ self.generate(self.nodes[0], 2)
+
+ self.log.info("Test sendall fails because minconf is negative")
+
+ assert_raises_rpc_error(-8,
+ "Invalid minconf (minconf cannot be negative): -2",
+ self.wallet.sendall,
+ recipients=[self.remainder_target],
+ options={"minconf": -2})
+ self.log.info("Test sendall fails because minconf is used while specific inputs are provided")
+
+ utxo = self.wallet.listunspent()[0]
+ assert_raises_rpc_error(-8,
+ "Cannot combine minconf or maxconf with specific inputs.",
+ self.wallet.sendall,
+ recipients=[self.remainder_target],
+ options={"inputs": [utxo], "minconf": 2})
+
+ self.log.info("Test sendall fails because there are no utxos with enough confirmations specified by minconf")
+
+ assert_raises_rpc_error(-6,
+ "Total value of UTXO pool too low to pay for transaction. Try using lower feerate or excluding uneconomic UTXOs with 'send_max' option.",
+ self.wallet.sendall,
+ recipients=[self.remainder_target],
+ options={"minconf": 7})
+
+ self.log.info("Test sendall only spends utxos with a specified number of confirmations when minconf is used")
+ self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"minconf": 6})
+
+ assert_equal(len(self.wallet.listunspent()), 1)
+ assert_equal(self.wallet.listunspent()[0]['confirmations'], 3)
+
+ # decrease minconf and show the remaining utxo is picked up
+ self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"minconf": 3})
+ assert_equal(self.wallet.getbalance(), 0)
+
+ @cleanup
+ def sendall_with_maxconf(self):
+ # utxo of 17 bicoin has 6 confirmations, utxo of 4 has 3
+ self.add_utxos([17])
+ self.generate(self.nodes[0], 2)
+ self.add_utxos([4])
+ self.generate(self.nodes[0], 2)
+
+ self.log.info("Test sendall fails because there are no utxos with enough confirmations specified by maxconf")
+ assert_raises_rpc_error(-6,
+ "Total value of UTXO pool too low to pay for transaction. Try using lower feerate or excluding uneconomic UTXOs with 'send_max' option.",
+ self.wallet.sendall,
+ recipients=[self.remainder_target],
+ options={"maxconf": 1})
+
+ self.log.info("Test sendall only spends utxos with a specified number of confirmations when maxconf is used")
+ self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"maxconf":4})
+ assert_equal(len(self.wallet.listunspent()), 1)
+ assert_equal(self.wallet.listunspent()[0]['confirmations'], 6)
+
# This tests needs to be the last one otherwise @cleanup will fail with "Transaction too large" error
def sendall_fails_with_transaction_too_large(self):
self.log.info("Test that sendall fails if resulting transaction is too large")
+
+ # Force the wallet to bulk-generate the addresses we'll need
+ self.wallet.keypoolrefill(1600)
+
# create many inputs
outputs = {self.wallet.getnewaddress(): 0.000025 for _ in range(1600)}
self.def_wallet.sendmany(amounts=outputs)
@@ -341,6 +448,18 @@ class SendallTest(BitcoinTestFramework):
# Sendall fails when providing a fee that is too high
self.sendall_fails_on_high_fee()
+ # Sendall fails when fee rate is lower than minimum
+ self.sendall_fails_on_low_fee()
+
+ # Sendall succeeds with watchonly wallets spending specific UTXOs
+ self.sendall_watchonly_specific_inputs()
+
+ # Sendall only uses outputs with at least a give number of confirmations when using minconf
+ self.sendall_with_minconf()
+
+ # Sendall only uses outputs with less than a given number of confirmation when using minconf
+ self.sendall_with_maxconf()
+
# Sendall fails when many inputs result to too large transaction
self.sendall_fails_with_transaction_too_large()
diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py
index 5609ac9bf5..8d25044e43 100755
--- a/test/functional/wallet_signer.py
+++ b/test/functional/wallet_signer.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 external signer.
@@ -13,11 +13,15 @@ import platform
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ assert_greater_than,
assert_raises_rpc_error,
)
class WalletSignerTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
def mock_signer_path(self):
path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'mocks', 'signer.py')
if platform.system() == "Windows":
@@ -98,7 +102,7 @@ class WalletSignerTest(BitcoinTestFramework):
# )
# self.clear_mock_result(self.nodes[1])
- assert_equal(hww.getwalletinfo()["keypoolsize"], 30)
+ assert_equal(hww.getwalletinfo()["keypoolsize"], 40)
address1 = hww.getnewaddress(address_type="bech32")
assert_equal(address1, "bcrt1qm90ugl4d48jv8n6e5t9ln6t9zlpm5th68x4f8g")
@@ -121,6 +125,13 @@ class WalletSignerTest(BitcoinTestFramework):
assert_equal(address_info['ismine'], True)
assert_equal(address_info['hdkeypath'], "m/44'/1'/0'/0/0")
+ address4 = hww.getnewaddress(address_type="bech32m")
+ assert_equal(address4, "bcrt1phw4cgpt6cd30kz9k4wkpwm872cdvhss29jga2xpmftelhqll62ms4e9sqj")
+ address_info = hww.getaddressinfo(address4)
+ assert_equal(address_info['solvable'], True)
+ assert_equal(address_info['ismine'], True)
+ assert_equal(address_info['hdkeypath'], "m/86'/1'/0'/0/0")
+
self.log.info('Test walletdisplayaddress')
result = hww.walletdisplayaddress(address1)
assert_equal(result, {"address": address1})
@@ -133,7 +144,7 @@ class WalletSignerTest(BitcoinTestFramework):
self.clear_mock_result(self.nodes[1])
self.log.info('Prepare mock PSBT')
- self.nodes[0].sendtoaddress(address1, 1)
+ self.nodes[0].sendtoaddress(address4, 1)
self.generate(self.nodes[0], 1)
# Load private key into wallet to generate a signed PSBT for the mock
@@ -142,14 +153,14 @@ class WalletSignerTest(BitcoinTestFramework):
assert mock_wallet.getwalletinfo()['private_keys_enabled']
result = mock_wallet.importdescriptors([{
- "desc": "wpkh([00000001/84'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0/*)#rweraev0",
+ "desc": "tr([00000001/86'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0/*)#0jtt2jc9",
"timestamp": 0,
"range": [0,1],
"internal": False,
"active": True
},
{
- "desc": "wpkh([00000001/84'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/*)#j6uzqvuh",
+ "desc": "tr([00000001/86'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/*)#7xw2h8ga",
"timestamp": 0,
"range": [0, 0],
"internal": True,
@@ -159,11 +170,11 @@ class WalletSignerTest(BitcoinTestFramework):
assert_equal(result[1], {'success': True})
assert_equal(mock_wallet.getwalletinfo()["txcount"], 1)
dest = self.nodes[0].getnewaddress(address_type='bech32')
- mock_psbt = mock_wallet.walletcreatefundedpsbt([], {dest:0.5}, 0, {}, True)['psbt']
+ mock_psbt = mock_wallet.walletcreatefundedpsbt([], {dest:0.5}, 0, {'replaceable': True}, True)['psbt']
mock_psbt_signed = mock_wallet.walletprocesspsbt(psbt=mock_psbt, sign=True, sighashtype="ALL", bip32derivs=True)
mock_psbt_final = mock_wallet.finalizepsbt(mock_psbt_signed["psbt"])
mock_tx = mock_psbt_final["hex"]
- assert(mock_wallet.testmempoolaccept([mock_tx])[0]["allowed"])
+ assert mock_wallet.testmempoolaccept([mock_tx])[0]["allowed"]
# # Create a new wallet and populate with specific public keys, in order
# # to work with the mock signed PSBT.
@@ -192,22 +203,42 @@ class WalletSignerTest(BitcoinTestFramework):
# assert_equal(result[1], {'success': True})
assert_equal(hww.getwalletinfo()["txcount"], 1)
- assert(hww.testmempoolaccept([mock_tx])[0]["allowed"])
+ assert hww.testmempoolaccept([mock_tx])[0]["allowed"]
with open(os.path.join(self.nodes[1].cwd, "mock_psbt"), "w", encoding="utf8") as f:
f.write(mock_psbt_signed["psbt"])
self.log.info('Test send using hww1')
+ # Don't broadcast transaction yet so the RPC returns the raw hex
res = hww.send(outputs={dest:0.5},options={"add_to_wallet": False})
- assert(res["complete"])
+ assert res["complete"]
assert_equal(res["hex"], mock_tx)
self.log.info('Test sendall using hww1')
res = hww.sendall(recipients=[{dest:0.5}, hww.getrawchangeaddress()],options={"add_to_wallet": False})
- assert(res["complete"])
+ assert res["complete"]
assert_equal(res["hex"], mock_tx)
+ # Broadcast transaction so we can bump the fee
+ hww.sendrawtransaction(res["hex"])
+
+ self.log.info('Prepare fee bumped mock PSBT')
+
+ # Now that the transaction is broadcast, bump fee in mock wallet:
+ orig_tx_id = res["txid"]
+ mock_psbt_bumped = mock_wallet.psbtbumpfee(orig_tx_id)["psbt"]
+ mock_psbt_bumped_signed = mock_wallet.walletprocesspsbt(psbt=mock_psbt_bumped, sign=True, sighashtype="ALL", bip32derivs=True)
+
+ with open(os.path.join(self.nodes[1].cwd, "mock_psbt"), "w", encoding="utf8") as f:
+ f.write(mock_psbt_bumped_signed["psbt"])
+
+ self.log.info('Test bumpfee using hww1')
+
+ # Bump fee
+ res = hww.bumpfee(orig_tx_id)
+ assert_greater_than(res["fee"], res["origfee"])
+ assert_equal(res["errors"], [])
# # Handle error thrown by script
# self.set_mock_result(self.nodes[4], "2")
diff --git a/test/functional/wallet_signmessagewithaddress.py b/test/functional/wallet_signmessagewithaddress.py
index 74a8f2eef2..4a4b818bd1 100755
--- a/test/functional/wallet_signmessagewithaddress.py
+++ b/test/functional/wallet_signmessagewithaddress.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2021 The Bitcoin Core developers
+# Copyright (c) 2016-2022 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 Wallet commands for signing and verifying messages."""
@@ -10,6 +10,9 @@ from test_framework.util import (
)
class SignMessagesWithAddressTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
diff --git a/test/functional/wallet_signrawtransactionwithwallet.py b/test/functional/wallet_signrawtransactionwithwallet.py
index 6b30386b7e..3d2f41cb83 100755
--- a/test/functional/wallet_signrawtransactionwithwallet.py
+++ b/test/functional/wallet_signrawtransactionwithwallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2021 The Bitcoin Core developers
+# Copyright (c) 2015-2022 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 transaction signing using the signrawtransactionwithwallet RPC."""
@@ -34,6 +34,9 @@ from decimal import (
)
class SignRawTransactionWithWalletTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
diff --git a/test/functional/wallet_simulaterawtx.py b/test/functional/wallet_simulaterawtx.py
index a408b99515..545aad892c 100755
--- a/test/functional/wallet_simulaterawtx.py
+++ b/test/functional/wallet_simulaterawtx.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 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 simulaterawtransaction.
@@ -15,6 +15,9 @@ from test_framework.util import (
)
class SimulateTxTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
diff --git a/test/functional/wallet_startup.py b/test/functional/wallet_startup.py
index d96c2da686..2cc4e312af 100755
--- a/test/functional/wallet_startup.py
+++ b/test/functional/wallet_startup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2022 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 wallet load on startup.
@@ -13,6 +13,9 @@ from test_framework.util import (
class WalletStartupTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index 3c630ba433..b52892704f 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -1,10 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 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 generation and spending of P2TR addresses."""
import random
+import uuid
from decimal import Decimal
from test_framework.address import output_key_to_p2tr
@@ -156,9 +157,6 @@ KEYS = [
}
]
-CHANGE_XPRV = "tprv8ZgxMBicQKsPcyDrWwiecVnTtFmfRwbfFqEfR4ZGWvq5aTTwLBWmAm5zrbMcYtb9gQNFfhRfqhhrBG37U3nhmXxEgeEPBJGHAPrHCrAd1WX"
-CHANGE_XPUB = "tpubD6NzVbkrYhZ4WSFeQbPF1uSaTHHbbGnZq8qShabZwCdUQwihxaLMMFhs2kidGF2qrRKiQVqw8VoyuTHj1bZqmMXMeciaU1gBjWA1sim2zUB"
-
def key(hex_key):
"""Construct an x-only pubkey from its hex representation."""
@@ -189,6 +187,9 @@ def compute_raw_taproot_address(pubkey):
class WalletTaprootTest(BitcoinTestFramework):
"""Test generation and spending of P2TR address outputs."""
+ def add_options(self, parser):
+ self.add_wallet_options(parser, legacy=False)
+
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
@@ -229,17 +230,28 @@ class WalletTaprootTest(BitcoinTestFramework):
def do_test_addr(self, comment, pattern, privmap, treefn, keys):
self.log.info("Testing %s address derivation" % comment)
+
+ # Create wallets
+ wallet_uuid = uuid.uuid4().hex
+ self.nodes[0].createwallet(wallet_name=f"privs_tr_enabled_{wallet_uuid}", descriptors=True, blank=True)
+ self.nodes[0].createwallet(wallet_name=f"pubs_tr_enabled_{wallet_uuid}", descriptors=True, blank=True, disable_private_keys=True)
+ self.nodes[0].createwallet(wallet_name=f"addr_gen_{wallet_uuid}", descriptors=True, disable_private_keys=True, blank=True)
+ privs_tr_enabled = self.nodes[0].get_wallet_rpc(f"privs_tr_enabled_{wallet_uuid}")
+ pubs_tr_enabled = self.nodes[0].get_wallet_rpc(f"pubs_tr_enabled_{wallet_uuid}")
+ addr_gen = self.nodes[0].get_wallet_rpc(f"addr_gen_{wallet_uuid}")
+
desc = self.make_desc(pattern, privmap, keys, False)
desc_pub = self.make_desc(pattern, privmap, keys, True)
assert_equal(self.nodes[0].getdescriptorinfo(desc)['descriptor'], desc_pub)
- result = self.addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}])
- assert(result[0]['success'])
+ result = addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}])
+ assert result[0]['success']
+ address_type = "bech32m" if "tr" in pattern else "bech32"
for i in range(4):
- addr_g = self.addr_gen.getnewaddress(address_type='bech32m')
+ addr_g = addr_gen.getnewaddress(address_type=address_type)
if treefn is not None:
addr_r = self.make_addr(treefn, keys, i)
assert_equal(addr_g, addr_r)
- desc_a = self.addr_gen.getaddressinfo(addr_g)['desc']
+ desc_a = addr_gen.getaddressinfo(addr_g)['desc']
if desc.startswith("tr("):
assert desc_a.startswith("tr(")
rederive = self.nodes[1].deriveaddresses(desc_a)
@@ -247,25 +259,37 @@ class WalletTaprootTest(BitcoinTestFramework):
assert_equal(rederive[0], addr_g)
# tr descriptors can be imported
- result = self.privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
- assert(result[0]["success"])
- result = self.pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
- assert(result[0]["success"])
+ result = privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
+ assert result[0]['success']
+ result = pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
+ assert result[0]["success"]
+
+ # Cleanup
+ privs_tr_enabled.unloadwallet()
+ pubs_tr_enabled.unloadwallet()
+ addr_gen.unloadwallet()
def do_test_sendtoaddress(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
self.log.info("Testing %s through sendtoaddress" % comment)
+
+ # Create wallets
+ wallet_uuid = uuid.uuid4().hex
+ self.nodes[0].createwallet(wallet_name=f"rpc_online_{wallet_uuid}", descriptors=True, blank=True)
+ rpc_online = self.nodes[0].get_wallet_rpc(f"rpc_online_{wallet_uuid}")
+
desc_pay = self.make_desc(pattern, privmap, keys_pay)
desc_change = self.make_desc(pattern, privmap, keys_change)
desc_pay_pub = self.make_desc(pattern, privmap, keys_pay, True)
desc_change_pub = self.make_desc(pattern, privmap, keys_change, True)
assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub)
assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub)
- result = self.rpc_online.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
- assert(result[0]['success'])
- result = self.rpc_online.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
- assert(result[0]['success'])
+ result = rpc_online.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
+ assert result[0]['success']
+ result = rpc_online.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
+ assert result[0]['success']
+ address_type = "bech32m" if "tr" in pattern else "bech32"
for i in range(4):
- addr_g = self.rpc_online.getnewaddress(address_type='bech32m')
+ addr_g = rpc_online.getnewaddress(address_type=address_type)
if treefn is not None:
addr_r = self.make_addr(treefn, keys_pay, i)
assert_equal(addr_g, addr_r)
@@ -273,31 +297,51 @@ class WalletTaprootTest(BitcoinTestFramework):
to_amnt = random.randrange(1000000, boring_balance)
self.boring.sendtoaddress(address=addr_g, amount=Decimal(to_amnt) / 100000000, subtractfeefromamount=True)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- test_balance = int(self.rpc_online.getbalance() * 100000000)
+ test_balance = int(rpc_online.getbalance() * 100000000)
ret_amnt = random.randrange(100000, test_balance)
# Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
- res = self.rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True, fee_rate=200)
+ res = rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True, fee_rate=200)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.rpc_online.gettransaction(res)["confirmations"] > 0)
+ assert rpc_online.gettransaction(res)["confirmations"] > 0
+
+ # Cleanup
+ txid = rpc_online.sendall(recipients=[self.boring.getnewaddress()])["txid"]
+ self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
+ assert rpc_online.gettransaction(txid)["confirmations"] > 0
+ rpc_online.unloadwallet()
def do_test_psbt(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
self.log.info("Testing %s through PSBT" % comment)
+
+ # Create wallets
+ wallet_uuid = uuid.uuid4().hex
+ self.nodes[0].createwallet(wallet_name=f"psbt_online_{wallet_uuid}", descriptors=True, disable_private_keys=True, blank=True)
+ self.nodes[1].createwallet(wallet_name=f"psbt_offline_{wallet_uuid}", descriptors=True, blank=True)
+ self.nodes[1].createwallet(f"key_only_wallet_{wallet_uuid}", descriptors=True, blank=True)
+ psbt_online = self.nodes[0].get_wallet_rpc(f"psbt_online_{wallet_uuid}")
+ psbt_offline = self.nodes[1].get_wallet_rpc(f"psbt_offline_{wallet_uuid}")
+ key_only_wallet = self.nodes[1].get_wallet_rpc(f"key_only_wallet_{wallet_uuid}")
+
desc_pay = self.make_desc(pattern, privmap, keys_pay, False)
desc_change = self.make_desc(pattern, privmap, keys_change, False)
desc_pay_pub = self.make_desc(pattern, privmap, keys_pay, True)
desc_change_pub = self.make_desc(pattern, privmap, keys_change, True)
assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub)
assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub)
- result = self.psbt_online.importdescriptors([{"desc": desc_pay_pub, "active": True, "timestamp": "now"}])
- assert(result[0]['success'])
- result = self.psbt_online.importdescriptors([{"desc": desc_change_pub, "active": True, "timestamp": "now", "internal": True}])
- assert(result[0]['success'])
- result = self.psbt_offline.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
- assert(result[0]['success'])
- result = self.psbt_offline.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
- assert(result[0]['success'])
+ result = psbt_online.importdescriptors([{"desc": desc_pay_pub, "active": True, "timestamp": "now"}])
+ assert result[0]['success']
+ result = psbt_online.importdescriptors([{"desc": desc_change_pub, "active": True, "timestamp": "now", "internal": True}])
+ assert result[0]['success']
+ result = psbt_offline.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
+ assert result[0]['success']
+ result = psbt_offline.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
+ assert result[0]['success']
+ for key in keys_pay + keys_change:
+ result = key_only_wallet.importdescriptors([{"desc": descsum_create(f"wpkh({key['xprv']}/*)"), "timestamp":"now"}])
+ assert result[0]["success"]
+ address_type = "bech32m" if "tr" in pattern else "bech32"
for i in range(4):
- addr_g = self.psbt_online.getnewaddress(address_type='bech32m')
+ addr_g = psbt_online.getnewaddress(address_type=address_type)
if treefn is not None:
addr_r = self.make_addr(treefn, keys_pay, i)
assert_equal(addr_g, addr_r)
@@ -305,28 +349,43 @@ class WalletTaprootTest(BitcoinTestFramework):
to_amnt = random.randrange(1000000, boring_balance)
self.boring.sendtoaddress(address=addr_g, amount=Decimal(to_amnt) / 100000000, subtractfeefromamount=True)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- test_balance = int(self.psbt_online.getbalance() * 100000000)
+ test_balance = int(psbt_online.getbalance() * 100000000)
ret_amnt = random.randrange(100000, test_balance)
# Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
- psbt = self.psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): Decimal(ret_amnt) / 100000000}], None, {"subtractFeeFromOutputs":[0], "fee_rate": 200, "change_type": "bech32m"})['psbt']
- res = self.psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
-
- decoded = self.psbt_offline.decodepsbt(res["psbt"])
- if pattern.startswith("tr("):
- for psbtin in decoded["inputs"]:
- assert "non_witness_utxo" not in psbtin
- assert "witness_utxo" in psbtin
- assert "taproot_internal_key" in psbtin
- assert "taproot_bip32_derivs" in psbtin
- assert "taproot_key_path_sig" in psbtin or "taproot_script_path_sigs" in psbtin
- if "taproot_script_path_sigs" in psbtin:
- assert "taproot_merkle_root" in psbtin
- assert "taproot_scripts" in psbtin
-
- rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
+ psbt = psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): Decimal(ret_amnt) / 100000000}], None, {"subtractFeeFromOutputs":[0], "fee_rate": 200, "change_type": address_type})['psbt']
+ res = psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
+ for wallet in [psbt_offline, key_only_wallet]:
+ res = wallet.walletprocesspsbt(psbt=psbt, finalize=False)
+
+ decoded = wallet.decodepsbt(res["psbt"])
+ if pattern.startswith("tr("):
+ for psbtin in decoded["inputs"]:
+ assert "non_witness_utxo" not in psbtin
+ assert "witness_utxo" in psbtin
+ assert "taproot_internal_key" in psbtin
+ assert "taproot_bip32_derivs" in psbtin
+ assert "taproot_key_path_sig" in psbtin or "taproot_script_path_sigs" in psbtin
+ if "taproot_script_path_sigs" in psbtin:
+ assert "taproot_merkle_root" in psbtin
+ assert "taproot_scripts" in psbtin
+
+ rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
+ res = self.nodes[0].testmempoolaccept([rawtx])
+ assert res[0]["allowed"]
+
txid = self.nodes[0].sendrawtransaction(rawtx)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.psbt_online.gettransaction(txid)['confirmations'] > 0)
+ assert psbt_online.gettransaction(txid)['confirmations'] > 0
+
+ # Cleanup
+ psbt = psbt_online.sendall(recipients=[self.boring.getnewaddress()], options={"psbt": True})["psbt"]
+ res = psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
+ rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
+ txid = self.nodes[0].sendrawtransaction(rawtx)
+ self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
+ assert psbt_online.gettransaction(txid)['confirmations'] > 0
+ psbt_online.unloadwallet()
+ psbt_offline.unloadwallet()
def do_test(self, comment, pattern, privmap, treefn):
nkeys = len(privmap)
@@ -336,21 +395,8 @@ class WalletTaprootTest(BitcoinTestFramework):
self.do_test_psbt(comment, pattern, privmap, treefn, keys[2*nkeys:3*nkeys], keys[3*nkeys:4*nkeys])
def run_test(self):
- self.log.info("Creating wallets...")
- self.nodes[0].createwallet(wallet_name="privs_tr_enabled", descriptors=True, blank=True)
- self.privs_tr_enabled = self.nodes[0].get_wallet_rpc("privs_tr_enabled")
- self.nodes[0].createwallet(wallet_name="pubs_tr_enabled", descriptors=True, blank=True, disable_private_keys=True)
- self.pubs_tr_enabled = self.nodes[0].get_wallet_rpc("pubs_tr_enabled")
self.nodes[0].createwallet(wallet_name="boring")
- self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True)
- self.nodes[0].createwallet(wallet_name="rpc_online", descriptors=True, blank=True)
- self.nodes[0].createwallet(wallet_name="psbt_online", descriptors=True, disable_private_keys=True, blank=True)
- self.nodes[1].createwallet(wallet_name="psbt_offline", descriptors=True, blank=True)
self.boring = self.nodes[0].get_wallet_rpc("boring")
- self.addr_gen = self.nodes[0].get_wallet_rpc("addr_gen")
- self.rpc_online = self.nodes[0].get_wallet_rpc("rpc_online")
- self.psbt_online = self.nodes[0].get_wallet_rpc("psbt_online")
- self.psbt_offline = self.nodes[1].get_wallet_rpc("psbt_offline")
self.log.info("Mining blocks...")
gen_addr = self.boring.getnewaddress()
@@ -460,18 +506,5 @@ class WalletTaprootTest(BitcoinTestFramework):
lambda k1: key(k1)
)
- self.log.info("Sending everything back...")
-
- txid = self.rpc_online.sendall(recipients=[self.boring.getnewaddress()])["txid"]
- self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.rpc_online.gettransaction(txid)["confirmations"] > 0)
-
- psbt = self.psbt_online.sendall(recipients=[self.boring.getnewaddress()], options={"psbt": True})["psbt"]
- res = self.psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
- rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
- txid = self.nodes[0].sendrawtransaction(rawtx)
- self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.psbt_online.gettransaction(txid)['confirmations'] > 0)
-
if __name__ == '__main__':
WalletTaprootTest().main()
diff --git a/test/functional/wallet_timelock.py b/test/functional/wallet_timelock.py
index a71cec6607..57a7c3907a 100755
--- a/test/functional/wallet_timelock.py
+++ b/test/functional/wallet_timelock.py
@@ -8,6 +8,9 @@ from test_framework.util import assert_equal
class WalletLocktimeTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py
index 9caa1fa3d0..3386ecd599 100755
--- a/test/functional/wallet_transactiontime_rescan.py
+++ b/test/functional/wallet_transactiontime_rescan.py
@@ -1,12 +1,14 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 transaction time during old block rescanning
"""
+import threading
import time
+from test_framework.authproxy import JSONRPCException
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -14,12 +16,22 @@ from test_framework.util import (
assert_raises_rpc_error,
set_node_times,
)
+from test_framework.wallet_util import (
+ get_generate_key,
+)
class TransactionTimeRescanTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.setup_clean_chain = False
self.num_nodes = 3
+ self.extra_args = [["-keypool=400"],
+ ["-keypool=400"],
+ []
+ ]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -164,6 +176,52 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Invalid stop_height", restorewo_wallet.rescanblockchain, 1, -1)
assert_raises_rpc_error(-8, "stop_height must be greater than start_height", restorewo_wallet.rescanblockchain, 20, 10)
+ self.log.info("Test `rescanblockchain` fails when wallet is encrypted and locked")
+ usernode.createwallet(wallet_name="enc_wallet", passphrase="passphrase")
+ enc_wallet = usernode.get_wallet_rpc("enc_wallet")
+ assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", enc_wallet.rescanblockchain)
+
+ if not self.options.descriptors:
+ self.log.info("Test rescanning an encrypted wallet")
+ hd_seed = get_generate_key().privkey
+
+ usernode.createwallet(wallet_name="temp_wallet", blank=True, descriptors=False)
+ temp_wallet = usernode.get_wallet_rpc("temp_wallet")
+ temp_wallet.sethdseed(seed=hd_seed)
+
+ for i in range(399):
+ temp_wallet.getnewaddress()
+
+ self.generatetoaddress(usernode, COINBASE_MATURITY + 1, temp_wallet.getnewaddress())
+ self.generatetoaddress(usernode, COINBASE_MATURITY + 1, temp_wallet.getnewaddress())
+
+ minernode.createwallet("encrypted_wallet", blank=True, passphrase="passphrase", descriptors=False)
+ encrypted_wallet = minernode.get_wallet_rpc("encrypted_wallet")
+
+ encrypted_wallet.walletpassphrase("passphrase", 99999)
+ encrypted_wallet.sethdseed(seed=hd_seed)
+
+ t = threading.Thread(target=encrypted_wallet.rescanblockchain)
+
+ with minernode.assert_debug_log(expected_msgs=[f'Rescan started from block 0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206... (slow variant inspecting all blocks)'], timeout=5):
+ t.start()
+
+ # set the passphrase timeout to 1 to test that the wallet remains unlocked during the rescan
+ minernode.cli("-rpcwallet=encrypted_wallet").walletpassphrase("passphrase", 1)
+
+ try:
+ minernode.cli("-rpcwallet=encrypted_wallet").walletlock()
+ except JSONRPCException as e:
+ assert e.error['code'] == -4 and "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before locking the wallet." in e.error['message']
+
+ try:
+ minernode.cli("-rpcwallet=encrypted_wallet").walletpassphrasechange("passphrase", "newpassphrase")
+ except JSONRPCException as e:
+ assert e.error['code'] == -4 and "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before changing the passphrase." in e.error['message']
+
+ t.join()
+
+ assert_equal(encrypted_wallet.getbalance(), temp_wallet.getbalance())
if __name__ == '__main__':
TransactionTimeRescanTest().main()
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index 5bdde13aa4..d8ef66d83a 100755
--- a/test/functional/wallet_txn_clone.py
+++ b/test/functional/wallet_txn_clone.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 accounts properly when there are cloned transactions with malleated scriptsigs."""
@@ -24,6 +24,7 @@ class TxnMallTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def add_options(self, parser):
+ self.add_wallet_options(parser)
parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true",
help="Test double-spend of 1-confirmed transaction")
parser.add_argument("--segwit", dest="segwit", default=False, action="store_true",
diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py
index 206187fb61..38ebfe0d7a 100755
--- a/test/functional/wallet_txn_doublespend.py
+++ b/test/functional/wallet_txn_doublespend.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2022 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 accounts properly when there is a double-spend conflict."""
@@ -22,6 +22,7 @@ class TxnMallTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def add_options(self, parser):
+ self.add_wallet_options(parser)
parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true",
help="Test double-spend of 1-confirmed transaction")
diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py
index c452e1eafd..4495a7d778 100755
--- a/test/functional/wallet_upgradewallet.py
+++ b/test/functional/wallet_upgradewallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""upgradewallet RPC functional test
@@ -45,6 +45,9 @@ def deser_keymeta(f):
return ver, create_time, kp_str, seed_id, fpr, path_len, path, has_key_orig
class UpgradeWalletTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=False)
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py
index 69c32ba54c..dd4514318c 100755
--- a/test/functional/wallet_watchonly.py
+++ b/test/functional/wallet_watchonly.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 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 watchonly arguments.
@@ -14,6 +14,9 @@ from test_framework.util import (
class CreateWalletWatchonlyTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
def set_test_params(self):
self.num_nodes = 1
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index e2eab2a0fe..af21e7b956 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -143,7 +143,7 @@ def main():
timeout=20,
check=True,
stderr=subprocess.PIPE,
- universal_newlines=True,
+ text=True,
).stderr
if "libFuzzer" not in help_output:
logging.error("Must be built with libFuzzer")
@@ -200,7 +200,7 @@ def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets):
env=get_fuzz_env(target=t, source_dir=src_dir),
check=True,
stderr=subprocess.PIPE,
- universal_newlines=True,
+ text=True,
).stderr))
futures = []
@@ -241,7 +241,7 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir)
env=get_fuzz_env(target=t, source_dir=src_dir),
check=True,
stderr=subprocess.PIPE,
- universal_newlines=True,
+ text=True,
).stderr
logging.debug(output)
@@ -270,7 +270,7 @@ def run_once(*, fuzz_pool, corpus, test_list, src_dir, build_dir, use_valgrind):
args,
env=get_fuzz_env(target=t, source_dir=src_dir),
stderr=subprocess.PIPE,
- universal_newlines=True,
+ text=True,
)
output += result.stderr
return output, result
@@ -299,7 +299,7 @@ def parse_test_list(*, fuzz_bin):
},
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
- universal_newlines=True,
+ text=True,
).stdout.splitlines()
return test_list_all
diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py
index c983dce619..60c868ca04 100755
--- a/test/get_previous_releases.py
+++ b/test/get_previous_releases.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (c) 2018-2021 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
@@ -80,6 +80,15 @@ SHA256_SUMS = {
"078f96b1e92895009c798ab827fb3fde5f6719eee886bd0c0e93acab18ea4865": {"tag": "v23.0", "tarball": "bitcoin-23.0-riscv64-linux-gnu.tar.gz"},
"c816780583009a9dad426dc0c183c89be9da98906e1e2c7ebae91041c1aaaaf3": {"tag": "v23.0", "tarball": "bitcoin-23.0-x86_64-apple-darwin.tar.gz"},
"2cca490c1f2842884a3c5b0606f179f9f937177da4eadd628e3f7fd7e25d26d0": {"tag": "v23.0", "tarball": "bitcoin-23.0-x86_64-linux-gnu.tar.gz"},
+
+ "0b48b9e69b30037b41a1e6b78fb7cbcc48c7ad627908c99686e81f3802454609": {"tag": "v24.0.1", "tarball": "bitcoin-24.0.1-aarch64-linux-gnu.tar.gz"},
+ "37d7660f0277301744e96426bbb001d2206b8d4505385dfdeedf50c09aaaef60": {"tag": "v24.0.1", "tarball": "bitcoin-24.0.1-arm-linux-gnueabihf.tar.gz"},
+ "90ed59e86bfda1256f4b4cad8cc1dd77ee0efec2492bcb5af61402709288b62c": {"tag": "v24.0.1", "tarball": "bitcoin-24.0.1-arm64-apple-darwin.tar.gz"},
+ "7590645e8676f8b5fda62dc20174474c4ac8fd0defc83a19ed908ebf2e94dc11": {"tag": "v24.0.1", "tarball": "bitcoin-24.0.1-powerpc64-linux-gnu.tar.gz"},
+ "79e89a101f23ff87816675b98769cd1ee91059f95c5277f38f48f21a9f7f8509": {"tag": "v24.0.1", "tarball": "bitcoin-24.0.1-powerpc64le-linux-gnu.tar.gz"},
+ "6b163cef7de4beb07b8cb3347095e0d76a584019b1891135cd1268a1f05b9d88": {"tag": "v24.0.1", "tarball": "bitcoin-24.0.1-riscv64-linux-gnu.tar.gz"},
+ "e2f751512f3c0f00eb68ba946d9c829e6cf99422a61e8f5e0a7c109c318674d0": {"tag": "v24.0.1", "tarball": "bitcoin-24.0.1-x86_64-apple-darwin.tar.gz"},
+ "49df6e444515d457ea0b885d66f521f2a26ca92ccf73d5296082e633544253bf": {"tag": "v24.0.1", "tarball": "bitcoin-24.0.1-x86_64-linux-gnu.tar.gz"},
}
@@ -136,7 +145,7 @@ def download_binary(tag, args) -> int:
tarballHash = hasher.hexdigest()
if tarballHash not in SHA256_SUMS or SHA256_SUMS[tarballHash]['tarball'] != tarball:
- if tarball in SHA256_SUMS.values():
+ if tarball in [v['tarball'] for v in SHA256_SUMS.values()]:
print("Checksum did not match")
return 1
@@ -148,10 +157,39 @@ def download_binary(tag, args) -> int:
ret = subprocess.run(['tar', '-zxf', tarball, '-C', tag,
'--strip-components=1',
'bitcoin-{tag}'.format(tag=tag[1:])]).returncode
- if ret:
+ if ret != 0:
+ print(f"Failed to extract the {tag} tarball")
return ret
Path(tarball).unlink()
+
+ if tag >= "v23" and platform == "arm64-apple-darwin":
+ # Starting with v23 there are arm64 binaries for ARM (e.g. M1, M2) macs, but they have to be signed to run
+ binary_path = f'{os.getcwd()}/{tag}/bin/'
+
+ for arm_binary in os.listdir(binary_path):
+ # Is it already signed?
+ ret = subprocess.run(
+ ['codesign', '-v', binary_path + arm_binary],
+ stderr=subprocess.DEVNULL, # Suppress expected stderr output
+ ).returncode
+ if ret == 1:
+ # Have to self-sign the binary
+ ret = subprocess.run(
+ ['codesign', '-s', '-', binary_path + arm_binary]
+ ).returncode
+ if ret != 0:
+ print(f"Failed to self-sign {tag} {arm_binary} arm64 binary")
+ return 1
+
+ # Confirm success
+ ret = subprocess.run(
+ ['codesign', '-v', binary_path + arm_binary]
+ ).returncode
+ if ret != 0:
+ print(f"Failed to verify the self-signed {tag} {arm_binary} arm64 binary")
+ return 1
+
return 0
@@ -260,11 +298,10 @@ if __name__ == '__main__':
help='download release binary.')
parser.add_argument('-t', '--target-dir', action='store',
help='target directory.', default='releases')
- parser.add_argument('tags', nargs='*', default=set(
- [v['tag'] for v in SHA256_SUMS.values()]
- ),
+ all_tags = sorted([*set([v['tag'] for v in SHA256_SUMS.values()])])
+ parser.add_argument('tags', nargs='*', default=all_tags,
help='release tags. e.g.: v0.18.1 v0.20.0rc2 '
- '(if not specified, the full list needed for'
+ '(if not specified, the full list needed for '
'backwards compatibility tests will be used)'
)
args = parser.parse_args()
diff --git a/test/lint/README.md b/test/lint/README.md
index 8d592c3282..704922d7ab 100644
--- a/test/lint/README.md
+++ b/test/lint/README.md
@@ -1,5 +1,23 @@
This folder contains lint scripts.
+Running locally
+===============
+
+To run linters locally with the same versions as the CI environment, use the included
+Dockerfile:
+
+```sh
+cd ./ci/lint
+docker build -t bitcoin-linter .
+
+cd /root/of/bitcoin/repo
+docker run --rm -v $(pwd):/bitcoin -it bitcoin-linter
+```
+
+After building the container once, you can simply run the last command any time you
+want to lint.
+
+
check-doc.py
============
Check for missing documentation of command line options.
diff --git a/test/lint/all-lint.py b/test/lint/all-lint.py
index 34a7b9742a..c7889796c6 100755
--- a/test/lint/all-lint.py
+++ b/test/lint/all-lint.py
@@ -10,11 +10,12 @@
from glob import glob
from pathlib import Path
from subprocess import run
+from sys import executable
exit_code = 0
mod_path = Path(__file__).parent
for lint in glob(f"{mod_path}/lint-*.py"):
- result = run([lint])
+ result = run([executable, lint])
if result.returncode != 0:
print(f"^---- failure generated from {lint.split('/')[-1]}")
exit_code |= result.returncode
diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py
index feaebc68e9..d22dd9d996 100755
--- a/test/lint/check-doc.py
+++ b/test/lint/check-doc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,7 +15,7 @@ import re
FOLDER_GREP = 'src'
FOLDER_TEST = 'src/test/'
-REGEX_ARG = r'(?:ForceSet|SoftSet|Get|Is)(?:Bool)?Args?(?:Set)?\("(-[^"]+)"'
+REGEX_ARG = r'\b(?:GetArg|GetArgs|GetBoolArg|GetIntArg|GetPathArg|IsArgSet|get_net)\("(-[^"]+)"'
REGEX_DOC = r'AddArg\("(-[^"=]+?)(?:=|")'
CMD_ROOT_DIR = '$(git rev-parse --show-toplevel)/{}'.format(FOLDER_GREP)
CMD_GREP_ARGS = r"git grep --perl-regexp '{}' -- {} ':(exclude){}'".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST)
diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh
index 9449b393f1..55c9528dea 100755
--- a/test/lint/commit-script-check.sh
+++ b/test/lint/commit-script-check.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2017-2021 The Bitcoin Core developers
+# Copyright (c) 2017-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/lint/lint-assertions.py b/test/lint/lint-assertions.py
index 195ff33d11..e7eecebce5 100755
--- a/test/lint/lint-assertions.py
+++ b/test/lint/lint-assertions.py
@@ -12,7 +12,7 @@ import subprocess
def git_grep(params: [], error_msg: ""):
try:
- output = subprocess.check_output(["git", "grep", *params], universal_newlines=True, encoding="utf8")
+ output = subprocess.check_output(["git", "grep", *params], text=True, encoding="utf8")
print(error_msg)
print(output)
return 1
diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py
index a0f17ac119..cf6a5f81f1 100755
--- a/test/lint/lint-circular-dependencies.py
+++ b/test/lint/lint-circular-dependencies.py
@@ -14,7 +14,7 @@ import sys
EXPECTED_CIRCULAR_DEPENDENCIES = (
"chainparamsbase -> util/system -> chainparamsbase",
"node/blockstorage -> validation -> node/blockstorage",
- "policy/fees -> txmempool -> policy/fees",
+ "node/utxo_snapshot -> validation -> node/utxo_snapshot",
"qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel",
"qt/recentrequeststablemodel -> qt/walletmodel -> qt/recentrequeststablemodel",
"qt/sendcoinsdialog -> qt/walletmodel -> qt/sendcoinsdialog",
@@ -38,14 +38,14 @@ def main():
os.chdir(CODE_DIR)
files = subprocess.check_output(
['git', 'ls-files', '--', '*.h', '*.cpp'],
- universal_newlines=True,
+ text=True,
).splitlines()
command = [sys.executable, "../contrib/devtools/circular-dependencies.py", *files]
dependencies_output = subprocess.run(
command,
stdout=subprocess.PIPE,
- universal_newlines=True,
+ text=True,
)
for dependency_str in dependencies_output.stdout.rstrip().split("\n"):
diff --git a/test/lint/lint-files.py b/test/lint/lint-files.py
index 123bee2cbc..f2b5db681b 100755
--- a/test/lint/lint-files.py
+++ b/test/lint/lint-files.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/lint/lint-git-commit-check.py b/test/lint/lint-git-commit-check.py
index a1d03370e8..5897a17e70 100755
--- a/test/lint/lint-git-commit-check.py
+++ b/test/lint/lint-git-commit-check.py
@@ -42,15 +42,17 @@ def main():
commit_range = "HEAD~" + args.prev_commits + "...HEAD"
else:
# This assumes that the target branch of the pull request will be master.
- merge_base = check_output(["git", "merge-base", "HEAD", "master"], universal_newlines=True, encoding="utf8").rstrip("\n")
+ merge_base = check_output(["git", "merge-base", "HEAD", "master"], text=True, encoding="utf8").rstrip("\n")
commit_range = merge_base + "..HEAD"
else:
commit_range = os.getenv("COMMIT_RANGE")
+ if commit_range == "SKIP_EMPTY_NOT_A_PR":
+ sys.exit(0)
- commit_hashes = check_output(["git", "log", commit_range, "--format=%H"], universal_newlines=True, encoding="utf8").splitlines()
+ commit_hashes = check_output(["git", "log", commit_range, "--format=%H"], text=True, encoding="utf8").splitlines()
for hash in commit_hashes:
- commit_info = check_output(["git", "log", "--format=%B", "-n", "1", hash], universal_newlines=True, encoding="utf8").splitlines()
+ commit_info = check_output(["git", "log", "--format=%B", "-n", "1", hash], text=True, encoding="utf8").splitlines()
if len(commit_info) >= 2:
if commit_info[1]:
print(f"The subject line of commit hash {hash} is followed by a non-empty line. Subject lines should always be followed by a blank line.")
diff --git a/test/lint/lint-includes.py b/test/lint/lint-includes.py
index b3fa4b9303..459030bb0b 100755
--- a/test/lint/lint-includes.py
+++ b/test/lint/lint-includes.py
@@ -35,13 +35,13 @@ EXPECTED_BOOST_INCLUDES = ["boost/date_time/posix_time/posix_time.hpp",
def get_toplevel():
- return check_output(["git", "rev-parse", "--show-toplevel"], universal_newlines=True, encoding="utf8").rstrip("\n")
+ return check_output(["git", "rev-parse", "--show-toplevel"], text=True, encoding="utf8").rstrip("\n")
def list_files_by_suffix(suffixes):
exclude_args = [":(exclude)" + dir for dir in EXCLUDED_DIRS]
- files_list = check_output(["git", "ls-files", "src"] + exclude_args, universal_newlines=True, encoding="utf8").splitlines()
+ files_list = check_output(["git", "ls-files", "src"] + exclude_args, text=True, encoding="utf8").splitlines()
return [file for file in files_list if file.endswith(suffixes)]
@@ -63,7 +63,7 @@ def find_included_cpps():
included_cpps = list()
try:
- included_cpps = check_output(["git", "grep", "-E", r"^#include [<\"][^>\"]+\.cpp[>\"]", "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8").splitlines()
+ included_cpps = check_output(["git", "grep", "-E", r"^#include [<\"][^>\"]+\.cpp[>\"]", "--", "*.cpp", "*.h"], text=True, encoding="utf8").splitlines()
except CalledProcessError as e:
if e.returncode > 1:
raise e
@@ -77,7 +77,7 @@ def find_extra_boosts():
exclusion_set = set()
try:
- included_boosts = check_output(["git", "grep", "-E", r"^#include <boost/", "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8").splitlines()
+ included_boosts = check_output(["git", "grep", "-E", r"^#include <boost/", "--", "*.cpp", "*.h"], text=True, encoding="utf8").splitlines()
except CalledProcessError as e:
if e.returncode > 1:
raise e
@@ -100,7 +100,7 @@ def find_quote_syntax_inclusions():
quote_syntax_inclusions = list()
try:
- quote_syntax_inclusions = check_output(["git", "grep", r"^#include \"", "--", "*.cpp", "*.h"] + exclude_args, universal_newlines=True, encoding="utf8").splitlines()
+ quote_syntax_inclusions = check_output(["git", "grep", r"^#include \"", "--", "*.cpp", "*.h"] + exclude_args, text=True, encoding="utf8").splitlines()
except CalledProcessError as e:
if e.returncode > 1:
raise e
@@ -143,13 +143,13 @@ def main():
if extra_boosts:
for boost in extra_boosts:
print(f"A new Boost dependency in the form of \"{boost}\" appears to have been introduced:")
- print(check_output(["git", "grep", boost, "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8"))
+ print(check_output(["git", "grep", boost, "--", "*.cpp", "*.h"], text=True, encoding="utf8"))
exit_code = 1
# Check if Boost dependencies are no longer used
for expected_boost in EXPECTED_BOOST_INCLUDES:
try:
- check_output(["git", "grep", "-q", r"^#include <%s>" % expected_boost, "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8")
+ check_output(["git", "grep", "-q", r"^#include <%s>" % expected_boost, "--", "*.cpp", "*.h"], text=True, encoding="utf8")
except CalledProcessError as e:
if e.returncode > 1:
raise e
diff --git a/test/lint/lint-locale-dependence.py b/test/lint/lint-locale-dependence.py
index ce7444cd1a..faea643882 100755
--- a/test/lint/lint-locale-dependence.py
+++ b/test/lint/lint-locale-dependence.py
@@ -34,8 +34,6 @@
#
# See https://doc.qt.io/qt-5/qcoreapplication.html#locale-settings and
# https://stackoverflow.com/a/34878283 for more details.
-#
-# TODO: Reduce KNOWN_VIOLATIONS by replacing uses of locale dependent snprintf with strprintf.
import re
import sys
@@ -45,7 +43,6 @@ from subprocess import check_output, CalledProcessError
KNOWN_VIOLATIONS = [
"src/dbwrapper.cpp:.*vsnprintf",
- "src/test/dbwrapper_tests.cpp:.*snprintf",
"src/test/fuzz/locale.cpp:.*setlocale",
"src/test/fuzz/string.cpp:.*strtol",
"src/test/fuzz/string.cpp:.*strtoul",
@@ -223,7 +220,7 @@ def find_locale_dependent_function_uses():
git_grep_output = list()
try:
- git_grep_output = check_output(git_grep_command, universal_newlines=True, encoding="utf8").splitlines()
+ git_grep_output = check_output(git_grep_command, text=True, encoding="utf8").splitlines()
except CalledProcessError as e:
if e.returncode > 1:
raise e
diff --git a/test/lint/lint-logs.py b/test/lint/lint-logs.py
index aaf697467d..de04a1aeca 100755
--- a/test/lint/lint-logs.py
+++ b/test/lint/lint-logs.py
@@ -16,7 +16,7 @@ from subprocess import check_output
def main():
- logs_list = check_output(["git", "grep", "--extended-regexp", r"(LogPrintLevel|LogPrintfCategory|LogPrintf?)\(", "--", "*.cpp"], universal_newlines=True, encoding="utf8").splitlines()
+ logs_list = check_output(["git", "grep", "--extended-regexp", r"(LogPrintLevel|LogPrintfCategory|LogPrintf?)\(", "--", "*.cpp"], text=True, encoding="utf8").splitlines()
unterminated_logs = [line for line in logs_list if not re.search(r'(\\n"|/\* Continued \*/)', line)]
diff --git a/test/lint/lint-python-mutable-default-parameters.py b/test/lint/lint-python-mutable-default-parameters.py
index 7991e3630b..820595ea34 100755
--- a/test/lint/lint-python-mutable-default-parameters.py
+++ b/test/lint/lint-python-mutable-default-parameters.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -21,7 +21,7 @@ def main():
"--",
"*.py",
]
- output = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True)
+ output = subprocess.run(command, stdout=subprocess.PIPE, text=True)
if len(output.stdout) > 0:
error_msg = (
"A mutable list or dict seems to be used as default parameter value:\n\n"
diff --git a/test/lint/lint-python-utf8-encoding.py b/test/lint/lint-python-utf8-encoding.py
index 62fdc34d50..364da63468 100755
--- a/test/lint/lint-python-utf8-encoding.py
+++ b/test/lint/lint-python-utf8-encoding.py
@@ -23,7 +23,7 @@ def check_fileopens():
fileopens = list()
try:
- fileopens = check_output(["git", "grep", r" open(", "--", "*.py"] + get_exclude_args(), universal_newlines=True, encoding="utf8").splitlines()
+ fileopens = check_output(["git", "grep", r" open(", "--", "*.py"] + get_exclude_args(), text=True, encoding="utf8").splitlines()
except CalledProcessError as e:
if e.returncode > 1:
raise e
@@ -37,12 +37,12 @@ def check_checked_outputs():
checked_outputs = list()
try:
- checked_outputs = check_output(["git", "grep", "check_output(", "--", "*.py"] + get_exclude_args(), universal_newlines=True, encoding="utf8").splitlines()
+ checked_outputs = check_output(["git", "grep", "check_output(", "--", "*.py"] + get_exclude_args(), text=True, encoding="utf8").splitlines()
except CalledProcessError as e:
if e.returncode > 1:
raise e
- filtered_checked_outputs = [checked_output for checked_output in checked_outputs if re.search(r"universal_newlines=True", checked_output) and not re.search(r"encoding=.(ascii|utf8|utf-8).", checked_output)]
+ filtered_checked_outputs = [checked_output for checked_output in checked_outputs if re.search(r"text=True", checked_output) and not re.search(r"encoding=.(ascii|utf8|utf-8).", checked_output)]
return filtered_checked_outputs
diff --git a/test/lint/lint-python.py b/test/lint/lint-python.py
index 4d16facfea..4ec7608708 100755
--- a/test/lint/lint-python.py
+++ b/test/lint/lint-python.py
@@ -47,6 +47,7 @@ ENABLED = (
'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()"
+ 'E722,' # do not use bare 'except'
'E742,' # do not define classes named "l", "O", or "I"
'E743,' # do not define functions named "l", "O", or "I"
'E901,' # SyntaxError: invalid syntax
diff --git a/test/lint/lint-shell.py b/test/lint/lint-shell.py
index ed95024ef5..1646bf0d3e 100755
--- a/test/lint/lint-shell.py
+++ b/test/lint/lint-shell.py
@@ -25,7 +25,7 @@ def check_shellcheck_install():
sys.exit(0)
def get_files(command):
- output = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True)
+ output = subprocess.run(command, stdout=subprocess.PIPE, text=True)
files = output.stdout.split('\n')
# remove whitespace element
diff --git a/test/lint/lint-spelling.py b/test/lint/lint-spelling.py
index 14d7d13a75..ac0bddeaa6 100755
--- a/test/lint/lint-spelling.py
+++ b/test/lint/lint-spelling.py
@@ -12,7 +12,7 @@ Note: Will exit successfully regardless of spelling errors.
from subprocess import check_output, STDOUT, CalledProcessError
IGNORE_WORDS_FILE = 'test/lint/spelling.ignore-words.txt'
-FILES_ARGS = ['git', 'ls-files', '--', ":(exclude)build-aux/m4/", ":(exclude)contrib/seeds/*.txt", ":(exclude)depends/", ":(exclude)doc/release-notes/", ":(exclude)src/leveldb/", ":(exclude)src/crc32c/", ":(exclude)src/qt/locale/", ":(exclude)src/qt/*.qrc", ":(exclude)src/secp256k1/", ":(exclude)src/minisketch/", ":(exclude)contrib/builder-keys/keys.txt", ":(exclude)contrib/guix/patches"]
+FILES_ARGS = ['git', 'ls-files', '--', ":(exclude)build-aux/m4/", ":(exclude)contrib/seeds/*.txt", ":(exclude)depends/", ":(exclude)doc/release-notes/", ":(exclude)src/leveldb/", ":(exclude)src/crc32c/", ":(exclude)src/qt/locale/", ":(exclude)src/qt/*.qrc", ":(exclude)src/secp256k1/", ":(exclude)src/minisketch/", ":(exclude)contrib/guix/patches"]
def check_codespell_install():
diff --git a/test/lint/lint-submodule.py b/test/lint/lint-submodule.py
index 89d4c80f55..4d2fbf088f 100755
--- a/test/lint/lint-submodule.py
+++ b/test/lint/lint-submodule.py
@@ -13,7 +13,7 @@ import sys
def main():
submodules_list = subprocess.check_output(['git', 'submodule', 'status', '--recursive'],
- universal_newlines = True, encoding = 'utf8').rstrip('\n')
+ text = True, encoding = 'utf8').rstrip('\n')
if submodules_list:
print("These submodules were found, delete them:\n", submodules_list)
sys.exit(1)
diff --git a/test/lint/lint-tests.py b/test/lint/lint-tests.py
index 849ddcb961..1eeb7bb014 100755
--- a/test/lint/lint-tests.py
+++ b/test/lint/lint-tests.py
@@ -23,7 +23,7 @@ def grep_boost_fixture_test_suite():
"src/test/**.cpp",
"src/wallet/test/**.cpp",
]
- return subprocess.check_output(command, universal_newlines=True, encoding="utf8")
+ return subprocess.check_output(command, text=True, encoding="utf8")
def check_matching_test_names(test_suite_list):
diff --git a/test/lint/lint-whitespace.py b/test/lint/lint-whitespace.py
index 3fb5b80013..f5e4a776d0 100755
--- a/test/lint/lint-whitespace.py
+++ b/test/lint/lint-whitespace.py
@@ -80,7 +80,7 @@ def get_diff(commit_range, check_only_code):
else:
what_files = ["."]
- diff = check_output(["git", "diff", "-U0", commit_range, "--"] + what_files + exclude_args, universal_newlines=True, encoding="utf8")
+ diff = check_output(["git", "diff", "-U0", commit_range, "--"] + what_files + exclude_args, text=True, encoding="utf8")
return diff
@@ -93,10 +93,12 @@ def main():
commit_range = "HEAD~" + args.prev_commits + "...HEAD"
else:
# This assumes that the target branch of the pull request will be master.
- merge_base = check_output(["git", "merge-base", "HEAD", "master"], universal_newlines=True, encoding="utf8").rstrip("\n")
+ merge_base = check_output(["git", "merge-base", "HEAD", "master"], text=True, encoding="utf8").rstrip("\n")
commit_range = merge_base + "..HEAD"
else:
commit_range = os.getenv("COMMIT_RANGE")
+ if commit_range == "SKIP_EMPTY_NOT_A_PR":
+ sys.exit(0)
whitespace_selection = []
tab_selection = []
diff --git a/test/lint/run-lint-format-strings.py b/test/lint/run-lint-format-strings.py
index b814446125..91915f05f9 100755
--- a/test/lint/run-lint-format-strings.py
+++ b/test/lint/run-lint-format-strings.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
@@ -17,6 +17,7 @@ FALSE_POSITIVES = [
("src/index/base.cpp", "FatalError(const char* fmt, const Args&... args)"),
("src/netbase.cpp", "LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args)"),
("src/clientversion.cpp", "strprintf(_(COPYRIGHT_HOLDERS).translated, COPYRIGHT_HOLDERS_SUBSTITUTION)"),
+ ("src/test/translation_tests.cpp", "strprintf(format, arg)"),
("src/validationinterface.cpp", "LogPrint(BCLog::VALIDATION, fmt \"\\n\", __VA_ARGS__)"),
("src/wallet/wallet.h", "WalletLogPrintf(std::string fmt, Params... parameters)"),
("src/wallet/wallet.h", "LogPrintf((\"%s \" + fmt).c_str(), GetDisplayName(), parameters...)"),
diff --git a/test/lint/spelling.ignore-words.txt b/test/lint/spelling.ignore-words.txt
index 82f18010c1..d44dd70684 100644
--- a/test/lint/spelling.ignore-words.txt
+++ b/test/lint/spelling.ignore-words.txt
@@ -4,6 +4,7 @@ blockin
bu
cachable
clen
+crypted
fo
fpr
hights
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index 67ef512895..2fa4e383e2 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -53,6 +53,7 @@ unsigned-integer-overflow:policy/fees.cpp
unsigned-integer-overflow:prevector.h
unsigned-integer-overflow:script/interpreter.cpp
unsigned-integer-overflow:txmempool.cpp
+unsigned-integer-overflow:xoroshiro128plusplus.h
implicit-integer-sign-change:compat/stdin.cpp
implicit-integer-sign-change:compressor.h
implicit-integer-sign-change:crypto/
@@ -69,3 +70,4 @@ shift-base:crypto/
shift-base:hash.cpp
shift-base:streams.h
shift-base:util/bip32.cpp
+shift-base:xoroshiro128plusplus.h
diff --git a/test/util/rpcauth-test.py b/test/util/rpcauth-test.py
index 53058dc394..8a7ff26dcb 100755
--- a/test/util/rpcauth-test.py
+++ b/test/util/rpcauth-test.py
@@ -4,7 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test share/rpcauth/rpcauth.py
"""
-import base64
+import re
import configparser
import hmac
import importlib
@@ -28,18 +28,17 @@ class TestRPCAuth(unittest.TestCase):
self.assertEqual(len(self.rpcauth.generate_salt(i)), i * 2)
def test_generate_password(self):
+ """Test that generated passwords only consist of urlsafe characters."""
+ r = re.compile(r"[0-9a-zA-Z_-]*")
password = self.rpcauth.generate_password()
- expected_password = base64.urlsafe_b64encode(
- base64.urlsafe_b64decode(password)).decode('utf-8')
- self.assertEqual(expected_password, password)
+ self.assertTrue(r.fullmatch(password))
def test_check_password_hmac(self):
salt = self.rpcauth.generate_salt(16)
password = self.rpcauth.generate_password()
password_hmac = self.rpcauth.password_to_hmac(salt, password)
- m = hmac.new(bytearray(salt, 'utf-8'),
- bytearray(password, 'utf-8'), 'SHA256')
+ m = hmac.new(salt.encode('utf-8'), password.encode('utf-8'), 'SHA256')
expected_password_hmac = m.hexdigest()
self.assertEqual(expected_password_hmac, password_hmac)
diff --git a/test/util/test_runner.py b/test/util/test_runner.py
index 03db05c563..e5cdd0bc3a 100755
--- a/test/util/test_runner.py
+++ b/test/util/test_runner.py
@@ -54,7 +54,7 @@ def bctester(testDir, input_basename, buildenv):
try:
bctest(testDir, testObj, buildenv)
logging.info("PASSED: " + testObj["description"])
- except:
+ except Exception:
logging.info("FAILED: " + testObj["description"])
failed_testcases.append(testObj["description"])
@@ -96,7 +96,7 @@ def bctest(testDir, testObj, buildenv):
try:
with open(os.path.join(testDir, outputFn), encoding="utf8") as f:
outputData = f.read()
- except:
+ except Exception:
logging.error("Output file " + outputFn + " cannot be opened")
raise
if not outputData:
@@ -107,7 +107,7 @@ def bctest(testDir, testObj, buildenv):
raise Exception
# Run the test
- proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+ proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
try:
outs = proc.communicate(input=inputData)
except OSError: